@arbidocs/react 0.5.86 → 0.5.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/dist/artifacts/index.cjs +46 -48
- package/dist/artifacts/index.cjs.map +1 -1
- package/dist/artifacts/index.js +7 -9
- package/dist/artifacts/index.js.map +1 -1
- package/dist/calls/livekit/index.cjs +60 -62
- package/dist/calls/livekit/index.cjs.map +1 -1
- package/dist/calls/livekit/index.js +6 -8
- package/dist/calls/livekit/index.js.map +1 -1
- package/dist/{chunk-Z3LLUO32.cjs → chunk-5NOZDH3F.cjs} +12 -2
- package/dist/chunk-5NOZDH3F.cjs.map +1 -0
- package/dist/{chunk-WQY3RQ6G.js → chunk-73ENECAT.js} +5 -6
- package/dist/{chunk-LUDIYWT7.cjs.map → chunk-73ENECAT.js.map} +1 -1
- package/dist/{chunk-2Y2WOIHH.cjs → chunk-AOPGD23L.cjs} +60 -148
- package/dist/chunk-AOPGD23L.cjs.map +1 -0
- package/dist/{chunk-G4Z3IP4J.js → chunk-BF5KW5ZI.js} +3 -17
- package/dist/chunk-BF5KW5ZI.js.map +1 -0
- package/dist/{chunk-TK7ERJPE.js → chunk-BFNY3RZG.js} +22 -12
- package/dist/chunk-BFNY3RZG.js.map +1 -0
- package/dist/{chunk-U4PWVSCT.cjs → chunk-C4WODQGO.cjs} +24 -11
- package/dist/chunk-C4WODQGO.cjs.map +1 -0
- package/dist/{chunk-E7VD5WNY.cjs → chunk-DS7NTSKH.cjs} +41 -74
- package/dist/chunk-DS7NTSKH.cjs.map +1 -0
- package/dist/{chunk-JT7PN7JH.js → chunk-DU2P354H.js} +6 -37
- package/dist/chunk-DU2P354H.js.map +1 -0
- package/dist/{chunk-TAVS54EN.cjs → chunk-GKWMT64A.cjs} +6 -6
- package/dist/{chunk-TAVS54EN.cjs.map → chunk-GKWMT64A.cjs.map} +1 -1
- package/dist/{chunk-AXKHDLBB.cjs → chunk-HEVPIVF2.cjs} +15 -15
- package/dist/{chunk-AXKHDLBB.cjs.map → chunk-HEVPIVF2.cjs.map} +1 -1
- package/dist/{chunk-XPLD4LFC.js → chunk-KTXZ222T.js} +6 -91
- package/dist/chunk-KTXZ222T.js.map +1 -0
- package/dist/{chunk-PXWKJI4K.cjs → chunk-LBAG7KL7.cjs} +35 -261
- package/dist/chunk-LBAG7KL7.cjs.map +1 -0
- package/dist/{chunk-CSPAEVZS.js → chunk-MS43RNXM.js} +5 -5
- package/dist/{chunk-CSPAEVZS.js.map → chunk-MS43RNXM.js.map} +1 -1
- package/dist/{chunk-OC7F5SNA.cjs → chunk-MXP4O4DI.cjs} +5 -5
- package/dist/{chunk-OC7F5SNA.cjs.map → chunk-MXP4O4DI.cjs.map} +1 -1
- package/dist/{chunk-ZWFMFOGP.cjs → chunk-NDIKMOBJ.cjs} +4 -4
- package/dist/{chunk-ZWFMFOGP.cjs.map → chunk-NDIKMOBJ.cjs.map} +1 -1
- package/dist/{chunk-XAEVT7ZM.js → chunk-NNAJLY6B.js} +34 -257
- package/dist/chunk-NNAJLY6B.js.map +1 -0
- package/dist/{chunk-LUDIYWT7.cjs → chunk-QLRDHLWR.cjs} +72 -73
- package/dist/chunk-QLRDHLWR.cjs.map +1 -0
- package/dist/{chunk-DZUBZ45Y.cjs → chunk-RLSBRZ6Z.cjs} +2 -17
- package/dist/chunk-RLSBRZ6Z.cjs.map +1 -0
- package/dist/{chunk-VGAA7AFS.js → chunk-S3OGDLDC.js} +4 -13
- package/dist/chunk-S3OGDLDC.js.map +1 -0
- package/dist/{chunk-NNWMHMEC.js → chunk-UW2SGTI5.js} +3 -3
- package/dist/{chunk-NNWMHMEC.js.map → chunk-UW2SGTI5.js.map} +1 -1
- package/dist/{chunk-QRCMKEE6.js → chunk-VSCU7K4V.js} +11 -3
- package/dist/chunk-VSCU7K4V.js.map +1 -0
- package/dist/{chunk-C44GO33B.js → chunk-WL2Y2T47.js} +3 -3
- package/dist/{chunk-C44GO33B.js.map → chunk-WL2Y2T47.js.map} +1 -1
- package/dist/{chunk-47YVW3J4.js → chunk-YQBDEOVE.js} +4 -4
- package/dist/{chunk-47YVW3J4.js.map → chunk-YQBDEOVE.js.map} +1 -1
- package/dist/{chunk-Q6U7ALNV.cjs → chunk-ZHXYFJIA.cjs} +44 -54
- package/dist/chunk-ZHXYFJIA.cjs.map +1 -0
- package/dist/document-tools/core.cjs +100 -110
- package/dist/document-tools/core.d.cts +3 -78
- package/dist/document-tools/core.d.ts +3 -78
- package/dist/document-tools/core.js +5 -7
- package/dist/document-tools/index.cjs +102 -112
- package/dist/document-tools/index.cjs.map +1 -1
- package/dist/document-tools/index.d.cts +2 -2
- package/dist/document-tools/index.d.ts +2 -2
- package/dist/document-tools/index.js +6 -8
- package/dist/document-tools/index.js.map +1 -1
- package/dist/index.cjs +1740 -2305
- package/dist/index.cjs.map +1 -1
- package/dist/{index.d-BDcwpFVa.d.cts → index.d-1_bJB-Yl.d.cts} +1 -58
- package/dist/{index.d-BDcwpFVa.d.ts → index.d-1_bJB-Yl.d.ts} +1 -58
- package/dist/{index.d-Deqz5-pF.d.ts → index.d-ChaR6kMc.d.cts} +1 -6
- package/dist/{index.d-Deqz5-pF.d.cts → index.d-ChaR6kMc.d.ts} +1 -6
- package/dist/index.d.cts +184 -1423
- package/dist/index.d.ts +184 -1423
- package/dist/index.js +281 -799
- package/dist/index.js.map +1 -1
- package/dist/{query-keys.d-Dm0NL9nr.d.cts → query-keys.d-D6SAUl7S.d.cts} +0 -9
- package/dist/{query-keys.d-Dm0NL9nr.d.ts → query-keys.d-D6SAUl7S.d.ts} +0 -9
- package/dist/shell/index.cjs +48 -53
- package/dist/shell/index.d.cts +1 -1
- package/dist/shell/index.d.ts +1 -1
- package/dist/shell/index.js +4 -5
- package/dist/ui/index.cjs +156 -169
- package/dist/ui/index.d.cts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -4
- package/dist/viewers/index.cjs +0 -120
- package/dist/viewers/index.cjs.map +1 -1
- package/dist/viewers/index.d.cts +3 -40
- package/dist/viewers/index.d.ts +3 -40
- package/dist/viewers/index.js +1 -120
- package/dist/viewers/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-2Y2WOIHH.cjs.map +0 -1
- package/dist/chunk-CPZ36AQS.js +0 -11
- package/dist/chunk-CPZ36AQS.js.map +0 -1
- package/dist/chunk-DZUBZ45Y.cjs.map +0 -1
- package/dist/chunk-E7VD5WNY.cjs.map +0 -1
- package/dist/chunk-G4Z3IP4J.js.map +0 -1
- package/dist/chunk-JT7PN7JH.js.map +0 -1
- package/dist/chunk-PXWKJI4K.cjs.map +0 -1
- package/dist/chunk-Q6U7ALNV.cjs.map +0 -1
- package/dist/chunk-QRCMKEE6.js.map +0 -1
- package/dist/chunk-RCKA7BEF.cjs +0 -14
- package/dist/chunk-RCKA7BEF.cjs.map +0 -1
- package/dist/chunk-TK7ERJPE.js.map +0 -1
- package/dist/chunk-U4PWVSCT.cjs.map +0 -1
- package/dist/chunk-VGAA7AFS.js.map +0 -1
- package/dist/chunk-VGMMK5OM.cjs +0 -26
- package/dist/chunk-VGMMK5OM.cjs.map +0 -1
- package/dist/chunk-VGO77X5U.js +0 -22
- package/dist/chunk-VGO77X5U.js.map +0 -1
- package/dist/chunk-WQY3RQ6G.js.map +0 -1
- package/dist/chunk-XAEVT7ZM.js.map +0 -1
- package/dist/chunk-XPLD4LFC.js.map +0 -1
- package/dist/chunk-Z3LLUO32.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/document-tools/production.ts"],"names":["fetchDocumentFile","fetchDocumentPdf","DocumentFetchError"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Production sets: number the selected documents with Bates labels (optionally a QR code back to\n * each document and an index page) and save the result back to the workspace. The dialog is\n * `ProductionSetDialog` in `@arbidocs/blocks/document-tools`; this is its data side.\n *\n * A PDF is numbered as stored (`/download`). Any other document is numbered through its PDF\n * rendition (`/view`, what the viewer shows for a Word or text file); one without a rendition is\n * left out. Saved results are new documents derived from their sources (role `production`) in a\n * Productions folder, shared with the workspace only if every source is. The originals never\n * change.\n *\n * pdf-lib (the numbering) is loaded only when a production is built, so importing this module\n * stays as light as the rest of the document tools.\n */\n\nimport type { components } from '@arbidocs/client'\nimport type { ProductionChoices } from '../annotations/ProductionDialog'\nimport type { BundleFile, BundleIndexEntry, BundleItem } from '../annotations/freeze/bundle'\nimport { DocumentFetchError, fetchDocumentFile, fetchDocumentPdf } from './document-pdf'\nimport type {\n DocumentToolsClient,\n DocumentToolsEnvironment,\n DocumentUploadQuery,\n} from './environment'\n\n/** The fields of a document record (`DocResponse`) a production uses. */\nexport type ProductionSource = Pick<\n components['schemas']['DocResponse'],\n 'external_id' | 'file_name' | 'file_type' | 'shared'\n> & {\n doc_metadata?: { title?: string | null } | null\n /** The document's workspace: the produced files are saved there, named on the upload. */\n workspace_ext_id?: string | null\n}\n\nexport const PRODUCTIONS_FOLDER = 'Productions'\n\nconst extensionOf = (fileName: string | null | undefined) => {\n const name = (fileName ?? '').toLowerCase()\n const dot = name.lastIndexOf('.')\n return dot < 0 ? '' : name.slice(dot + 1)\n}\n\n/** Media, archives and design files: no PDF version to number. */\nconst NO_RENDITION_EXTENSIONS = new Set(\n [\n // images\n 'jpg jpeg png gif bmp tiff tif webp heic',\n // video and audio\n 'mp4 mpeg mpg webm mov avi mkv mp3 wav m4a aac ogg flac',\n // archives, binaries, design files\n 'zip rar 7z tar gz exe bin dmg iso apk msi dll so psd ai sketch',\n ]\n .join(' ')\n .split(' ')\n)\n\nexport const isPdfDocument = (doc: ProductionSource) =>\n /pdf/i.test(doc.file_type ?? '') || extensionOf(doc.file_name) === 'pdf'\n\n/** True for a document with no PDF version to number (media, archives and the like). */\nexport const hasNoRendition = (doc: ProductionSource) =>\n !isPdfDocument(doc) && NO_RENDITION_EXTENSIONS.has(extensionOf(doc.file_name))\n\n/** The name a document goes by in the dialog and the index: its title, else its file name. */\nexport const productionDocumentName = (doc: ProductionSource) =>\n doc.doc_metadata?.title || doc.file_name || doc.external_id\n\nconst isPdfBytes = (bytes: Uint8Array) =>\n bytes.length > 4 && String.fromCharCode(...bytes.subarray(0, 5)) === '%PDF-'\n\n/**\n * The PDF to number for `doc`: the file itself, or the PDF version of anything else. `null` when a\n * non-PDF has no PDF version (yet), so it is left out; a PDF that cannot be downloaded throws.\n */\nexport async function fetchProductionPdf(\n client: DocumentToolsClient,\n doc: ProductionSource\n): Promise<Uint8Array | null> {\n const pdf = isPdfDocument(doc)\n let blob: Blob\n try {\n blob = await (pdf ? fetchDocumentFile : fetchDocumentPdf)(client, doc.external_id)\n } catch (e) {\n if (!pdf && e instanceof DocumentFetchError) return null\n throw e\n }\n const bytes = new Uint8Array(await blob.arrayBuffer())\n return pdf || isPdfBytes(bytes) ? bytes : null\n}\n\nconst safeName = (name: string) => name.replace(/[\\\\/:*?\"<>|]+/g, '_').trim()\n\n/** \"Production ACME-000001-ACME-000042\": names the files and folder of one production. */\nexport function productionTitle(firstLabel: string, lastLabel: string): string {\n return safeName(`Production ${firstLabel}-${lastLabel}`)\n}\n\n/** Where a production is saved: the Productions folder, or a folder of its own per document. */\nexport function productionFolder(title: string, merged: boolean): string {\n return merged ? PRODUCTIONS_FOLDER : `${PRODUCTIONS_FOLDER}/${title}`\n}\n\n/** In the workspace a per-document file says which range it holds, beside its original. */\nexport function productionFileName(file: BundleFile, title: string): string {\n if (!file.firstLabel) return `${title} index.pdf`\n return `${file.name.replace(/\\.pdf$/i, '')} (${file.firstLabel}-${file.lastLabel}).pdf`\n}\n\nconst csvCell = (value: string | number) => `\"${String(value).replace(/\"/g, '\"\"')}\"`\n\n/** The `index.csv` of a per-document production: every document with its file and range. */\nexport function productionIndexCsv(index: readonly BundleIndexEntry[]): string {\n const rows = index.map((e) =>\n [e.documentId, e.name, e.file, e.pages, e.firstLabel, e.lastLabel].map(csvCell).join(',')\n )\n return ['document_id,name,file,pages,first_label,last_label', ...rows].join('\\n')\n}\n\nexport interface ProductionUpload {\n name: string\n bytes: Uint8Array\n /** The documents this file was made from. */\n sources: ProductionSource[]\n}\n\n/** Save each file as a new workspace document derived from its sources; returns the new ids. */\nexport async function saveProductionFiles(\n upload: NonNullable<DocumentToolsEnvironment['uploadDocument']>,\n files: readonly ProductionUpload[],\n folder: string\n): Promise<string[]> {\n const ids: string[] = []\n for (const file of files) {\n const query: DocumentUploadQuery = {\n derived_from: file.sources.map((doc) => doc.external_id),\n derived_role: 'production',\n shared: file.sources.every((doc) => doc.shared),\n folder,\n }\n // Saved in the sources' workspace, named on the upload (never whichever one is open now).\n const workspaces = new Set(file.sources.map((doc) => doc.workspace_ext_id).filter(Boolean))\n if (workspaces.size === 1) query.workspace_ext_id = [...workspaces][0]\n const response = await upload({\n file: new File([file.bytes as BlobPart], file.name, { type: 'application/pdf' }),\n query,\n })\n ids.push(...(response?.doc_ext_ids ?? []))\n }\n return ids\n}\n\nexport interface BuildProductionOptions {\n /** The link a document's QR code opens (the document in the host app). */\n documentUrl: (documentId: string) => string\n /** Who produced the set; recorded in a merged file's metadata. */\n author?: string\n onProgress?: (done: number, total: number) => void\n}\n\nexport interface BuiltProduction {\n title: string\n merged: boolean\n /** The numbered files: one merged PDF (named after its range), or one per document (+ index). */\n files: BundleFile[]\n index: BundleIndexEntry[]\n /** The documents numbered, in order. */\n included: ProductionSource[]\n /** Documents left out because they have no PDF version yet. */\n noRendition: ProductionSource[]\n /** The files as they are saved to the workspace, each with the documents it was made from. */\n uploads: ProductionUpload[]\n folder: string\n}\n\n/**\n * Fetch each document's PDF (in `choices.order`) and number the set. Throws when none of the\n * documents has a PDF version, or when a PDF cannot be fetched.\n */\nexport async function buildProduction(\n client: DocumentToolsClient,\n documents: readonly ProductionSource[],\n choices: ProductionChoices,\n options: BuildProductionOptions\n): Promise<BuiltProduction> {\n const byId = new Map(documents.map((doc) => [doc.external_id, doc]))\n const included: ProductionSource[] = []\n const noRendition: ProductionSource[] = []\n const items: BundleItem[] = []\n for (const doc of choices.order.flatMap((id) => byId.get(id) ?? [])) {\n const bytes = await fetchProductionPdf(client, doc)\n if (!bytes) {\n noRendition.push(doc)\n continue\n }\n included.push(doc)\n items.push({\n name: productionDocumentName(doc),\n documentId: doc.external_id,\n bytes,\n qrUrl: options.documentUrl(doc.external_id),\n })\n }\n if (items.length === 0) {\n throw new Error('None of these documents has a PDF version to number yet.')\n }\n\n const { buildBundle } = await import('../annotations/freeze/bundle')\n const result = await buildBundle(items, {\n layout: choices.layout,\n bates: {\n prefix: choices.prefix,\n start: choices.start,\n digits: choices.digits,\n corner: choices.corner,\n },\n qr: choices.qr,\n // The QR code sits in the bottom corner the label is not in.\n qrCorner: choices.corner.endsWith('left') ? 'bottom-right' : 'bottom-left',\n indexPage: choices.indexPage,\n author: options.author,\n onProgress: options.onProgress,\n })\n\n const title = productionTitle(\n result.index[0].firstLabel,\n result.index[result.index.length - 1].lastLabel\n )\n const merged = choices.layout === 'merged'\n // A merged file is named after its range; per-document files keep their document names.\n const files = merged ? [{ ...result.files[0], name: `${title}.pdf` }] : result.files\n const sourceOf = new Map(result.index.map((e) => [e.file, byId.get(e.documentId)!]))\n const uploads = files.map((file) => ({\n name: merged ? file.name : productionFileName(file, title),\n bytes: file.bytes,\n // The merged file (and a separate index) is made from every document; each per-document\n // file from its own.\n sources: merged || !sourceOf.has(file.name) ? included : [sourceOf.get(file.name)!],\n }))\n return {\n title,\n merged,\n files,\n index: result.index,\n included,\n noRendition,\n uploads,\n folder: productionFolder(title, merged),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/document-tools/production.ts"],"names":["fetchDocumentFile","fetchDocumentPdf","DocumentFetchError"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Production sets: number the selected documents with Bates labels (optionally a QR code back to\n * each document and an index page) and save the result back to the workspace. The dialog is\n * `ProductionSetDialog` in `@arbidocs/blocks/document-tools`; this is its data side.\n *\n * A PDF is numbered as stored (`/download`). Any other document is numbered through its PDF\n * rendition (`/view`, what the viewer shows for a Word or text file); one without a rendition is\n * left out. Saved results are new documents derived from their sources (role `production`) in a\n * Productions folder, shared with the workspace only if every source is. The originals never\n * change.\n *\n * pdf-lib (the numbering) is loaded only when a production is built, so importing this module\n * stays as light as the rest of the document tools.\n */\n\nimport type { components } from '@arbidocs/client'\nimport type { ProductionChoices } from '../annotations/ProductionDialog'\nimport type { BundleFile, BundleIndexEntry, BundleItem } from '../annotations/freeze/bundle'\nimport { DocumentFetchError, fetchDocumentFile, fetchDocumentPdf } from './document-pdf'\nimport type {\n DocumentToolsClient,\n DocumentToolsEnvironment,\n DocumentUploadQuery,\n} from './environment'\n\n/** The fields of a document record (`DocResponse`) a production uses. */\nexport type ProductionSource = Pick<\n components['schemas']['DocResponse'],\n 'external_id' | 'file_name' | 'file_type' | 'shared'\n> & {\n doc_metadata?: { title?: string | null } | null\n /** The document's workspace: the produced files are saved there, named on the upload. */\n workspace_ext_id?: string | null\n}\n\nexport const PRODUCTIONS_FOLDER = 'Productions'\n\nconst extensionOf = (fileName: string | null | undefined) => {\n const name = (fileName ?? '').toLowerCase()\n const dot = name.lastIndexOf('.')\n return dot < 0 ? '' : name.slice(dot + 1)\n}\n\n/** Media, archives and design files: no PDF version to number. */\nconst NO_RENDITION_EXTENSIONS = new Set(\n [\n // images\n 'jpg jpeg png gif bmp tiff tif webp heic',\n // video and audio\n 'mp4 mpeg mpg webm mov avi mkv mp3 wav m4a aac ogg flac',\n // archives, binaries, design files\n 'zip rar 7z tar gz exe bin dmg iso apk msi dll so psd ai sketch',\n ]\n .join(' ')\n .split(' ')\n)\n\nexport const isPdfDocument = (doc: ProductionSource) =>\n /pdf/i.test(doc.file_type ?? '') || extensionOf(doc.file_name) === 'pdf'\n\n/** True for a document with no PDF version to number (media, archives and the like). */\nexport const hasNoRendition = (doc: ProductionSource) =>\n !isPdfDocument(doc) && NO_RENDITION_EXTENSIONS.has(extensionOf(doc.file_name))\n\n/** The name a document goes by in the dialog and the index: its title, else its file name. */\nexport const productionDocumentName = (doc: ProductionSource) =>\n doc.doc_metadata?.title || doc.file_name || doc.external_id\n\nconst isPdfBytes = (bytes: Uint8Array) =>\n bytes.length > 4 && String.fromCharCode(...bytes.subarray(0, 5)) === '%PDF-'\n\n/**\n * The PDF to number for `doc`: the file itself, or the PDF version of anything else. `null` when a\n * non-PDF has no PDF version (yet), so it is left out; a PDF that cannot be downloaded throws.\n */\nexport async function fetchProductionPdf(\n client: DocumentToolsClient,\n doc: ProductionSource\n): Promise<Uint8Array | null> {\n const pdf = isPdfDocument(doc)\n let blob: Blob\n try {\n blob = await (pdf ? fetchDocumentFile : fetchDocumentPdf)(client, doc.external_id)\n } catch (e) {\n if (!pdf && e instanceof DocumentFetchError) return null\n throw e\n }\n const bytes = new Uint8Array(await blob.arrayBuffer())\n return pdf || isPdfBytes(bytes) ? bytes : null\n}\n\nconst safeName = (name: string) => name.replace(/[\\\\/:*?\"<>|]+/g, '_').trim()\n\n/** \"Production ACME-000001-ACME-000042\": names the files and folder of one production. */\nexport function productionTitle(firstLabel: string, lastLabel: string): string {\n return safeName(`Production ${firstLabel}-${lastLabel}`)\n}\n\n/** Where a production is saved: the Productions folder, or a folder of its own per document. */\nexport function productionFolder(title: string, merged: boolean): string {\n return merged ? PRODUCTIONS_FOLDER : `${PRODUCTIONS_FOLDER}/${title}`\n}\n\n/** In the workspace a per-document file says which range it holds, beside its original. */\nexport function productionFileName(file: BundleFile, title: string): string {\n if (!file.firstLabel) return `${title} index.pdf`\n return `${file.name.replace(/\\.pdf$/i, '')} (${file.firstLabel}-${file.lastLabel}).pdf`\n}\n\nconst csvCell = (value: string | number) => `\"${String(value).replace(/\"/g, '\"\"')}\"`\n\n/** The `index.csv` of a per-document production: every document with its file and range. */\nexport function productionIndexCsv(index: readonly BundleIndexEntry[]): string {\n const rows = index.map((e) =>\n [e.documentId, e.name, e.file, e.pages, e.firstLabel, e.lastLabel].map(csvCell).join(',')\n )\n return ['document_id,name,file,pages,first_label,last_label', ...rows].join('\\n')\n}\n\nexport interface ProductionUpload {\n name: string\n bytes: Uint8Array\n /** The documents this file was made from. */\n sources: ProductionSource[]\n}\n\n/** Save each file as a new workspace document derived from its sources; returns the new ids. */\nexport async function saveProductionFiles(\n upload: NonNullable<DocumentToolsEnvironment['uploadDocument']>,\n files: readonly ProductionUpload[],\n folder: string\n): Promise<string[]> {\n const ids: string[] = []\n for (const file of files) {\n const query: DocumentUploadQuery = {\n derived_from: file.sources.map((doc) => doc.external_id),\n derived_role: 'production',\n shared: file.sources.every((doc) => doc.shared),\n folder,\n }\n // Saved in the sources' workspace, named on the upload (never whichever one is open now).\n const workspaces = new Set(file.sources.map((doc) => doc.workspace_ext_id).filter(Boolean))\n if (workspaces.size === 1) query.workspace_ext_id = [...workspaces][0]\n const response = await upload({\n file: new File([file.bytes as BlobPart], file.name, { type: 'application/pdf' }),\n query,\n })\n ids.push(...(response?.doc_ext_ids ?? []))\n }\n return ids\n}\n\nexport interface BuildProductionOptions {\n /** The link a document's QR code opens (the document in the host app). */\n documentUrl: (documentId: string) => string\n /** Who produced the set; recorded in a merged file's metadata. */\n author?: string\n onProgress?: (done: number, total: number) => void\n}\n\nexport interface BuiltProduction {\n title: string\n merged: boolean\n /** The numbered files: one merged PDF (named after its range), or one per document (+ index). */\n files: BundleFile[]\n index: BundleIndexEntry[]\n /** The documents numbered, in order. */\n included: ProductionSource[]\n /** Documents left out because they have no PDF version yet. */\n noRendition: ProductionSource[]\n /** The files as they are saved to the workspace, each with the documents it was made from. */\n uploads: ProductionUpload[]\n folder: string\n}\n\n/**\n * Fetch each document's PDF (in `choices.order`) and number the set. Throws when none of the\n * documents has a PDF version, or when a PDF cannot be fetched.\n */\nexport async function buildProduction(\n client: DocumentToolsClient,\n documents: readonly ProductionSource[],\n choices: ProductionChoices,\n options: BuildProductionOptions\n): Promise<BuiltProduction> {\n const byId = new Map(documents.map((doc) => [doc.external_id, doc]))\n const included: ProductionSource[] = []\n const noRendition: ProductionSource[] = []\n const items: BundleItem[] = []\n for (const doc of choices.order.flatMap((id) => byId.get(id) ?? [])) {\n const bytes = await fetchProductionPdf(client, doc)\n if (!bytes) {\n noRendition.push(doc)\n continue\n }\n included.push(doc)\n items.push({\n name: productionDocumentName(doc),\n documentId: doc.external_id,\n bytes,\n qrUrl: options.documentUrl(doc.external_id),\n })\n }\n if (items.length === 0) {\n throw new Error('None of these documents has a PDF version to number yet.')\n }\n\n const { buildBundle } = await import('../annotations/freeze/bundle')\n const result = await buildBundle(items, {\n layout: choices.layout,\n bates: {\n prefix: choices.prefix,\n start: choices.start,\n digits: choices.digits,\n corner: choices.corner,\n },\n qr: choices.qr,\n // The QR code sits in the bottom corner the label is not in.\n qrCorner: choices.corner.endsWith('left') ? 'bottom-right' : 'bottom-left',\n indexPage: choices.indexPage,\n author: options.author,\n onProgress: options.onProgress,\n })\n\n const title = productionTitle(\n result.index[0].firstLabel,\n result.index[result.index.length - 1].lastLabel\n )\n const merged = choices.layout === 'merged'\n // A merged file is named after its range; per-document files keep their document names.\n const files = merged ? [{ ...result.files[0], name: `${title}.pdf` }] : result.files\n const sourceOf = new Map(result.index.map((e) => [e.file, byId.get(e.documentId)!]))\n const uploads = files.map((file) => ({\n name: merged ? file.name : productionFileName(file, title),\n bytes: file.bytes,\n // The merged file (and a separate index) is made from every document; each per-document\n // file from its own.\n sources: merged || !sourceOf.has(file.name) ? included : [sourceOf.get(file.name)!],\n }))\n return {\n title,\n merged,\n files,\n index: result.index,\n included,\n noRendition,\n uploads,\n folder: productionFolder(title, merged),\n }\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DocumentToolsClient, DocumentToolsEnvironment } from './core.cjs';
|
|
2
|
-
export { AdoptedSignature, AnnotatableState, CopyMatch, CreateFileShare, DEFAULT_FIELD_SIZE, DocumentChange, DocumentFetchError, DocumentFetchOptions, DocumentToolsNoticeKind, DocumentToolsNoticeOptions, DocumentToolsNotify, DocumentToolsProvider, DocumentToolsProviderProps, DocumentToolsUser, DocumentUploadQuery, DocumentUploadRequest, FIELD_TYPE_LABELS, FileShare, FrozenCopySource, INFORMAL_SIGNATURE_NOTE, KeypairSource, LEGACY_LAYER_PREFIX, LegacyPrompt, MARK_FIELD_TYPES, MAX_MERGE_ATTEMPTS, MarkupDocument, MarkupDownloadError, MarkupSnapshot, MarkupStore, MarkupStoreError, MarkupStoreOptions, NamedSigner, OlderMarkupNote, ResolvedDocumentToolsEnvironment, SIGNATURE_FIELD_TYPES, SIGNED_LOCKED_REASON, SIGNED_UNCHANGED, SIGNER_PROGRESS_LABELS, SaveSignatureRequestVars, SavedSignature, SignDocumentResponse, SignDocumentVars, SignRequestSignResponse, SignRequestVars, SignatureAppearance, SignatureField, SignatureFieldSuggestions, SignatureFieldType, SignatureRecord, SignatureRequest, SignatureRequestSigner, SignatureStatusResponse, SignatureVerification, SignatureVerificationError, SignerCandidate, SignerDetails, SignerProgress, SigningError, SigningErrorReason, SuggestedSignatureField, UseDocumentBytesOptions, VERIFY_PATH, VerifiedSignature, VersionInfo, addToMarkup, canAnnotate, certificateLink, clientUpload, contentDispositionFileName, copyOpenThreads, createFileShare, createMarkupStore, currentHasMarkup, defaultCertificateUrl, deleteSavedSignature, downloadBlob, fetchDocumentFile, fetchDocumentPdf, fetchDocumentSignatureRequests, fetchDocumentSignatures, fetchMarkupPdf, fetchSavedSignature, fetchSignatureVerification, fieldsFromSuggestions, fieldsInSigningOrder, fileShareBytes, fileShareSigningRequest, forgetLegacyLayer, frozenCopyName, getFileShare, initialsOf, intentText, inviteSigners, isEmailSigner, isLegibleSignatureBox, isSignatureReference, isSignedVersion, marksByVersion, matchSignedCopy, migrateLegacyLayer, newFieldId, openThreadsOf, pngBytes, pngSize, readLegacyLayer, redactionLogName, saveSignatureRequest, sendBlocker, sha256Hex, signDocument, signFileShare, signSignatureRequest, signatureFieldSuggestions, splitSuggestions, storeSavedSignature, suggestSignatureFields, toAppearance, uploadFrozenCopy, uploadQueryString, useDeclineSignatureRequest, useDeleteSavedSignature, useDocumentBytes, useDocumentMarkup, useDocumentSignatureRequests, useDocumentSignatures, useDocumentTools, useFileShare, useFileSharePdf, useFileShares, useInviteSigners, useIsOnline, useOptionalDocumentTools, useSaveSignatureRequest, useSavedSignature, useSignDocument, useSignSignatureRequest,
|
|
2
|
+
export { AdoptedSignature, AnnotatableState, CopyMatch, CreateFileShare, DEFAULT_FIELD_SIZE, DocumentChange, DocumentFetchError, DocumentFetchOptions, DocumentToolsNoticeKind, DocumentToolsNoticeOptions, DocumentToolsNotify, DocumentToolsProvider, DocumentToolsProviderProps, DocumentToolsUser, DocumentUploadQuery, DocumentUploadRequest, FIELD_TYPE_LABELS, FileShare, FrozenCopySource, INFORMAL_SIGNATURE_NOTE, KeypairSource, LEGACY_LAYER_PREFIX, LegacyPrompt, MARK_FIELD_TYPES, MAX_MERGE_ATTEMPTS, MarkupDocument, MarkupDownloadError, MarkupSnapshot, MarkupStore, MarkupStoreError, MarkupStoreOptions, NamedSigner, OlderMarkupNote, ResolvedDocumentToolsEnvironment, SIGNATURE_FIELD_TYPES, SIGNED_LOCKED_REASON, SIGNED_UNCHANGED, SIGNER_PROGRESS_LABELS, SaveSignatureRequestVars, SavedSignature, SignDocumentResponse, SignDocumentVars, SignRequestSignResponse, SignRequestVars, SignatureAppearance, SignatureField, SignatureFieldSuggestions, SignatureFieldType, SignatureRecord, SignatureRequest, SignatureRequestSigner, SignatureStatusResponse, SignatureVerification, SignatureVerificationError, SignerCandidate, SignerDetails, SignerProgress, SigningError, SigningErrorReason, SuggestedSignatureField, UseDocumentBytesOptions, VERIFY_PATH, VerifiedSignature, VersionInfo, addToMarkup, canAnnotate, certificateLink, clientUpload, contentDispositionFileName, copyOpenThreads, createFileShare, createMarkupStore, currentHasMarkup, defaultCertificateUrl, deleteSavedSignature, downloadBlob, fetchDocumentFile, fetchDocumentPdf, fetchDocumentSignatureRequests, fetchDocumentSignatures, fetchMarkupPdf, fetchSavedSignature, fetchSignatureVerification, fieldsFromSuggestions, fieldsInSigningOrder, fileShareBytes, fileShareSigningRequest, forgetLegacyLayer, frozenCopyName, getFileShare, initialsOf, intentText, inviteSigners, isEmailSigner, isLegibleSignatureBox, isSignatureReference, isSignedVersion, marksByVersion, matchSignedCopy, migrateLegacyLayer, newFieldId, openThreadsOf, pngBytes, pngSize, readLegacyLayer, redactionLogName, saveSignatureRequest, sendBlocker, sha256Hex, signDocument, signFileShare, signSignatureRequest, signatureFieldSuggestions, splitSuggestions, storeSavedSignature, suggestSignatureFields, toAppearance, uploadFrozenCopy, uploadQueryString, useDeclineSignatureRequest, useDeleteSavedSignature, useDocumentBytes, useDocumentMarkup, useDocumentSignatureRequests, useDocumentSignatures, useDocumentTools, useFileShare, useFileSharePdf, useFileShares, useInviteSigners, useIsOnline, useOptionalDocumentTools, useSaveSignatureRequest, useSavedSignature, useSignDocument, useSignSignatureRequest, useSignatureVerification, useSignerCandidates, useStoreSavedSignature, useVoidSignatureRequest, versionsWithMarkup } from './core.cjs';
|
|
3
3
|
import { components } from '@arbidocs/client';
|
|
4
4
|
import { P as ProductionChoices } from '../ProductionDialog.d-CpzslFn0.cjs';
|
|
5
5
|
import { a as BundleFile, b as BundleIndexEntry } from '../bundle.d-BnCSbHy2.cjs';
|
|
6
|
-
export { D as DocumentBytesKind, f as documentBytesKey } from '../query-keys.d-
|
|
6
|
+
export { D as DocumentBytesKind, f as documentBytesKey } from '../query-keys.d-D6SAUl7S.cjs';
|
|
7
7
|
import 'react';
|
|
8
8
|
import '../store.d-GADDvC7w.cjs';
|
|
9
9
|
import '../model.d-CNtRWKVK.cjs';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DocumentToolsClient, DocumentToolsEnvironment } from './core.js';
|
|
2
|
-
export { AdoptedSignature, AnnotatableState, CopyMatch, CreateFileShare, DEFAULT_FIELD_SIZE, DocumentChange, DocumentFetchError, DocumentFetchOptions, DocumentToolsNoticeKind, DocumentToolsNoticeOptions, DocumentToolsNotify, DocumentToolsProvider, DocumentToolsProviderProps, DocumentToolsUser, DocumentUploadQuery, DocumentUploadRequest, FIELD_TYPE_LABELS, FileShare, FrozenCopySource, INFORMAL_SIGNATURE_NOTE, KeypairSource, LEGACY_LAYER_PREFIX, LegacyPrompt, MARK_FIELD_TYPES, MAX_MERGE_ATTEMPTS, MarkupDocument, MarkupDownloadError, MarkupSnapshot, MarkupStore, MarkupStoreError, MarkupStoreOptions, NamedSigner, OlderMarkupNote, ResolvedDocumentToolsEnvironment, SIGNATURE_FIELD_TYPES, SIGNED_LOCKED_REASON, SIGNED_UNCHANGED, SIGNER_PROGRESS_LABELS, SaveSignatureRequestVars, SavedSignature, SignDocumentResponse, SignDocumentVars, SignRequestSignResponse, SignRequestVars, SignatureAppearance, SignatureField, SignatureFieldSuggestions, SignatureFieldType, SignatureRecord, SignatureRequest, SignatureRequestSigner, SignatureStatusResponse, SignatureVerification, SignatureVerificationError, SignerCandidate, SignerDetails, SignerProgress, SigningError, SigningErrorReason, SuggestedSignatureField, UseDocumentBytesOptions, VERIFY_PATH, VerifiedSignature, VersionInfo, addToMarkup, canAnnotate, certificateLink, clientUpload, contentDispositionFileName, copyOpenThreads, createFileShare, createMarkupStore, currentHasMarkup, defaultCertificateUrl, deleteSavedSignature, downloadBlob, fetchDocumentFile, fetchDocumentPdf, fetchDocumentSignatureRequests, fetchDocumentSignatures, fetchMarkupPdf, fetchSavedSignature, fetchSignatureVerification, fieldsFromSuggestions, fieldsInSigningOrder, fileShareBytes, fileShareSigningRequest, forgetLegacyLayer, frozenCopyName, getFileShare, initialsOf, intentText, inviteSigners, isEmailSigner, isLegibleSignatureBox, isSignatureReference, isSignedVersion, marksByVersion, matchSignedCopy, migrateLegacyLayer, newFieldId, openThreadsOf, pngBytes, pngSize, readLegacyLayer, redactionLogName, saveSignatureRequest, sendBlocker, sha256Hex, signDocument, signFileShare, signSignatureRequest, signatureFieldSuggestions, splitSuggestions, storeSavedSignature, suggestSignatureFields, toAppearance, uploadFrozenCopy, uploadQueryString, useDeclineSignatureRequest, useDeleteSavedSignature, useDocumentBytes, useDocumentMarkup, useDocumentSignatureRequests, useDocumentSignatures, useDocumentTools, useFileShare, useFileSharePdf, useFileShares, useInviteSigners, useIsOnline, useOptionalDocumentTools, useSaveSignatureRequest, useSavedSignature, useSignDocument, useSignSignatureRequest,
|
|
2
|
+
export { AdoptedSignature, AnnotatableState, CopyMatch, CreateFileShare, DEFAULT_FIELD_SIZE, DocumentChange, DocumentFetchError, DocumentFetchOptions, DocumentToolsNoticeKind, DocumentToolsNoticeOptions, DocumentToolsNotify, DocumentToolsProvider, DocumentToolsProviderProps, DocumentToolsUser, DocumentUploadQuery, DocumentUploadRequest, FIELD_TYPE_LABELS, FileShare, FrozenCopySource, INFORMAL_SIGNATURE_NOTE, KeypairSource, LEGACY_LAYER_PREFIX, LegacyPrompt, MARK_FIELD_TYPES, MAX_MERGE_ATTEMPTS, MarkupDocument, MarkupDownloadError, MarkupSnapshot, MarkupStore, MarkupStoreError, MarkupStoreOptions, NamedSigner, OlderMarkupNote, ResolvedDocumentToolsEnvironment, SIGNATURE_FIELD_TYPES, SIGNED_LOCKED_REASON, SIGNED_UNCHANGED, SIGNER_PROGRESS_LABELS, SaveSignatureRequestVars, SavedSignature, SignDocumentResponse, SignDocumentVars, SignRequestSignResponse, SignRequestVars, SignatureAppearance, SignatureField, SignatureFieldSuggestions, SignatureFieldType, SignatureRecord, SignatureRequest, SignatureRequestSigner, SignatureStatusResponse, SignatureVerification, SignatureVerificationError, SignerCandidate, SignerDetails, SignerProgress, SigningError, SigningErrorReason, SuggestedSignatureField, UseDocumentBytesOptions, VERIFY_PATH, VerifiedSignature, VersionInfo, addToMarkup, canAnnotate, certificateLink, clientUpload, contentDispositionFileName, copyOpenThreads, createFileShare, createMarkupStore, currentHasMarkup, defaultCertificateUrl, deleteSavedSignature, downloadBlob, fetchDocumentFile, fetchDocumentPdf, fetchDocumentSignatureRequests, fetchDocumentSignatures, fetchMarkupPdf, fetchSavedSignature, fetchSignatureVerification, fieldsFromSuggestions, fieldsInSigningOrder, fileShareBytes, fileShareSigningRequest, forgetLegacyLayer, frozenCopyName, getFileShare, initialsOf, intentText, inviteSigners, isEmailSigner, isLegibleSignatureBox, isSignatureReference, isSignedVersion, marksByVersion, matchSignedCopy, migrateLegacyLayer, newFieldId, openThreadsOf, pngBytes, pngSize, readLegacyLayer, redactionLogName, saveSignatureRequest, sendBlocker, sha256Hex, signDocument, signFileShare, signSignatureRequest, signatureFieldSuggestions, splitSuggestions, storeSavedSignature, suggestSignatureFields, toAppearance, uploadFrozenCopy, uploadQueryString, useDeclineSignatureRequest, useDeleteSavedSignature, useDocumentBytes, useDocumentMarkup, useDocumentSignatureRequests, useDocumentSignatures, useDocumentTools, useFileShare, useFileSharePdf, useFileShares, useInviteSigners, useIsOnline, useOptionalDocumentTools, useSaveSignatureRequest, useSavedSignature, useSignDocument, useSignSignatureRequest, useSignatureVerification, useSignerCandidates, useStoreSavedSignature, useVoidSignatureRequest, versionsWithMarkup } from './core.js';
|
|
3
3
|
import { components } from '@arbidocs/client';
|
|
4
4
|
import { P as ProductionChoices } from '../ProductionDialog.d-CpzslFn0.js';
|
|
5
5
|
import { a as BundleFile, b as BundleIndexEntry } from '../bundle.d-BnCSbHy2.js';
|
|
6
|
-
export { D as DocumentBytesKind, f as documentBytesKey } from '../query-keys.d-
|
|
6
|
+
export { D as DocumentBytesKind, f as documentBytesKey } from '../query-keys.d-D6SAUl7S.js';
|
|
7
7
|
import 'react';
|
|
8
8
|
import '../store.d-DkFXbWDk.js';
|
|
9
9
|
import '../model.d-CNtRWKVK.js';
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
export { DEFAULT_FIELD_SIZE, FIELD_TYPE_LABELS, INFORMAL_SIGNATURE_NOTE, LEGACY_LAYER_PREFIX, MARK_FIELD_TYPES, MAX_MERGE_ATTEMPTS, MarkupStoreError, SIGNATURE_FIELD_TYPES, SIGNED_UNCHANGED, SIGNER_PROGRESS_LABELS, SignatureVerificationError, SigningError, VERIFY_PATH, addToMarkup, canAnnotate, copyOpenThreads, createFileShare, createMarkupStore, deleteSavedSignature, fetchDocumentSignatureRequests, fetchDocumentSignatures, fetchSavedSignature, fetchSignatureVerification, fieldsFromSuggestions, fieldsInSigningOrder, fileShareBytes, fileShareSigningRequest, forgetLegacyLayer, frozenCopyName, getFileShare, initialsOf, intentText, inviteSigners, isEmailSigner, isLegibleSignatureBox, isSignatureReference, marksByVersion, matchSignedCopy, migrateLegacyLayer, newFieldId, openThreadsOf, pngBytes, pngSize, readLegacyLayer, redactionLogName, saveSignatureRequest, sendBlocker, sha256Hex, signDocument, signFileShare, signSignatureRequest, signatureFieldSuggestions, splitSuggestions, storeSavedSignature, suggestSignatureFields, toAppearance, uploadFrozenCopy, useDeclineSignatureRequest, useDeleteSavedSignature, useDocumentBytes, useDocumentMarkup, useDocumentSignatureRequests, useDocumentSignatures, useFileShare, useFileSharePdf, useFileShares, useInviteSigners, useIsOnline, useSaveSignatureRequest, useSavedSignature, useSignDocument, useSignSignatureRequest,
|
|
2
|
-
import { fetchDocumentFile, fetchDocumentPdf, DocumentFetchError } from '../chunk-
|
|
3
|
-
export { DocumentFetchError, DocumentToolsProvider, MarkupDownloadError, SIGNED_LOCKED_REASON, certificateLink, clientUpload, contentDispositionFileName, currentHasMarkup, defaultCertificateUrl, downloadBlob, fetchDocumentFile, fetchDocumentPdf, fetchMarkupPdf, isSignedVersion, uploadQueryString, useDocumentTools, useOptionalDocumentTools } from '../chunk-
|
|
1
|
+
export { DEFAULT_FIELD_SIZE, FIELD_TYPE_LABELS, INFORMAL_SIGNATURE_NOTE, LEGACY_LAYER_PREFIX, MARK_FIELD_TYPES, MAX_MERGE_ATTEMPTS, MarkupStoreError, SIGNATURE_FIELD_TYPES, SIGNED_UNCHANGED, SIGNER_PROGRESS_LABELS, SignatureVerificationError, SigningError, VERIFY_PATH, addToMarkup, canAnnotate, copyOpenThreads, createFileShare, createMarkupStore, deleteSavedSignature, fetchDocumentSignatureRequests, fetchDocumentSignatures, fetchSavedSignature, fetchSignatureVerification, fieldsFromSuggestions, fieldsInSigningOrder, fileShareBytes, fileShareSigningRequest, forgetLegacyLayer, frozenCopyName, getFileShare, initialsOf, intentText, inviteSigners, isEmailSigner, isLegibleSignatureBox, isSignatureReference, marksByVersion, matchSignedCopy, migrateLegacyLayer, newFieldId, openThreadsOf, pngBytes, pngSize, readLegacyLayer, redactionLogName, saveSignatureRequest, sendBlocker, sha256Hex, signDocument, signFileShare, signSignatureRequest, signatureFieldSuggestions, splitSuggestions, storeSavedSignature, suggestSignatureFields, toAppearance, uploadFrozenCopy, useDeclineSignatureRequest, useDeleteSavedSignature, useDocumentBytes, useDocumentMarkup, useDocumentSignatureRequests, useDocumentSignatures, useFileShare, useFileSharePdf, useFileShares, useInviteSigners, useIsOnline, useSaveSignatureRequest, useSavedSignature, useSignDocument, useSignSignatureRequest, useSignatureVerification, useSignerCandidates, useStoreSavedSignature, useVoidSignatureRequest, versionsWithMarkup } from '../chunk-DU2P354H.js';
|
|
2
|
+
import { fetchDocumentFile, fetchDocumentPdf, DocumentFetchError } from '../chunk-YQBDEOVE.js';
|
|
3
|
+
export { DocumentFetchError, DocumentToolsProvider, MarkupDownloadError, SIGNED_LOCKED_REASON, certificateLink, clientUpload, contentDispositionFileName, currentHasMarkup, defaultCertificateUrl, downloadBlob, fetchDocumentFile, fetchDocumentPdf, fetchMarkupPdf, isSignedVersion, uploadQueryString, useDocumentTools, useOptionalDocumentTools } from '../chunk-YQBDEOVE.js';
|
|
4
4
|
import '../chunk-T4CLW3DN.js';
|
|
5
5
|
import '../chunk-T3USOSVN.js';
|
|
6
|
-
export { documentBytesKey } from '../chunk-
|
|
7
|
-
import '../chunk-
|
|
8
|
-
import '../chunk-NNWMHMEC.js';
|
|
6
|
+
export { documentBytesKey } from '../chunk-BFNY3RZG.js';
|
|
7
|
+
import '../chunk-UW2SGTI5.js';
|
|
9
8
|
import '../chunk-WUTL62MC.js';
|
|
10
9
|
import '../chunk-YNNAJJ5Z.js';
|
|
11
10
|
import '../chunk-47CCGUWR.js';
|
|
12
|
-
import '../chunk-
|
|
13
|
-
import '../chunk-CPZ36AQS.js';
|
|
11
|
+
import '../chunk-VSCU7K4V.js';
|
|
14
12
|
import '../chunk-SN5YV6FF.js';
|
|
15
13
|
|
|
16
14
|
// src/document-tools/production.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/document-tools/production.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Production sets: number the selected documents with Bates labels (optionally a QR code back to\n * each document and an index page) and save the result back to the workspace. The dialog is\n * `ProductionSetDialog` in `@arbidocs/blocks/document-tools`; this is its data side.\n *\n * A PDF is numbered as stored (`/download`). Any other document is numbered through its PDF\n * rendition (`/view`, what the viewer shows for a Word or text file); one without a rendition is\n * left out. Saved results are new documents derived from their sources (role `production`) in a\n * Productions folder, shared with the workspace only if every source is. The originals never\n * change.\n *\n * pdf-lib (the numbering) is loaded only when a production is built, so importing this module\n * stays as light as the rest of the document tools.\n */\n\nimport type { components } from '@arbidocs/client'\nimport type { ProductionChoices } from '../annotations/ProductionDialog'\nimport type { BundleFile, BundleIndexEntry, BundleItem } from '../annotations/freeze/bundle'\nimport { DocumentFetchError, fetchDocumentFile, fetchDocumentPdf } from './document-pdf'\nimport type {\n DocumentToolsClient,\n DocumentToolsEnvironment,\n DocumentUploadQuery,\n} from './environment'\n\n/** The fields of a document record (`DocResponse`) a production uses. */\nexport type ProductionSource = Pick<\n components['schemas']['DocResponse'],\n 'external_id' | 'file_name' | 'file_type' | 'shared'\n> & {\n doc_metadata?: { title?: string | null } | null\n /** The document's workspace: the produced files are saved there, named on the upload. */\n workspace_ext_id?: string | null\n}\n\nexport const PRODUCTIONS_FOLDER = 'Productions'\n\nconst extensionOf = (fileName: string | null | undefined) => {\n const name = (fileName ?? '').toLowerCase()\n const dot = name.lastIndexOf('.')\n return dot < 0 ? '' : name.slice(dot + 1)\n}\n\n/** Media, archives and design files: no PDF version to number. */\nconst NO_RENDITION_EXTENSIONS = new Set(\n [\n // images\n 'jpg jpeg png gif bmp tiff tif webp heic',\n // video and audio\n 'mp4 mpeg mpg webm mov avi mkv mp3 wav m4a aac ogg flac',\n // archives, binaries, design files\n 'zip rar 7z tar gz exe bin dmg iso apk msi dll so psd ai sketch',\n ]\n .join(' ')\n .split(' ')\n)\n\nexport const isPdfDocument = (doc: ProductionSource) =>\n /pdf/i.test(doc.file_type ?? '') || extensionOf(doc.file_name) === 'pdf'\n\n/** True for a document with no PDF version to number (media, archives and the like). */\nexport const hasNoRendition = (doc: ProductionSource) =>\n !isPdfDocument(doc) && NO_RENDITION_EXTENSIONS.has(extensionOf(doc.file_name))\n\n/** The name a document goes by in the dialog and the index: its title, else its file name. */\nexport const productionDocumentName = (doc: ProductionSource) =>\n doc.doc_metadata?.title || doc.file_name || doc.external_id\n\nconst isPdfBytes = (bytes: Uint8Array) =>\n bytes.length > 4 && String.fromCharCode(...bytes.subarray(0, 5)) === '%PDF-'\n\n/**\n * The PDF to number for `doc`: the file itself, or the PDF version of anything else. `null` when a\n * non-PDF has no PDF version (yet), so it is left out; a PDF that cannot be downloaded throws.\n */\nexport async function fetchProductionPdf(\n client: DocumentToolsClient,\n doc: ProductionSource\n): Promise<Uint8Array | null> {\n const pdf = isPdfDocument(doc)\n let blob: Blob\n try {\n blob = await (pdf ? fetchDocumentFile : fetchDocumentPdf)(client, doc.external_id)\n } catch (e) {\n if (!pdf && e instanceof DocumentFetchError) return null\n throw e\n }\n const bytes = new Uint8Array(await blob.arrayBuffer())\n return pdf || isPdfBytes(bytes) ? bytes : null\n}\n\nconst safeName = (name: string) => name.replace(/[\\\\/:*?\"<>|]+/g, '_').trim()\n\n/** \"Production ACME-000001-ACME-000042\": names the files and folder of one production. */\nexport function productionTitle(firstLabel: string, lastLabel: string): string {\n return safeName(`Production ${firstLabel}-${lastLabel}`)\n}\n\n/** Where a production is saved: the Productions folder, or a folder of its own per document. */\nexport function productionFolder(title: string, merged: boolean): string {\n return merged ? PRODUCTIONS_FOLDER : `${PRODUCTIONS_FOLDER}/${title}`\n}\n\n/** In the workspace a per-document file says which range it holds, beside its original. */\nexport function productionFileName(file: BundleFile, title: string): string {\n if (!file.firstLabel) return `${title} index.pdf`\n return `${file.name.replace(/\\.pdf$/i, '')} (${file.firstLabel}-${file.lastLabel}).pdf`\n}\n\nconst csvCell = (value: string | number) => `\"${String(value).replace(/\"/g, '\"\"')}\"`\n\n/** The `index.csv` of a per-document production: every document with its file and range. */\nexport function productionIndexCsv(index: readonly BundleIndexEntry[]): string {\n const rows = index.map((e) =>\n [e.documentId, e.name, e.file, e.pages, e.firstLabel, e.lastLabel].map(csvCell).join(',')\n )\n return ['document_id,name,file,pages,first_label,last_label', ...rows].join('\\n')\n}\n\nexport interface ProductionUpload {\n name: string\n bytes: Uint8Array\n /** The documents this file was made from. */\n sources: ProductionSource[]\n}\n\n/** Save each file as a new workspace document derived from its sources; returns the new ids. */\nexport async function saveProductionFiles(\n upload: NonNullable<DocumentToolsEnvironment['uploadDocument']>,\n files: readonly ProductionUpload[],\n folder: string\n): Promise<string[]> {\n const ids: string[] = []\n for (const file of files) {\n const query: DocumentUploadQuery = {\n derived_from: file.sources.map((doc) => doc.external_id),\n derived_role: 'production',\n shared: file.sources.every((doc) => doc.shared),\n folder,\n }\n // Saved in the sources' workspace, named on the upload (never whichever one is open now).\n const workspaces = new Set(file.sources.map((doc) => doc.workspace_ext_id).filter(Boolean))\n if (workspaces.size === 1) query.workspace_ext_id = [...workspaces][0]\n const response = await upload({\n file: new File([file.bytes as BlobPart], file.name, { type: 'application/pdf' }),\n query,\n })\n ids.push(...(response?.doc_ext_ids ?? []))\n }\n return ids\n}\n\nexport interface BuildProductionOptions {\n /** The link a document's QR code opens (the document in the host app). */\n documentUrl: (documentId: string) => string\n /** Who produced the set; recorded in a merged file's metadata. */\n author?: string\n onProgress?: (done: number, total: number) => void\n}\n\nexport interface BuiltProduction {\n title: string\n merged: boolean\n /** The numbered files: one merged PDF (named after its range), or one per document (+ index). */\n files: BundleFile[]\n index: BundleIndexEntry[]\n /** The documents numbered, in order. */\n included: ProductionSource[]\n /** Documents left out because they have no PDF version yet. */\n noRendition: ProductionSource[]\n /** The files as they are saved to the workspace, each with the documents it was made from. */\n uploads: ProductionUpload[]\n folder: string\n}\n\n/**\n * Fetch each document's PDF (in `choices.order`) and number the set. Throws when none of the\n * documents has a PDF version, or when a PDF cannot be fetched.\n */\nexport async function buildProduction(\n client: DocumentToolsClient,\n documents: readonly ProductionSource[],\n choices: ProductionChoices,\n options: BuildProductionOptions\n): Promise<BuiltProduction> {\n const byId = new Map(documents.map((doc) => [doc.external_id, doc]))\n const included: ProductionSource[] = []\n const noRendition: ProductionSource[] = []\n const items: BundleItem[] = []\n for (const doc of choices.order.flatMap((id) => byId.get(id) ?? [])) {\n const bytes = await fetchProductionPdf(client, doc)\n if (!bytes) {\n noRendition.push(doc)\n continue\n }\n included.push(doc)\n items.push({\n name: productionDocumentName(doc),\n documentId: doc.external_id,\n bytes,\n qrUrl: options.documentUrl(doc.external_id),\n })\n }\n if (items.length === 0) {\n throw new Error('None of these documents has a PDF version to number yet.')\n }\n\n const { buildBundle } = await import('../annotations/freeze/bundle')\n const result = await buildBundle(items, {\n layout: choices.layout,\n bates: {\n prefix: choices.prefix,\n start: choices.start,\n digits: choices.digits,\n corner: choices.corner,\n },\n qr: choices.qr,\n // The QR code sits in the bottom corner the label is not in.\n qrCorner: choices.corner.endsWith('left') ? 'bottom-right' : 'bottom-left',\n indexPage: choices.indexPage,\n author: options.author,\n onProgress: options.onProgress,\n })\n\n const title = productionTitle(\n result.index[0].firstLabel,\n result.index[result.index.length - 1].lastLabel\n )\n const merged = choices.layout === 'merged'\n // A merged file is named after its range; per-document files keep their document names.\n const files = merged ? [{ ...result.files[0], name: `${title}.pdf` }] : result.files\n const sourceOf = new Map(result.index.map((e) => [e.file, byId.get(e.documentId)!]))\n const uploads = files.map((file) => ({\n name: merged ? file.name : productionFileName(file, title),\n bytes: file.bytes,\n // The merged file (and a separate index) is made from every document; each per-document\n // file from its own.\n sources: merged || !sourceOf.has(file.name) ? included : [sourceOf.get(file.name)!],\n }))\n return {\n title,\n merged,\n files,\n index: result.index,\n included,\n noRendition,\n uploads,\n folder: productionFolder(title, merged),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/document-tools/production.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Production sets: number the selected documents with Bates labels (optionally a QR code back to\n * each document and an index page) and save the result back to the workspace. The dialog is\n * `ProductionSetDialog` in `@arbidocs/blocks/document-tools`; this is its data side.\n *\n * A PDF is numbered as stored (`/download`). Any other document is numbered through its PDF\n * rendition (`/view`, what the viewer shows for a Word or text file); one without a rendition is\n * left out. Saved results are new documents derived from their sources (role `production`) in a\n * Productions folder, shared with the workspace only if every source is. The originals never\n * change.\n *\n * pdf-lib (the numbering) is loaded only when a production is built, so importing this module\n * stays as light as the rest of the document tools.\n */\n\nimport type { components } from '@arbidocs/client'\nimport type { ProductionChoices } from '../annotations/ProductionDialog'\nimport type { BundleFile, BundleIndexEntry, BundleItem } from '../annotations/freeze/bundle'\nimport { DocumentFetchError, fetchDocumentFile, fetchDocumentPdf } from './document-pdf'\nimport type {\n DocumentToolsClient,\n DocumentToolsEnvironment,\n DocumentUploadQuery,\n} from './environment'\n\n/** The fields of a document record (`DocResponse`) a production uses. */\nexport type ProductionSource = Pick<\n components['schemas']['DocResponse'],\n 'external_id' | 'file_name' | 'file_type' | 'shared'\n> & {\n doc_metadata?: { title?: string | null } | null\n /** The document's workspace: the produced files are saved there, named on the upload. */\n workspace_ext_id?: string | null\n}\n\nexport const PRODUCTIONS_FOLDER = 'Productions'\n\nconst extensionOf = (fileName: string | null | undefined) => {\n const name = (fileName ?? '').toLowerCase()\n const dot = name.lastIndexOf('.')\n return dot < 0 ? '' : name.slice(dot + 1)\n}\n\n/** Media, archives and design files: no PDF version to number. */\nconst NO_RENDITION_EXTENSIONS = new Set(\n [\n // images\n 'jpg jpeg png gif bmp tiff tif webp heic',\n // video and audio\n 'mp4 mpeg mpg webm mov avi mkv mp3 wav m4a aac ogg flac',\n // archives, binaries, design files\n 'zip rar 7z tar gz exe bin dmg iso apk msi dll so psd ai sketch',\n ]\n .join(' ')\n .split(' ')\n)\n\nexport const isPdfDocument = (doc: ProductionSource) =>\n /pdf/i.test(doc.file_type ?? '') || extensionOf(doc.file_name) === 'pdf'\n\n/** True for a document with no PDF version to number (media, archives and the like). */\nexport const hasNoRendition = (doc: ProductionSource) =>\n !isPdfDocument(doc) && NO_RENDITION_EXTENSIONS.has(extensionOf(doc.file_name))\n\n/** The name a document goes by in the dialog and the index: its title, else its file name. */\nexport const productionDocumentName = (doc: ProductionSource) =>\n doc.doc_metadata?.title || doc.file_name || doc.external_id\n\nconst isPdfBytes = (bytes: Uint8Array) =>\n bytes.length > 4 && String.fromCharCode(...bytes.subarray(0, 5)) === '%PDF-'\n\n/**\n * The PDF to number for `doc`: the file itself, or the PDF version of anything else. `null` when a\n * non-PDF has no PDF version (yet), so it is left out; a PDF that cannot be downloaded throws.\n */\nexport async function fetchProductionPdf(\n client: DocumentToolsClient,\n doc: ProductionSource\n): Promise<Uint8Array | null> {\n const pdf = isPdfDocument(doc)\n let blob: Blob\n try {\n blob = await (pdf ? fetchDocumentFile : fetchDocumentPdf)(client, doc.external_id)\n } catch (e) {\n if (!pdf && e instanceof DocumentFetchError) return null\n throw e\n }\n const bytes = new Uint8Array(await blob.arrayBuffer())\n return pdf || isPdfBytes(bytes) ? bytes : null\n}\n\nconst safeName = (name: string) => name.replace(/[\\\\/:*?\"<>|]+/g, '_').trim()\n\n/** \"Production ACME-000001-ACME-000042\": names the files and folder of one production. */\nexport function productionTitle(firstLabel: string, lastLabel: string): string {\n return safeName(`Production ${firstLabel}-${lastLabel}`)\n}\n\n/** Where a production is saved: the Productions folder, or a folder of its own per document. */\nexport function productionFolder(title: string, merged: boolean): string {\n return merged ? PRODUCTIONS_FOLDER : `${PRODUCTIONS_FOLDER}/${title}`\n}\n\n/** In the workspace a per-document file says which range it holds, beside its original. */\nexport function productionFileName(file: BundleFile, title: string): string {\n if (!file.firstLabel) return `${title} index.pdf`\n return `${file.name.replace(/\\.pdf$/i, '')} (${file.firstLabel}-${file.lastLabel}).pdf`\n}\n\nconst csvCell = (value: string | number) => `\"${String(value).replace(/\"/g, '\"\"')}\"`\n\n/** The `index.csv` of a per-document production: every document with its file and range. */\nexport function productionIndexCsv(index: readonly BundleIndexEntry[]): string {\n const rows = index.map((e) =>\n [e.documentId, e.name, e.file, e.pages, e.firstLabel, e.lastLabel].map(csvCell).join(',')\n )\n return ['document_id,name,file,pages,first_label,last_label', ...rows].join('\\n')\n}\n\nexport interface ProductionUpload {\n name: string\n bytes: Uint8Array\n /** The documents this file was made from. */\n sources: ProductionSource[]\n}\n\n/** Save each file as a new workspace document derived from its sources; returns the new ids. */\nexport async function saveProductionFiles(\n upload: NonNullable<DocumentToolsEnvironment['uploadDocument']>,\n files: readonly ProductionUpload[],\n folder: string\n): Promise<string[]> {\n const ids: string[] = []\n for (const file of files) {\n const query: DocumentUploadQuery = {\n derived_from: file.sources.map((doc) => doc.external_id),\n derived_role: 'production',\n shared: file.sources.every((doc) => doc.shared),\n folder,\n }\n // Saved in the sources' workspace, named on the upload (never whichever one is open now).\n const workspaces = new Set(file.sources.map((doc) => doc.workspace_ext_id).filter(Boolean))\n if (workspaces.size === 1) query.workspace_ext_id = [...workspaces][0]\n const response = await upload({\n file: new File([file.bytes as BlobPart], file.name, { type: 'application/pdf' }),\n query,\n })\n ids.push(...(response?.doc_ext_ids ?? []))\n }\n return ids\n}\n\nexport interface BuildProductionOptions {\n /** The link a document's QR code opens (the document in the host app). */\n documentUrl: (documentId: string) => string\n /** Who produced the set; recorded in a merged file's metadata. */\n author?: string\n onProgress?: (done: number, total: number) => void\n}\n\nexport interface BuiltProduction {\n title: string\n merged: boolean\n /** The numbered files: one merged PDF (named after its range), or one per document (+ index). */\n files: BundleFile[]\n index: BundleIndexEntry[]\n /** The documents numbered, in order. */\n included: ProductionSource[]\n /** Documents left out because they have no PDF version yet. */\n noRendition: ProductionSource[]\n /** The files as they are saved to the workspace, each with the documents it was made from. */\n uploads: ProductionUpload[]\n folder: string\n}\n\n/**\n * Fetch each document's PDF (in `choices.order`) and number the set. Throws when none of the\n * documents has a PDF version, or when a PDF cannot be fetched.\n */\nexport async function buildProduction(\n client: DocumentToolsClient,\n documents: readonly ProductionSource[],\n choices: ProductionChoices,\n options: BuildProductionOptions\n): Promise<BuiltProduction> {\n const byId = new Map(documents.map((doc) => [doc.external_id, doc]))\n const included: ProductionSource[] = []\n const noRendition: ProductionSource[] = []\n const items: BundleItem[] = []\n for (const doc of choices.order.flatMap((id) => byId.get(id) ?? [])) {\n const bytes = await fetchProductionPdf(client, doc)\n if (!bytes) {\n noRendition.push(doc)\n continue\n }\n included.push(doc)\n items.push({\n name: productionDocumentName(doc),\n documentId: doc.external_id,\n bytes,\n qrUrl: options.documentUrl(doc.external_id),\n })\n }\n if (items.length === 0) {\n throw new Error('None of these documents has a PDF version to number yet.')\n }\n\n const { buildBundle } = await import('../annotations/freeze/bundle')\n const result = await buildBundle(items, {\n layout: choices.layout,\n bates: {\n prefix: choices.prefix,\n start: choices.start,\n digits: choices.digits,\n corner: choices.corner,\n },\n qr: choices.qr,\n // The QR code sits in the bottom corner the label is not in.\n qrCorner: choices.corner.endsWith('left') ? 'bottom-right' : 'bottom-left',\n indexPage: choices.indexPage,\n author: options.author,\n onProgress: options.onProgress,\n })\n\n const title = productionTitle(\n result.index[0].firstLabel,\n result.index[result.index.length - 1].lastLabel\n )\n const merged = choices.layout === 'merged'\n // A merged file is named after its range; per-document files keep their document names.\n const files = merged ? [{ ...result.files[0], name: `${title}.pdf` }] : result.files\n const sourceOf = new Map(result.index.map((e) => [e.file, byId.get(e.documentId)!]))\n const uploads = files.map((file) => ({\n name: merged ? file.name : productionFileName(file, title),\n bytes: file.bytes,\n // The merged file (and a separate index) is made from every document; each per-document\n // file from its own.\n sources: merged || !sourceOf.has(file.name) ? included : [sourceOf.get(file.name)!],\n }))\n return {\n title,\n merged,\n files,\n index: result.index,\n included,\n noRendition,\n uploads,\n folder: productionFolder(title, merged),\n }\n}\n"]}
|