import { OneNoteExportError } from '../onenote/export/index.js'; import type { OneNotePackageDto, OneNotePageDto, OneNoteSectionDto, } from '../onenote/model/dto.js'; import type { OneNoteResource } from '../onenote/one/content-model.js'; import { createWorkerExportArtifact } from './export-adapter.js'; import { failureFromUnknown, openPackageForWorker, openPackageSetForWorker, openSectionForWorker, resourcePayload, workerPageKey, workerResourceKey, } from './parser-adapter.js'; import type { WorkerFailure, WorkerRequest, WorkerResponse, } from './worker-protocol.js'; interface ModuleWorkerScope { onmessage: ((event: MessageEvent) => void) | null; postMessage(response: WorkerResponse, transfer?: Transferable[]): void; } interface ParserSession { source: OneNoteSectionDto | OneNotePackageDto; pages: Map; resources: Map; } const workerScope = globalThis as unknown as ModuleWorkerScope; const sessions = new Map(); let sessionSequence = 0; function createSession( source: OneNoteSectionDto | OneNotePackageDto, pages: Map, resources: Map ): string { const id = `session-${++sessionSequence}`; sessions.set(id, { source, pages, resources }); return id; } async function handleRequest(data: WorkerRequest): Promise { switch (data.type) { case 'parse-one': { try { const parsed = openSectionForWorker( new Uint8Array(data.bytes), data.fileName ); const sessionId = createSession( parsed.section, parsed.pages, parsed.resources ); workerScope.postMessage({ type: 'section', requestId: data.requestId, sessionId, section: parsed.section, }); } catch (error) { workerScope.postMessage({ type: 'failure', requestId: data.requestId, error: failureFromUnknown(error), }); } return; } case 'parse-onepkg': try { const parsed = data.cabinetParts && data.cabinetParts.length > 0 ? await openPackageSetForWorker( [ { fileName: data.fileName, bytes: new Uint8Array(data.bytes), }, ...data.cabinetParts.map((part) => ({ fileName: part.fileName, bytes: new Uint8Array(part.bytes), })), ], data.fileName ) : await openPackageForWorker( new Uint8Array(data.bytes), data.fileName ); const sessionId = createSession( parsed.notebook, parsed.pages, parsed.resources ); workerScope.postMessage({ type: 'package', requestId: data.requestId, sessionId, notebook: parsed.notebook, }); } catch (error) { workerScope.postMessage({ type: 'failure', requestId: data.requestId, error: failureFromUnknown(error), }); } return; case 'get-page': { const session = sessions.get(data.sessionId); if (!session) { workerScope.postMessage({ type: 'failure', requestId: data.requestId, error: { code: 'session-not-available', message: 'The parser session is no longer available.', recoverable: false, }, }); return; } const page = session.pages.get( workerPageKey(data.pageId, data.sectionId) ); if (!page) { workerScope.postMessage({ type: 'failure', requestId: data.requestId, error: { code: 'page-not-available', message: 'The selected page is not available in this source.', recoverable: true, }, }); return; } workerScope.postMessage({ type: 'page', requestId: data.requestId, sessionId: data.sessionId, page, }); return; } case 'get-resource': { const session = sessions.get(data.sessionId); if (!session) { workerScope.postMessage({ type: 'failure', requestId: data.requestId, error: { code: 'session-not-available', message: 'The parser session is no longer available.', recoverable: false, }, }); return; } const resource = session.resources.get( workerResourceKey(data.resourceId, data.sectionId) ); const payload = resource ? resourcePayload(resource, data.intent) : undefined; if (!payload) { workerScope.postMessage({ type: 'failure', requestId: data.requestId, error: { code: 'resource-not-available', message: data.intent === 'preview' && resource ? 'This image can be downloaded but is not approved for automatic preview.' : 'The selected embedded resource is not available.', recoverable: true, }, }); return; } workerScope.postMessage( { type: 'resource', requestId: data.requestId, sessionId: data.sessionId, resource: payload, }, [payload.bytes] ); return; } case 'export-session': { const session = sessions.get(data.sessionId); if (!session) { workerScope.postMessage({ type: 'failure', requestId: data.requestId, error: { code: 'session-not-available', message: 'The parser session is no longer available.', recoverable: false, }, }); return; } try { const artifact = createWorkerExportArtifact( session.source, session.pages, session.resources, data.format ); workerScope.postMessage( { type: 'export-artifact', requestId: data.requestId, sessionId: data.sessionId, artifact, }, [artifact.bytes] ); } catch (error) { workerScope.postMessage({ type: 'failure', requestId: data.requestId, error: exportFailureFromUnknown(error), }); } return; } case 'dispose': sessions.delete(data.sessionId); workerScope.postMessage({ type: 'disposed', sessionId: data.sessionId, }); } } function exportFailureFromUnknown(error: unknown): WorkerFailure { if (error instanceof OneNoteExportError) { return { code: error.code === 'limit-exceeded' ? 'limit-exceeded' : 'export-failed', message: error.message, recoverable: true, structure: 'OneNote export', }; } return { code: 'export-failed', message: error instanceof Error ? error.message : 'The local notebook export could not be created.', recoverable: true, structure: 'OneNote export', }; } workerScope.onmessage = ({ data }) => { void handleRequest(data); };