📄 src/downloader/worker-protocol.ts
D-OPEN SOVEREIGN
1/*
2 * Copyright (c) 2026 DataPond D-Library Pty Ltd. ("The Sanctuary")
3 * Non-Profit Public Library — The World Library
4 * 
5 * D-SAFE Certification issued by POND Enterprise.
6 * Published under the D-Open Code Sovereign Licence v1.0 framework
7 * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.
8 * https://registry.world.bibliotech.com/licence
9 * Source code donated to DataPond D-Library by it's author: data pond.
10 * 
11 * Technical Guardian ("The Shield"): Pond Enterprise Pty Ltd. (ACN 694 747 987)
12 * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.
13 * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.
14 */
15// Discriminated union message protocol shared by both sides of every worker boundary.
16
17export type FilePhase = 'unknown' | 'queued' | 'downloading' | 'done' | 'error';
18
19export interface FileState {
20    phase: FilePhase;
21    loaded?: number;
22    total?: number;
23    error?: string;
24}
25
26export interface BookData {
27    txId:       string;
28    dimensions: Array<{ width: number; height: number }>;
29    parsed:     boolean;
30}
31
32// ─── Main thread → File worker ───────────────────────────────────────────────
33
34export type WorkerCommand =
35    | { type: 'GetFile';        txId: string; mime: 'pdf' | 'preview' }
36    | { type: 'ProcessPages';   txId: string; from: number; to: number }
37    | { type: 'CancelDownload'; txId: string };
38
39// ─── Main thread → Mu worker (separate worker) ───────────────────────────────
40
41// Init MUST be the first message sent to the mu-worker. mupdf is loaded via
42// dynamic import from a URL sibling to the worker script — not bundled — because
43// esbuild cannot bundle WASM loaders that contain Node.js environment detection.
44export type MuWorkerCommand =
45    | { type: 'MuInit';       mupdfUrl: string }
46    | { type: 'ProcessPages'; txId: string; from: number; to: number };
47
48// ─── File worker → Main thread ───────────────────────────────────────────────
49
50export type WorkerMessage =
51    | { type: 'FileRpcResponse'; ok: boolean; key: string; error?: string }
52    | { type: 'HYDRATE';             payload: HydratePayload }
53    | { type: 'DownloadProgress';    txId: string; loaded: number; total?: number }
54    | { type: 'DownloadFinished';    txId: string; key: string; mime: 'pdf' | 'preview' }
55    | { type: 'DownloadError';       txId: string; error: string; retryable: boolean }
56    | { type: 'StoragePruneStarted'; targetFreeBytes: number }
57    | { type: 'StoragePruned';       removed: number; freedBytes: number; prunedTxIds: string[] }
58    | { type: 'MuPageDone';  txId: string; page: number }
59    | { type: 'MuPageError'; txId: string; page: number; error: string }
60    | { type: 'MuPdfData';   txId: string; bookData: BookData };
61
62export interface HydratePayload {
63    files:   Array<[txId: string, state: FileState]>;
64    renders: Array<[txId: string, pages: Array<[page: number, phase: FilePhase]>]>;
65}
66