/// <reference no-default-lib="true" /> /// <reference lib="esnext" /> /// <reference lib="dom" /> /// <reference lib="dom.iterable" /> import { getPage, getProject, readLinks, type FetchError, type LinksError, type PageError, } from "jsr:@cosense/std@0.29/rest"; import type { Page, UnixTime } from "jsr:@cosense/types@0.10/rest"; import { useStatusBar } from "jsr:@cosense/std@0.29/browser/dom"; import { pooledMap } from "jsr:@std/async@1/pool"; import { createOk, isErr, type Result, unwrapOk, unwrapErr } from "npm:option-t@51/plain_result"; import { getUnixTime } from "npm:date-fns@4/getUnixTime"; export type ExportPage = Pick<Page, "id" | "title" | "created" | "updated" | "lines">; export interface ExportData { name: string; displayName: string; exported: UnixTime; pages: ExportPage[]; } export const createExport = async ( project: string, threshold = 100, ): Promise<ExportData> => { const { render, dispose } = useStatusBar(); render( { type: "spinner"}, { type: "text", text: `Loading pages from "${project}"` }, ); try { const result = await getProject(project); if (isErr(result)) throw new Error(unwrapErr(result).name, { cause: unwrapErr(result) }); const { name, displayName } = unwrapOk(result); const pages: ExportPage[] = []; const { render, dispose } = useStatusBar(); try { for await ( const result of pooledMap( threshold, readLinks(project), async (result): Promise<Result<string, FetchError | LinksError | PageError>> => { if (isErr(result)) return result; const page = unwrapOk(result); const result2 = await getPage(project, page.title); if (isErr(result2)) return result2; const { id, title, created, updated, lines } = unwrapOk(result2); pages.push({ id, title, created, updated, lines }); return createOk(`[${pages.length}] ${title}`); }, ) ) { if (isErr(result)) throw new Error(unwrapErr(result).name, { cause: unwrapErr(result) }); let animationId: number | undefined; if (animationId !== undefined) cancelAnimationFrame(animationId); animationId = requestAnimationFrame( () => render({ type: "text", text: unwrapOk(result) }) ); } } finally { dispose(); } const exported = getUnixTime(new Date()); render( { type: "check-circle" }, { type: "text", text: `Exported ${pages.length} pages from /${name}`} ); return { name, displayName, exported, pages }; } catch(e) { render( { type: "exclamation-triangle" }, { type: "text", text: e instanceof Error ? `${e.name} ${e.message}` : "Unexpected error! (see developer console)", }, ); throw e; } finally { setTimeout(() => dispose(), 1000); } };