Files
ackandClaude Fable 5.1 95c80d04c9 Kokkoja: first public assembly
Assembled from the development repository by tools/make_release.sh.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 15:58:02 +02:00

68 lines
2.4 KiB
JavaScript

// @ts-check
/**
* Files outside the notebooks: image files to put on a page, and the place
* a picture of a page is exported to. A web page cannot look through the
* user's directories or write where the user chooses, so it asks the local
* program (kokkoja.py), as it does for the notebooks.
*/
import { askLocalProgram } from './notebook.js';
/**
* @typedef {object} DirectoryListing
* @property {string} directory Its full path.
* @property {string | null} parent Null at the top of the file system.
* @property {{name: string, path: string}[]} directories
* @property {{name: string, path: string, size: number}[]} files Image files only.
*/
/**
* @param {Response} response
* @returns {Promise<string>} What the local program says went wrong.
*/
async function reason(response) {
try {
return String((await response.json()).error);
} catch {
return `error ${response.status}`;
}
}
/**
* @param {string} [directory] A full path; without one, where the notebooks are.
* @returns {Promise<DirectoryListing>}
*/
export async function listFiles(directory = '') {
const response = await askLocalProgram(`api/files?directory=${encodeURIComponent(directory)}`);
if (!response.ok) throw new Error(`${directory}: ${await reason(response)}`);
return response.json();
}
/**
* @param {string} path The full path of an image file, from a listing.
* @returns {Promise<Blob>}
*/
export async function readFile(path) {
const response = await askLocalProgram(`api/file?path=${encodeURIComponent(path)}`);
if (!response.ok) throw new Error(`${path}: ${await reason(response)}`);
return response.blob();
}
/**
* Write a PNG picture into a directory.
* @param {string} directory Its full path.
* @param {string} name Ending in .png.
* @param {Blob} picture
* @param {boolean} replace Whether a file of that name may be replaced.
* @returns {Promise<string | null>} The full path written, or null if a
* file of that name exists and may not be replaced.
*/
export async function writePicture(directory, name, picture, replace) {
const query = `directory=${encodeURIComponent(directory)}&name=${encodeURIComponent(name)}` +
(replace ? '&replace=1' : '');
const response = await askLocalProgram(`api/file?${query}`, 'PUT', picture);
if (response.status === 409) return null;
if (!response.ok) throw new Error(await reason(response));
return (await response.json()).saved;
}