@embedpdf/engine-core 3.0.0-next.14 → 3.0.0-next.15
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/dist/AnnotationList-CkijRHet.d.cts +27163 -0
- package/dist/AnnotationList-CkijRHet.d.ts +27163 -0
- package/dist/Change-CKoxfTNY.js +889 -0
- package/dist/Change-CKoxfTNY.js.map +1 -0
- package/dist/Change-CjImsrN0.cjs +1020 -0
- package/dist/Change-CjImsrN0.cjs.map +1 -0
- package/dist/DocumentRenderService-BfFdFSwI.cjs +120 -0
- package/dist/DocumentRenderService-BfFdFSwI.cjs.map +1 -0
- package/dist/DocumentRenderService-DV3J9lMz.js +85 -0
- package/dist/DocumentRenderService-DV3J9lMz.js.map +1 -0
- package/dist/{DocumentSecurityService-Ca6EK3-3.d.ts → DocumentSecurityService-CU1M6Q7m.d.ts} +100 -112
- package/dist/{DocumentSecurityService-CIx1MT0T.d.cts → DocumentSecurityService-e6vp2de8.d.cts} +100 -112
- package/dist/LocalDocumentHandle-D02FMm-Z.cjs +53 -0
- package/dist/LocalDocumentHandle-D02FMm-Z.cjs.map +1 -0
- package/dist/LocalDocumentHandle-DAPdaOt_.js +30 -0
- package/dist/LocalDocumentHandle-DAPdaOt_.js.map +1 -0
- package/dist/LocalEngine-DFoBm4B3.d.cts +1565 -0
- package/dist/LocalEngine-DPriFujS.d.ts +1565 -0
- package/dist/PageInsertBlankInput-CXHAM7l6.cjs +17 -0
- package/dist/PageInsertBlankInput-CXHAM7l6.cjs.map +1 -0
- package/dist/PageInsertBlankInput-DhVYVJ_S.js +12 -0
- package/dist/PageInsertBlankInput-DhVYVJ_S.js.map +1 -0
- package/dist/authority-B3BklsB4.js +2239 -0
- package/dist/authority-B3BklsB4.js.map +1 -0
- package/dist/{viewport-BWeNHZmb.cjs → authority-DLMNR7ff.cjs} +820 -1647
- package/dist/authority-DLMNR7ff.cjs.map +1 -0
- package/dist/builders-CNj0POeY.js +161 -0
- package/dist/builders-CNj0POeY.js.map +1 -0
- package/dist/builders-Cgdp_YCn.cjs +184 -0
- package/dist/builders-Cgdp_YCn.cjs.map +1 -0
- package/dist/calibrate-7T3fnP8-.js +2404 -0
- package/dist/calibrate-7T3fnP8-.js.map +1 -0
- package/dist/calibrate-DJBXnhLE.cjs +2919 -0
- package/dist/calibrate-DJBXnhLE.cjs.map +1 -0
- package/dist/charmap-Cprti1ta.js +239 -0
- package/dist/charmap-Cprti1ta.js.map +1 -0
- package/dist/charmap-aYlefQP9.cjs +304 -0
- package/dist/charmap-aYlefQP9.cjs.map +1 -0
- package/dist/conformance.cjs +16466 -5247
- package/dist/conformance.cjs.map +1 -1
- package/dist/conformance.d.cts +924 -165
- package/dist/conformance.d.ts +924 -165
- package/dist/conformance.js +16429 -5252
- package/dist/conformance.js.map +1 -1
- package/dist/format-Bp3QFSH1.cjs +574 -0
- package/dist/format-Bp3QFSH1.cjs.map +1 -0
- package/dist/format-Dgg428Kb.js +461 -0
- package/dist/format-Dgg428Kb.js.map +1 -0
- package/dist/index.cjs +323 -116
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +14 -5
- package/dist/pageRefs-B3ur7Ckm.cjs +51 -0
- package/dist/pageRefs-B3ur7Ckm.cjs.map +1 -0
- package/dist/pageRefs-DkbuxSCV.js +40 -0
- package/dist/pageRefs-DkbuxSCV.js.map +1 -0
- package/dist/public.cjs +57 -0
- package/dist/public.d.cts +5 -0
- package/dist/public.d.ts +5 -0
- package/dist/public.js +9 -0
- package/dist/resolveAnnotationDraft-7Ke4nV7F.cjs +3646 -0
- package/dist/resolveAnnotationDraft-7Ke4nV7F.cjs.map +1 -0
- package/dist/resolveAnnotationDraft-CUpf0SMh.js +3167 -0
- package/dist/resolveAnnotationDraft-CUpf0SMh.js.map +1 -0
- package/dist/{resolver-inAVzsWt.js → resolver-CzxmD9Ck.js} +294 -144
- package/dist/resolver-CzxmD9Ck.js.map +1 -0
- package/dist/{resolver-CYVNV4hn.cjs → resolver-D2OCtE8F.cjs} +347 -143
- package/dist/resolver-D2OCtE8F.cjs.map +1 -0
- package/dist/runtime-Cl0v56mm.d.ts +2032 -0
- package/dist/runtime-p1WDzDo4.d.cts +2032 -0
- package/dist/runtime.cjs +726 -297
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +5 -1372
- package/dist/runtime.d.ts +5 -1372
- package/dist/runtime.js +396 -179
- package/dist/runtime.js.map +1 -1
- package/dist/schema-C-gU4vj7.cjs +3034 -0
- package/dist/schema-C-gU4vj7.cjs.map +1 -0
- package/dist/schema-DzlUNk38.js +2081 -0
- package/dist/schema-DzlUNk38.js.map +1 -0
- package/dist/schemas-Berf1swF.cjs +2481 -0
- package/dist/schemas-Berf1swF.cjs.map +1 -0
- package/dist/schemas-D6xOGjqg.js +1654 -0
- package/dist/schemas-D6xOGjqg.js.map +1 -0
- package/dist/subtype-CG4WpIRj.js +129 -0
- package/dist/subtype-CG4WpIRj.js.map +1 -0
- package/dist/subtype-aDt5TFmK.cjs +158 -0
- package/dist/subtype-aDt5TFmK.cjs.map +1 -0
- package/dist/validation.cjs +578 -0
- package/dist/validation.cjs.map +1 -0
- package/dist/validation.d.cts +174 -0
- package/dist/validation.d.ts +174 -0
- package/dist/validation.js +571 -0
- package/dist/validation.js.map +1 -0
- package/dist/value-BFS1R8ek.cjs +435 -0
- package/dist/value-BFS1R8ek.cjs.map +1 -0
- package/dist/value-Dhc8eYcx.js +340 -0
- package/dist/value-Dhc8eYcx.js.map +1 -0
- package/dist/viewport-BJW13EGZ.js +540 -0
- package/dist/viewport-BJW13EGZ.js.map +1 -0
- package/dist/viewport-DlL5Bxbg.cjs +671 -0
- package/dist/viewport-DlL5Bxbg.cjs.map +1 -0
- package/dist/wire.cjs +1051 -397
- package/dist/wire.cjs.map +1 -1
- package/dist/wire.d.cts +12403 -790
- package/dist/wire.d.ts +12403 -790
- package/dist/wire.js +821 -242
- package/dist/wire.js.map +1 -1
- package/package.json +10 -1
- package/dist/AbortError-DwuHPK_I.js +0 -27
- package/dist/AbortError-DwuHPK_I.js.map +0 -1
- package/dist/AbortError-P0RU0Mgg.cjs +0 -38
- package/dist/AbortError-P0RU0Mgg.cjs.map +0 -1
- package/dist/AnnotationListSnapshot-D9R5n2Kf.d.cts +0 -7101
- package/dist/AnnotationListSnapshot-D9R5n2Kf.d.ts +0 -7101
- package/dist/Engine-EWWHhEIi.d.ts +0 -1277
- package/dist/Engine-FNaAEjfb.d.cts +0 -1277
- package/dist/derive-BbsDk_Kz.cjs +0 -880
- package/dist/derive-BbsDk_Kz.cjs.map +0 -1
- package/dist/derive-DAFJolWu.js +0 -647
- package/dist/derive-DAFJolWu.js.map +0 -1
- package/dist/format-Bbphf4zR.js +0 -435
- package/dist/format-Bbphf4zR.js.map +0 -1
- package/dist/format-D_epWlob.cjs +0 -518
- package/dist/format-D_epWlob.cjs.map +0 -1
- package/dist/resolver-CYVNV4hn.cjs.map +0 -1
- package/dist/resolver-inAVzsWt.js.map +0 -1
- package/dist/schemas-CFQGvWiu.js +0 -3243
- package/dist/schemas-CFQGvWiu.js.map +0 -1
- package/dist/schemas-D0g6tKa9.cjs +0 -4694
- package/dist/schemas-D0g6tKa9.cjs.map +0 -1
- package/dist/viewport-BWeNHZmb.cjs.map +0 -1
- package/dist/viewport-CvMcadfQ.js +0 -3072
- package/dist/viewport-CvMcadfQ.js.map +0 -1
|
@@ -1,282 +1,189 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
|
|
1
|
+
const require_value = require("./value-BFS1R8ek.cjs");
|
|
2
|
+
const require_resolveAnnotationDraft = require("./resolveAnnotationDraft-7Ke4nV7F.cjs");
|
|
3
|
+
const require_format = require("./format-Bp3QFSH1.cjs");
|
|
4
|
+
const require_calibrate = require("./calibrate-DJBXnhLE.cjs");
|
|
5
|
+
const require_resolver = require("./resolver-D2OCtE8F.cjs");
|
|
6
|
+
const require_viewport = require("./viewport-DlL5Bxbg.cjs");
|
|
7
|
+
//#region src/geometry/pageBoxes.ts
|
|
8
|
+
/** The media box of a page that has none, which the file needs: US Letter. */
|
|
9
|
+
const DEFAULT_MEDIA_BOX = {
|
|
10
|
+
left: 0,
|
|
11
|
+
bottom: 0,
|
|
12
|
+
right: 612,
|
|
13
|
+
top: 792
|
|
14
|
+
};
|
|
15
|
+
/** A box that shares nothing with the media box: no size, at the origin. */
|
|
16
|
+
const EMPTY_BOX = {
|
|
17
|
+
left: 0,
|
|
18
|
+
right: 0,
|
|
19
|
+
bottom: 0,
|
|
20
|
+
top: 0
|
|
21
|
+
};
|
|
5
22
|
/**
|
|
6
|
-
* The
|
|
7
|
-
* and
|
|
23
|
+
* The page's five boxes as ISO 32000-1 §14.11.2 defines them: the crop box
|
|
24
|
+
* defaults to the media box and the other three to the crop box, and each is
|
|
25
|
+
* reduced to the part it shares with the media box. The crop box is then the
|
|
26
|
+
* visible page, what the page shows.
|
|
27
|
+
*
|
|
28
|
+
* For broken files, which the standard doesn't cover, we do what Acrobat
|
|
29
|
+
* does: a page without a media box is US Letter, and a box that shares
|
|
30
|
+
* nothing with the media box is empty, so a crop box off the page leaves a
|
|
31
|
+
* page with no size.
|
|
8
32
|
*/
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
33
|
+
function pageBoxesOf(written) {
|
|
34
|
+
const media = written.media ?? DEFAULT_MEDIA_BOX;
|
|
35
|
+
const within = (box) => require_resolveAnnotationDraft.pdfRectIntersection(box, media) ?? EMPTY_BOX;
|
|
36
|
+
const crop = within(written.crop ?? media);
|
|
12
37
|
return {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
submitCoordinates: bit(5),
|
|
19
|
-
includeAppendSaves: bit(7),
|
|
20
|
-
includeAnnotations: bit(8),
|
|
21
|
-
canonicalFormat: bit(10),
|
|
22
|
-
exclNonUserAnnots: bit(11),
|
|
23
|
-
exclFKey: bit(12),
|
|
24
|
-
embedForm: bit(14)
|
|
38
|
+
media,
|
|
39
|
+
crop,
|
|
40
|
+
bleed: within(written.bleed ?? crop),
|
|
41
|
+
trim: within(written.trim ?? crop),
|
|
42
|
+
art: within(written.art ?? crop)
|
|
25
43
|
};
|
|
26
|
-
};
|
|
27
|
-
//#endregion
|
|
28
|
-
//#region src/dto/PageRender.ts
|
|
29
|
-
function createPageImageHandle(result, blobSource) {
|
|
30
|
-
return {
|
|
31
|
-
...result,
|
|
32
|
-
async objectUrl(signal) {
|
|
33
|
-
if (typeof Blob === "undefined" || typeof URL === "undefined" || !URL.createObjectURL) throw new require_derive.EngineError(require_format.EngineErrorCode.RuntimeUnavailable, "Object URLs are not available in this environment");
|
|
34
|
-
const blob = await blobSource.blob(signal);
|
|
35
|
-
const url = URL.createObjectURL(blob);
|
|
36
|
-
return {
|
|
37
|
-
url,
|
|
38
|
-
revoke: () => URL.revokeObjectURL(url)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
//#endregion
|
|
44
|
-
//#region src/dto/PdfSaveMode.ts
|
|
45
|
-
const DEFAULT_PDF_SAVE_MODE = "incremental";
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/dto/RichText.ts
|
|
48
|
-
/** The plain-text projection of a rich document: paragraphs joined by `\r`,
|
|
49
|
-
* runs concatenated — what the engine writes to `/Contents`. */
|
|
50
|
-
function richTextPlainText(doc) {
|
|
51
|
-
return doc.paragraphs.map((p) => p.runs.map((r) => r.text).join("")).join("\r");
|
|
52
44
|
}
|
|
53
|
-
/** Plain text as rich paragraphs: one per line break, one run each, no
|
|
54
|
-
* overrides (the engine's own `/Contents` fallback shape). */
|
|
55
|
-
function richTextParagraphsFromPlainText(text) {
|
|
56
|
-
return text.split(/\r\n|\r|\n/).map((line) => ({ runs: [{ text: line }] }));
|
|
57
|
-
}
|
|
58
|
-
//#endregion
|
|
59
|
-
//#region src/identity/PageObjectNumber.ts
|
|
60
45
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
46
|
+
* A page's turn from its `/Rotate`, degrees clockwise. ISO 32000-1 Table 30
|
|
47
|
+
* allows multiples of 90; a negative one or one past 360 is the same turn.
|
|
48
|
+
* For a value that isn't a multiple of 90, which the file shouldn't hold, we
|
|
49
|
+
* do what Acrobat does: no turn.
|
|
64
50
|
*/
|
|
65
|
-
function
|
|
66
|
-
|
|
51
|
+
function pageRotationOf(written) {
|
|
52
|
+
if (!Number.isInteger(written) || written % 90 !== 0) return 0;
|
|
53
|
+
return (written % 360 + 360) % 360;
|
|
67
54
|
}
|
|
68
55
|
//#endregion
|
|
69
|
-
//#region src/
|
|
56
|
+
//#region src/dto/PageRender.ts
|
|
70
57
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* `
|
|
74
|
-
*
|
|
75
|
-
* Format:
|
|
76
|
-
* `{ kind: 'objectNumber', value: 42 }` -> `'obj:42'`
|
|
77
|
-
* `{ kind: 'nm', value: 'foo bar' }` -> `'nm:foo bar'`
|
|
78
|
-
*
|
|
79
|
-
* The caller is responsible for `encodeURIComponent`-ing the result before
|
|
80
|
-
* splicing it into a URL path; `wirePaths.layerAnnotationByKey` already does
|
|
81
|
-
* that. /NM values are opaque strings and may contain anything; the
|
|
82
|
-
* `nm:` prefix lets the decoder distinguish them from numeric ids
|
|
83
|
-
* unambiguously.
|
|
58
|
+
* What a page picture draws: the options as passed, and for each one left
|
|
59
|
+
* out, what the caller may read. A left-out option never asks for more than
|
|
60
|
+
* the caller may see; `true` for something they may not read is refused
|
|
61
|
+
* (`PermissionDenied`, naming the option).
|
|
84
62
|
*/
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
63
|
+
function resolvePageLayers(options, may) {
|
|
64
|
+
const { includeAnnotations, includeFormFields } = options ?? {};
|
|
65
|
+
if (includeAnnotations === true && !may.annotations) throw new require_resolver.PermissionDenied("doc.annotate.read", "includeAnnotations");
|
|
66
|
+
if (includeFormFields === true && !may.formFields) throw new require_resolver.PermissionDenied("doc.forms.read", "includeFormFields");
|
|
67
|
+
return {
|
|
68
|
+
includeAnnotations: includeAnnotations ?? may.annotations,
|
|
69
|
+
includeFormFields: includeFormFields ?? (includeAnnotations === false ? false : may.formFields)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** `InvalidArg` unless `quality` is absent or between 0 and 1. */
|
|
73
|
+
function checkImageQuality(quality) {
|
|
74
|
+
if (quality === void 0 || quality >= 0 && quality <= 1) return;
|
|
75
|
+
throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "quality must be between 0 and 1", { details: { field: "quality" } });
|
|
76
|
+
}
|
|
77
|
+
function createPageImageHandle(result, blobSource) {
|
|
78
|
+
return {
|
|
79
|
+
...result,
|
|
80
|
+
...imageSourceOf(blobSource)
|
|
81
|
+
};
|
|
91
82
|
}
|
|
92
83
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* throwing.
|
|
96
|
-
*
|
|
97
|
-
* The input is the already-`decodeURIComponent`-ed segment from the route
|
|
98
|
-
* path. Empty `/NM` values are rejected: `nm:` with no suffix is not a
|
|
99
|
-
* valid identity.
|
|
84
|
+
* An image whose encoded bytes this device holds (a picture it made, such as
|
|
85
|
+
* a stamp's preview), to paint like one an engine rendered.
|
|
100
86
|
*/
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
const rest = key.slice(4);
|
|
104
|
-
const n = Number.parseInt(rest, 10);
|
|
105
|
-
if (!Number.isInteger(n) || n <= 0 || String(n) !== rest) return null;
|
|
106
|
-
return {
|
|
107
|
-
kind: "objectNumber",
|
|
108
|
-
value: n
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
if (key.startsWith("nm:")) {
|
|
112
|
-
const value = key.slice(3);
|
|
113
|
-
if (value.length === 0) return null;
|
|
114
|
-
return {
|
|
115
|
-
kind: "nm",
|
|
116
|
-
value
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
//#endregion
|
|
122
|
-
//#region src/revision/RevisionToken.ts
|
|
123
|
-
function revisionTokensEqual(a, b) {
|
|
124
|
-
return a.docSessionId === b.docSessionId && a.pageObjectNumber === b.pageObjectNumber && a.generation === b.generation;
|
|
87
|
+
function imageSourceOfBytes(bytes, contentType) {
|
|
88
|
+
return imageSourceOf({ blob: async () => new Blob([bytes.slice()], { type: contentType }) });
|
|
125
89
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const UNKNOWN_WEAK_ANNOTATION_STATE = { kind: "unknown" };
|
|
129
|
-
function knownWeakAnnotationState(hasAnyWeakAnnotations) {
|
|
90
|
+
/** The image `blobSource` gives, as a blob and as an object URL. */
|
|
91
|
+
function imageSourceOf(blobSource) {
|
|
130
92
|
return {
|
|
131
|
-
|
|
132
|
-
|
|
93
|
+
blob() {
|
|
94
|
+
return require_viewport.AbortablePromise.run(async (signal) => {
|
|
95
|
+
if (typeof Blob === "undefined") throw new require_format.EngineError(require_format.EngineErrorCode.RuntimeUnavailable, "Blob is not available in this environment");
|
|
96
|
+
const blob = await blobSource.blob(signal);
|
|
97
|
+
if (signal.aborted) throw signal.reason;
|
|
98
|
+
return blob;
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
objectUrl() {
|
|
102
|
+
return require_viewport.AbortablePromise.run(async (signal) => {
|
|
103
|
+
if (typeof Blob === "undefined" || typeof URL === "undefined" || !URL.createObjectURL) throw new require_format.EngineError(require_format.EngineErrorCode.RuntimeUnavailable, "Object URLs are not available in this environment");
|
|
104
|
+
const blob = await blobSource.blob(signal);
|
|
105
|
+
const url = URL.createObjectURL(blob);
|
|
106
|
+
if (signal.aborted) {
|
|
107
|
+
URL.revokeObjectURL(url);
|
|
108
|
+
throw signal.reason;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
url,
|
|
112
|
+
revoke: () => URL.revokeObjectURL(url)
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
}
|
|
133
116
|
};
|
|
134
117
|
}
|
|
135
118
|
//#endregion
|
|
136
|
-
//#region src/
|
|
137
|
-
const
|
|
138
|
-
invisible: false,
|
|
139
|
-
hidden: false,
|
|
140
|
-
print: false,
|
|
141
|
-
noZoom: false,
|
|
142
|
-
noRotate: false,
|
|
143
|
-
noView: false,
|
|
144
|
-
readOnly: false,
|
|
145
|
-
locked: false,
|
|
146
|
-
toggleNoView: false,
|
|
147
|
-
lockedContents: false
|
|
148
|
-
};
|
|
119
|
+
//#region src/dto/PdfSaveMode.ts
|
|
120
|
+
const DEFAULT_PDF_SAVE_MODE = "incremental";
|
|
149
121
|
//#endregion
|
|
150
|
-
//#region src/
|
|
151
|
-
function isBlob(value) {
|
|
152
|
-
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
153
|
-
}
|
|
122
|
+
//#region src/identity/uuid.ts
|
|
154
123
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
124
|
+
* Generate an RFC 4122 v4 UUID using the Web Crypto API surface available in
|
|
125
|
+
* every realm this code runs in: Node 19+, Web Workers, browsers on https,
|
|
126
|
+
* http, intranet and file: pages, and edge runtimes.
|
|
127
|
+
*
|
|
128
|
+
* Why this implementation:
|
|
129
|
+
* - `crypto.randomUUID()` is limited to secure contexts in some browsers;
|
|
130
|
+
* `getRandomValues()` has no such restriction.
|
|
131
|
+
* - `import { randomUUID } from 'crypto'` makes Vite externalize the
|
|
132
|
+
* `crypto` module for browser builds and fail at runtime.
|
|
133
|
+
*
|
|
134
|
+
* Output is the canonical hex form: `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`,
|
|
135
|
+
* where `y` is one of `8/9/a/b` (variant nibble = 10xx).
|
|
162
136
|
*/
|
|
163
|
-
function
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
137
|
+
function generateUuid() {
|
|
138
|
+
const bytes = globalThis.crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
139
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
140
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
141
|
+
return formatUuid(bytes);
|
|
167
142
|
}
|
|
168
143
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
144
|
+
* Generate an RFC 9562 v7 UUID: the Unix time in milliseconds in the first
|
|
145
|
+
* 48 bits, then random bits. Names made later sort later, which is what an
|
|
146
|
+
* annotation's `/NM` gets when the data names none.
|
|
171
147
|
*/
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
mimeType: source.type || void 0,
|
|
179
|
-
...blobName !== void 0 ? { name: blobName } : {}
|
|
180
|
-
};
|
|
148
|
+
function generateUuidV7(now = Date.now()) {
|
|
149
|
+
const bytes = globalThis.crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
150
|
+
let time = Math.max(0, Math.floor(now));
|
|
151
|
+
for (let i = 5; i >= 0; i--) {
|
|
152
|
+
bytes[i] = time % 256;
|
|
153
|
+
time = Math.floor(time / 256);
|
|
181
154
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
mimeType: void 0,
|
|
186
|
-
name: void 0
|
|
187
|
-
} : {
|
|
188
|
-
bytes: await data.arrayBuffer(),
|
|
189
|
-
mimeType: data.type || void 0,
|
|
190
|
-
name: blobFileName(data)
|
|
191
|
-
};
|
|
192
|
-
const resolvedName = name ?? inner.name;
|
|
193
|
-
return {
|
|
194
|
-
bytes: inner.bytes,
|
|
195
|
-
...mimeType ?? inner.mimeType ? { mimeType: mimeType ?? inner.mimeType } : {},
|
|
196
|
-
...resolvedName !== void 0 ? { name: resolvedName } : {}
|
|
197
|
-
};
|
|
155
|
+
bytes[6] = bytes[6] & 15 | 112;
|
|
156
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
157
|
+
return formatUuid(bytes);
|
|
198
158
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const name = blob.name;
|
|
203
|
-
return typeof name === "string" && name.length > 0 ? name : void 0;
|
|
159
|
+
function formatUuid(bytes) {
|
|
160
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
161
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
204
162
|
}
|
|
205
163
|
//#endregion
|
|
206
|
-
//#region src/
|
|
207
|
-
/**
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
* @returns metadata, or `null` for unsupported/corrupt data
|
|
211
|
-
*/
|
|
212
|
-
function sniffBinaryMetadata(buffer) {
|
|
213
|
-
if (buffer.byteLength < 4) return null;
|
|
214
|
-
const bytes = new Uint8Array(buffer);
|
|
215
|
-
if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) return parsePng(buffer);
|
|
216
|
-
if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return parseJpeg(buffer);
|
|
217
|
-
if (bytes[0] === 37 && bytes[1] === 80 && bytes[2] === 68 && bytes[3] === 70) return { mimeType: "application/pdf" };
|
|
218
|
-
return null;
|
|
219
|
-
}
|
|
220
|
-
function parsePng(buffer) {
|
|
221
|
-
if (buffer.byteLength < 24) return null;
|
|
222
|
-
const view = new DataView(buffer);
|
|
223
|
-
const width = view.getUint32(16);
|
|
224
|
-
const height = view.getUint32(20);
|
|
225
|
-
if (width === 0 || height === 0) return null;
|
|
226
|
-
return {
|
|
227
|
-
mimeType: "image/png",
|
|
228
|
-
width,
|
|
229
|
-
height
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
function parseJpeg(buffer) {
|
|
233
|
-
const bytes = new Uint8Array(buffer);
|
|
234
|
-
let offset = 2;
|
|
235
|
-
while (offset + 4 < bytes.byteLength) {
|
|
236
|
-
if (bytes[offset] !== 255) return null;
|
|
237
|
-
const marker = bytes[offset + 1];
|
|
238
|
-
if (marker >= 192 && marker <= 195) {
|
|
239
|
-
if (offset + 9 > bytes.byteLength) return null;
|
|
240
|
-
const view = new DataView(buffer, offset + 5);
|
|
241
|
-
const height = view.getUint16(0);
|
|
242
|
-
const width = view.getUint16(2);
|
|
243
|
-
if (width === 0 || height === 0) return null;
|
|
244
|
-
return {
|
|
245
|
-
mimeType: "image/jpeg",
|
|
246
|
-
width,
|
|
247
|
-
height
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
if (marker === 216 || marker === 217) offset += 2;
|
|
251
|
-
else if (marker === 255) offset += 1;
|
|
252
|
-
else {
|
|
253
|
-
const segLen = bytes[offset + 2] << 8 | bytes[offset + 3];
|
|
254
|
-
offset += 2 + segLen;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return null;
|
|
164
|
+
//#region src/annotation/family.ts
|
|
165
|
+
/** The family an annotation of `subtype` belongs to. */
|
|
166
|
+
function familyOfSubtype(subtype) {
|
|
167
|
+
return subtype === "widget" ? "widgets" : "annotations";
|
|
258
168
|
}
|
|
259
169
|
//#endregion
|
|
260
|
-
//#region src/
|
|
170
|
+
//#region src/dto/normalizeAttachmentFileSource.ts
|
|
261
171
|
/**
|
|
262
172
|
* Resolve an attachment `file` into its wire halves: metadata into the
|
|
263
|
-
* JSON body, bytes into the resource map. Unlike stamps there is
|
|
173
|
+
* JSON body, bytes into the resource map. Unlike stamps there is no
|
|
264
174
|
* format allowlist — attaching arbitrary files is the point — so the
|
|
265
|
-
* declared mime type wins
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* Shared by the file-attachment annotation draft (below) and the
|
|
269
|
-
* document-level `attachments.create` mutation — one vocabulary, one
|
|
270
|
-
* normalizer for both homes a file can enter a PDF through.
|
|
175
|
+
* declared mime type wins, then the Blob's; attachment formats cannot be
|
|
176
|
+
* reliably sniffed, so without either the file has no type.
|
|
177
|
+
* Used by the document-level `attachments.create`.
|
|
271
178
|
*/
|
|
272
179
|
async function normalizeAttachmentFileSource(file, key) {
|
|
273
|
-
const resolved = await resolveBinarySource(file.data);
|
|
180
|
+
const resolved = await require_calibrate.resolveBinarySource(file.data instanceof ArrayBuffer ? new Uint8Array(file.data) : file.data);
|
|
274
181
|
const name = file.name ?? resolved.name;
|
|
275
|
-
if (!name) throw new
|
|
182
|
+
if (!name) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "attachment file requires a name — pass { data, name } or a File whose name is set");
|
|
276
183
|
const mimeType = file.mimeType ?? resolved.mimeType;
|
|
277
184
|
return {
|
|
278
185
|
wireFile: {
|
|
279
|
-
|
|
186
|
+
resources: { file: key },
|
|
280
187
|
name,
|
|
281
188
|
...mimeType !== void 0 ? { mimeType } : {},
|
|
282
189
|
...file.description !== void 0 ? { description: file.description } : {}
|
|
@@ -288,512 +195,309 @@ async function normalizeAttachmentFileSource(file, key) {
|
|
|
288
195
|
}
|
|
289
196
|
};
|
|
290
197
|
}
|
|
291
|
-
async function normalizeFileAttachmentDraft(draft, allocateKey) {
|
|
292
|
-
const { file, ...rest } = draft;
|
|
293
|
-
const key = allocateKey();
|
|
294
|
-
const { wireFile, resource } = await normalizeAttachmentFileSource(file, key);
|
|
295
|
-
return {
|
|
296
|
-
wire: {
|
|
297
|
-
...rest,
|
|
298
|
-
file: wireFile
|
|
299
|
-
},
|
|
300
|
-
resources: { [key]: resource }
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
198
|
//#endregion
|
|
304
|
-
//#region src/
|
|
199
|
+
//#region src/transfer/annotationImport.ts
|
|
305
200
|
/**
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
201
|
+
* The facts an import committed: one `annotations.created` per annotation, in
|
|
202
|
+
* bundle order, each with the envelope of its own page and its own id. The
|
|
203
|
+
* cache pins move once, with the last.
|
|
309
204
|
*/
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return {
|
|
315
|
-
...resolved,
|
|
316
|
-
mimeType: meta.mimeType
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
async function normalizeStampDraft(draft, allocateKey) {
|
|
320
|
-
const { source, ...rest } = draft;
|
|
321
|
-
const resolved = await resolveStampSource(source);
|
|
322
|
-
const key = allocateKey();
|
|
323
|
-
return {
|
|
324
|
-
wire: {
|
|
325
|
-
...rest,
|
|
326
|
-
source: { resource: key }
|
|
327
|
-
},
|
|
328
|
-
resources: { [key]: resolved }
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
async function normalizeStampPatch(patch, allocateKey) {
|
|
332
|
-
if (patch.source === void 0) {
|
|
333
|
-
const { source: _source, ...rest } = patch;
|
|
205
|
+
function annotationImportFacts(result) {
|
|
206
|
+
const last = result.annotations.length - 1;
|
|
207
|
+
return result.annotations.map((annotation, index) => {
|
|
208
|
+
const { page } = annotation.ref;
|
|
334
209
|
return {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
...rest,
|
|
345
|
-
source: { resource: key }
|
|
346
|
-
},
|
|
347
|
-
resources: { [key]: resolved }
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
//#endregion
|
|
351
|
-
//#region src/annotation/normalize.ts
|
|
352
|
-
function createResourceKeyAllocator() {
|
|
353
|
-
let next = 0;
|
|
354
|
-
return () => `r${next++}`;
|
|
355
|
-
}
|
|
356
|
-
async function normalizeAnnotationDraft(draft) {
|
|
357
|
-
switch (draft.subtype) {
|
|
358
|
-
case "stamp": return normalizeStampDraft(draft, createResourceKeyAllocator());
|
|
359
|
-
case "file-attachment": return normalizeFileAttachmentDraft(draft, createResourceKeyAllocator());
|
|
360
|
-
default: return {
|
|
361
|
-
wire: draft,
|
|
362
|
-
resources: {}
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
async function normalizeAnnotationPatch(patch) {
|
|
367
|
-
switch (patch.subtype) {
|
|
368
|
-
case "stamp": return normalizeStampPatch(patch, createResourceKeyAllocator());
|
|
369
|
-
default: return {
|
|
370
|
-
wire: patch,
|
|
371
|
-
resources: {}
|
|
210
|
+
page,
|
|
211
|
+
annotation,
|
|
212
|
+
meta: {
|
|
213
|
+
affectedPages: result.meta.affectedPages.filter((affected) => affected.objectNumber === page.objectNumber),
|
|
214
|
+
cacheDelta: index === last ? result.meta.cacheDelta : null,
|
|
215
|
+
opId: result.meta.opId,
|
|
216
|
+
undoable: result.meta.undoable,
|
|
217
|
+
changed: [annotation.ref]
|
|
218
|
+
}
|
|
372
219
|
};
|
|
373
|
-
}
|
|
220
|
+
});
|
|
374
221
|
}
|
|
375
222
|
//#endregion
|
|
376
|
-
//#region src/
|
|
377
|
-
/** Subtypes that never participate in comment threads. `unsupported`
|
|
378
|
-
* covers `/Popup` dictionaries (raw code 16) and unreadable foreign
|
|
379
|
-
* blobs — neither makes a meaningful comment card. */
|
|
380
|
-
const EXCLUDED_SUBTYPES = /* @__PURE__ */ new Set([
|
|
381
|
-
"widget",
|
|
382
|
-
"link",
|
|
383
|
-
"unsupported"
|
|
384
|
-
]);
|
|
385
|
-
const REVIEW_STATES = /* @__PURE__ */ new Set([
|
|
386
|
-
"accepted",
|
|
387
|
-
"rejected",
|
|
388
|
-
"cancelled",
|
|
389
|
-
"completed",
|
|
390
|
-
"none"
|
|
391
|
-
]);
|
|
392
|
-
const MARKED_STATES = /* @__PURE__ */ new Set(["marked", "unmarked"]);
|
|
393
|
-
const nonEmpty = (v) => typeof v === "string" && v !== "";
|
|
223
|
+
//#region src/transfer/exportSelection.ts
|
|
394
224
|
/**
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
225
|
+
* The annotations an export takes, in document order: page order, then each
|
|
226
|
+
* page's annotation order. Besides the selection:
|
|
227
|
+
*
|
|
228
|
+
* - a reply brings its parent, and the parent's, up to the root;
|
|
229
|
+
* - an annotation brings its popup, and a popup brings its parent;
|
|
230
|
+
* - with `include: 'threads'`, the default, every reply below a selected
|
|
231
|
+
* annotation.
|
|
232
|
+
*
|
|
233
|
+
* A reply is on its parent's page (ISO 32000-2 §12.5.6.2, `/IRT`) and a popup
|
|
234
|
+
* on its parent's, so none of this reaches another page. `readPage` returns a
|
|
235
|
+
* page's annotations in `/Annots` order and is called once for each page
|
|
236
|
+
* the selection is on. `pages` is the document's pages in order. A selected
|
|
237
|
+
* page or annotation the document doesn't have is refused with `NotFound`.
|
|
398
238
|
*/
|
|
399
|
-
function
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
function buildCommentThreads(annotations, opts = {}) {
|
|
403
|
-
const eligible = annotations.filter((a) => !EXCLUDED_SUBTYPES.has(a.subtype));
|
|
239
|
+
function closeExportSelection(selection, pages, readPage) {
|
|
240
|
+
const inDocument = new Set(pages.map(require_format.encodePageKey));
|
|
241
|
+
const read = /* @__PURE__ */ new Map();
|
|
404
242
|
const byKey = /* @__PURE__ */ new Map();
|
|
405
|
-
|
|
406
|
-
const
|
|
407
|
-
if (
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
pageObjectNumber: a.pageObjectNumber,
|
|
412
|
-
nm: a.nm
|
|
413
|
-
});
|
|
414
|
-
if (!byKey.has(aliasKey)) byKey.set(aliasKey, a);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
const children = /* @__PURE__ */ new Map();
|
|
418
|
-
for (const a of eligible) {
|
|
419
|
-
if (!a.inReplyTo) continue;
|
|
420
|
-
const parent = byKey.get(require_derive.refKey(a.inReplyTo));
|
|
421
|
-
if (!parent) continue;
|
|
422
|
-
const parentKey = require_derive.refKey(parent.ref);
|
|
423
|
-
const list = children.get(parentKey);
|
|
424
|
-
if (list) list.push(a);
|
|
425
|
-
else children.set(parentKey, [a]);
|
|
426
|
-
}
|
|
427
|
-
const visited = /* @__PURE__ */ new Set();
|
|
428
|
-
const threads = [];
|
|
429
|
-
const walk = (root) => {
|
|
430
|
-
const replies = [];
|
|
431
|
-
const groupedParts = [];
|
|
432
|
-
const states = [];
|
|
433
|
-
visited.add(require_derive.refKey(root.ref));
|
|
434
|
-
const stack = [...children.get(require_derive.refKey(root.ref)) ?? []];
|
|
435
|
-
while (stack.length > 0) {
|
|
436
|
-
const a = stack.pop();
|
|
437
|
-
const key = require_derive.refKey(a.ref);
|
|
438
|
-
if (visited.has(key)) continue;
|
|
439
|
-
visited.add(key);
|
|
440
|
-
if (isStateAnnotation(a)) states.push(a);
|
|
441
|
-
else if (require_derive.classifyRelation(a) === "grouped-subordinate") groupedParts.push(a);
|
|
442
|
-
else replies.push(a);
|
|
443
|
-
stack.push(...children.get(key) ?? []);
|
|
444
|
-
}
|
|
445
|
-
replies.sort(chronological);
|
|
446
|
-
states.sort(chronological);
|
|
447
|
-
threads.push({
|
|
448
|
-
root,
|
|
449
|
-
pageObjectNumber: root.pageObjectNumber,
|
|
450
|
-
replies,
|
|
451
|
-
groupedParts,
|
|
452
|
-
review: computeReview(states, opts)
|
|
453
|
-
});
|
|
243
|
+
const readOnce = (page) => {
|
|
244
|
+
const pageKey = require_format.encodePageKey(page);
|
|
245
|
+
if (read.has(pageKey) || !inDocument.has(pageKey)) return;
|
|
246
|
+
const annotations = readPage(page);
|
|
247
|
+
read.set(pageKey, annotations);
|
|
248
|
+
for (const annotation of annotations) byKey.set(require_format.annotationKey(annotation.ref), annotation);
|
|
454
249
|
};
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
if (isStateAnnotation(a)) continue;
|
|
459
|
-
walk(a);
|
|
460
|
-
}
|
|
461
|
-
return threads;
|
|
462
|
-
}
|
|
463
|
-
/** `created ?? modified` ascending; undated last; z-order tiebreak. */
|
|
464
|
-
function chronological(a, b) {
|
|
465
|
-
const at = a.created ?? a.modified;
|
|
466
|
-
const bt = b.created ?? b.modified;
|
|
467
|
-
if (at !== null && bt !== null && at !== bt) return at < bt ? -1 : 1;
|
|
468
|
-
if (at !== null && bt === null) return -1;
|
|
469
|
-
if (at === null && bt !== null) return 1;
|
|
470
|
-
return a.index - b.index;
|
|
471
|
-
}
|
|
472
|
-
function computeReview(states, opts) {
|
|
473
|
-
const byReviewer = {};
|
|
474
|
-
const markedLatest = {};
|
|
475
|
-
let lastChange = null;
|
|
476
|
-
for (const a of states) {
|
|
477
|
-
const status = toReviewStatus(a);
|
|
478
|
-
if (!status) continue;
|
|
479
|
-
if (status.stateModel === "marked") {
|
|
480
|
-
if (status.by !== null && isNewer(status, markedLatest[status.by])) markedLatest[status.by] = status;
|
|
481
|
-
continue;
|
|
482
|
-
}
|
|
483
|
-
if (status.by !== null && isNewer(status, byReviewer[status.by])) byReviewer[status.by] = status;
|
|
484
|
-
if (isNewer(status, lastChange)) lastChange = status;
|
|
485
|
-
}
|
|
486
|
-
const markedBy = Object.keys(markedLatest).filter((key) => markedLatest[key].state === "marked").sort();
|
|
487
|
-
const review = {
|
|
488
|
-
byReviewer,
|
|
489
|
-
lastChange,
|
|
490
|
-
markedBy,
|
|
491
|
-
statusRefs: states.map((a) => a.ref)
|
|
250
|
+
const find = (ref) => {
|
|
251
|
+
readOnce(ref.page);
|
|
252
|
+
return byKey.get(require_format.annotationKey(ref));
|
|
492
253
|
};
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
const rawState = nonEmpty(a.state) ? a.state : null;
|
|
506
|
-
let stateModel = nonEmpty(a.stateModel) ? a.stateModel : null;
|
|
507
|
-
if (stateModel === null && rawState !== null) if (REVIEW_STATES.has(rawState)) stateModel = "review";
|
|
508
|
-
else if (MARKED_STATES.has(rawState)) stateModel = "marked";
|
|
509
|
-
else return null;
|
|
510
|
-
let state = rawState;
|
|
511
|
-
if (state === null) if (stateModel === "review") state = "none";
|
|
512
|
-
else if (stateModel === "marked") state = "unmarked";
|
|
513
|
-
else return null;
|
|
514
|
-
if (stateModel === null) return null;
|
|
515
|
-
return {
|
|
516
|
-
state,
|
|
517
|
-
stateModel,
|
|
518
|
-
by: a.userId ?? (nonEmpty(a.author) ? a.author : null),
|
|
519
|
-
at: a.modified ?? a.created ?? null,
|
|
520
|
-
ref: a.ref
|
|
254
|
+
for (const page of selection.pages ?? []) if (!inDocument.has(require_format.encodePageKey(page))) throw new require_format.EngineError(require_format.EngineErrorCode.NotFound, `export: the document has no page ${require_format.encodePageKey(page)}`);
|
|
255
|
+
const everything = !selection.refs && !selection.pages;
|
|
256
|
+
const threads = (selection.include ?? "threads") === "threads";
|
|
257
|
+
for (const page of everything ? pages : selection.pages ?? []) readOnce(page);
|
|
258
|
+
const taken = /* @__PURE__ */ new Set();
|
|
259
|
+
const pending = [];
|
|
260
|
+
const take = (annotation) => {
|
|
261
|
+
if (!annotation) return;
|
|
262
|
+
const key = require_format.annotationKey(annotation.ref);
|
|
263
|
+
if (taken.has(key)) return;
|
|
264
|
+
taken.add(key);
|
|
265
|
+
pending.push(annotation);
|
|
521
266
|
};
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
267
|
+
if (everything) for (const annotations of read.values()) annotations.forEach(take);
|
|
268
|
+
else {
|
|
269
|
+
for (const page of selection.pages ?? []) read.get(require_format.encodePageKey(page))?.forEach(take);
|
|
270
|
+
for (const ref of selection.refs ?? []) {
|
|
271
|
+
const annotation = find(ref);
|
|
272
|
+
if (!annotation) throw new require_format.EngineError(require_format.EngineErrorCode.NotFound, `export: the document has no annotation ${require_format.annotationKey(ref)}`);
|
|
273
|
+
take(annotation);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (threads) {
|
|
277
|
+
for (const annotation of [...pending]) if (annotation.subtype === "popup" && annotation.parent) take(find(annotation.parent));
|
|
278
|
+
const replies = /* @__PURE__ */ new Map();
|
|
279
|
+
for (const annotations of read.values()) for (const annotation of annotations) {
|
|
280
|
+
const parent = annotation.reply ? find(annotation.reply.to) : void 0;
|
|
281
|
+
if (!parent) continue;
|
|
282
|
+
const key = require_format.annotationKey(parent.ref);
|
|
283
|
+
replies.set(key, [...replies.get(key) ?? [], annotation]);
|
|
284
|
+
}
|
|
285
|
+
for (let i = 0; i < pending.length; i++) replies.get(require_format.annotationKey(pending[i].ref))?.forEach(take);
|
|
286
|
+
}
|
|
287
|
+
for (let i = 0; i < pending.length; i++) {
|
|
288
|
+
const annotation = pending[i];
|
|
289
|
+
if (annotation.reply) take(find(annotation.reply.to));
|
|
290
|
+
if (annotation.popup) take(find(annotation.popup));
|
|
291
|
+
if (annotation.subtype === "popup" && annotation.parent) take(find(annotation.parent));
|
|
292
|
+
}
|
|
293
|
+
const ordered = [];
|
|
294
|
+
for (const page of pages) for (const annotation of read.get(require_format.encodePageKey(page)) ?? []) if (taken.has(require_format.annotationKey(annotation.ref))) ordered.push(annotation);
|
|
295
|
+
return ordered;
|
|
532
296
|
}
|
|
533
297
|
//#endregion
|
|
534
|
-
//#region src/
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
function invalidatesWeakIndexRefs(kind, weakStateBefore) {
|
|
542
|
-
if (!shiftsExistingAnnotationIndices(kind)) return false;
|
|
543
|
-
if (weakStateBefore.kind !== "known") throw new Error(`invalidatesWeakIndexRefs requires a known WeakAnnotationState for ${kind}; got 'unknown'. Caller must scan the page before computing mutation impact.`);
|
|
544
|
-
return weakStateBefore.hasAnyWeakAnnotations;
|
|
298
|
+
//#region src/annotation/AnnotationList.ts
|
|
299
|
+
/** Lists of different pages as one, in their order. */
|
|
300
|
+
function concatAnnotationLists(lists) {
|
|
301
|
+
return {
|
|
302
|
+
annotations: lists.flatMap((list) => list.annotations),
|
|
303
|
+
pages: lists.flatMap((list) => list.pages)
|
|
304
|
+
};
|
|
545
305
|
}
|
|
546
306
|
//#endregion
|
|
547
|
-
//#region src/
|
|
307
|
+
//#region src/mutation/AnnotationMutationResults.ts
|
|
548
308
|
/**
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
*
|
|
552
|
-
* anything visible while far above accumulated f32 drift at page magnitudes.
|
|
309
|
+
* What a delete removed, as its `annotations.deleted` event names it for
|
|
310
|
+
* listeners that didn't make the call: the refs in `meta.changed`, the
|
|
311
|
+
* annotation first.
|
|
553
312
|
*/
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
"
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
]);
|
|
571
|
-
/**
|
|
572
|
-
* Kinds whose `/AP` paints `/Contents`. Everywhere else `contents` is popup
|
|
573
|
-
* note text — editing a comment must never re-bake (or destroy) the shape's
|
|
574
|
-
* appearance.
|
|
575
|
-
*/
|
|
576
|
-
const CONTENTS_PAINTED = /* @__PURE__ */ new Set(["free-text", "redact"]);
|
|
577
|
-
/**
|
|
578
|
-
* The vertex family's `/EMBD_Metadata/Rotation` is an advisory scalar (the
|
|
579
|
-
* vertices are already rotated); it never drives the AP generator, so patches
|
|
580
|
-
* touching it are appearance-inert for these kinds.
|
|
581
|
-
*/
|
|
582
|
-
const ADVISORY_ROTATION = /* @__PURE__ */ new Set([
|
|
583
|
-
"line",
|
|
584
|
-
"polyline",
|
|
585
|
-
"polygon",
|
|
586
|
-
"ink"
|
|
587
|
-
]);
|
|
588
|
-
/**
|
|
589
|
-
* The box kinds carry the `/EMBD_Metadata` transform pair (`rotation` +
|
|
590
|
-
* `unrotatedRect`), tri-state on writes: omitted fields are PRESERVED, `null`
|
|
591
|
-
* (or `0` for rotation) clears. Translation verification therefore compares
|
|
592
|
-
* the after-state — `patch.rotation ?? current.rotation` — not the patch keys.
|
|
593
|
-
*/
|
|
594
|
-
const BOX_TRANSFORM = /* @__PURE__ */ new Set([
|
|
595
|
-
"square",
|
|
596
|
-
"circle",
|
|
597
|
-
"free-text",
|
|
598
|
-
"stamp"
|
|
599
|
-
]);
|
|
313
|
+
function deletedAnnotationsOf(result) {
|
|
314
|
+
return result.meta.changed;
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/annotation/resolve/patchBetween.ts
|
|
318
|
+
/** Exact deep equality: the same value, or arrays and objects whose members are. */
|
|
319
|
+
function sameValue(left, right) {
|
|
320
|
+
if (Object.is(left, right)) return true;
|
|
321
|
+
if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) return false;
|
|
322
|
+
if (Array.isArray(left) !== Array.isArray(right)) return false;
|
|
323
|
+
const leftRecord = left;
|
|
324
|
+
const rightRecord = right;
|
|
325
|
+
const names = Object.keys(leftRecord).filter((name) => leftRecord[name] !== void 0);
|
|
326
|
+
const others = Object.keys(rightRecord).filter((name) => rightRecord[name] !== void 0);
|
|
327
|
+
return names.length === others.length && names.every((name) => sameValue(leftRecord[name], rightRecord[name]));
|
|
328
|
+
}
|
|
600
329
|
/**
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
330
|
+
* What `after` changed from `before`, as `update` takes it: each data field
|
|
331
|
+
* whose value differs, whole. Fields the engine works out, stamps or keeps as
|
|
332
|
+
* found (a drawn kind's `rect`, the dates and authors, the refs it keeps) are
|
|
333
|
+
* left out. Values are compared exactly, so a value rebuilt with the same
|
|
334
|
+
* content is no change. Works in either space: it only compares values by
|
|
335
|
+
* field name.
|
|
604
336
|
*/
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
highlight: ["rect", "quadPoints"],
|
|
618
|
-
underline: ["rect", "quadPoints"],
|
|
619
|
-
squiggly: ["rect", "quadPoints"],
|
|
620
|
-
strikeout: ["rect", "quadPoints"],
|
|
621
|
-
redact: ["rect", "quadPoints"],
|
|
622
|
-
caret: ["rect"],
|
|
623
|
-
text: ["rect"],
|
|
624
|
-
stamp: ["rect", "unrotatedRect"],
|
|
625
|
-
"file-attachment": ["rect"],
|
|
626
|
-
link: ["rect"]
|
|
627
|
-
};
|
|
628
|
-
const numEq = (a, b) => Math.abs(a - b) <= EPSILON;
|
|
629
|
-
/** Degrees normalized to [0,360); absent reads as 0 (no rotation). */
|
|
630
|
-
const normDeg = (v) => {
|
|
631
|
-
return typeof v === "number" ? (v % 360 + 360) % 360 : 0;
|
|
632
|
-
};
|
|
337
|
+
function annotationPatchBetween(before, after) {
|
|
338
|
+
const patch = {};
|
|
339
|
+
if (before === after) return patch;
|
|
340
|
+
const owners = require_resolveAnnotationDraft.kindFactsOf(after.subtype)?.owners ?? {};
|
|
341
|
+
const was = before;
|
|
342
|
+
const now = after;
|
|
343
|
+
for (const [name, owner] of Object.entries(owners)) {
|
|
344
|
+
if (owner !== "data" || sameValue(was[name], now[name])) continue;
|
|
345
|
+
patch[name] = now[name] === void 0 ? null : now[name];
|
|
346
|
+
}
|
|
347
|
+
return patch;
|
|
348
|
+
}
|
|
633
349
|
/**
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
* and objects compare structurally.
|
|
350
|
+
* `current` with `patch`'s data fields set, each as a read spells it: the
|
|
351
|
+
* patch as given. No field follows from another here; `applyAnnotationPatch`
|
|
352
|
+
* adds what the engine's rules make follow. Works in either space.
|
|
638
353
|
*/
|
|
639
|
-
function
|
|
640
|
-
|
|
641
|
-
if (typeof a === "number" && typeof b === "number") return numEq(a, b);
|
|
642
|
-
if (Array.isArray(a) || Array.isArray(b)) {
|
|
643
|
-
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
644
|
-
return a.every((v, i) => semanticEqual(v, b[i]));
|
|
645
|
-
}
|
|
646
|
-
if (typeof a === "object" && typeof b === "object") {
|
|
647
|
-
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
648
|
-
for (const k of keys) if (!semanticEqual(a[k], b[k])) return false;
|
|
649
|
-
return true;
|
|
650
|
-
}
|
|
651
|
-
return a === b;
|
|
354
|
+
function mergeAnnotationPatch(current, patch) {
|
|
355
|
+
return require_calibrate.applyResolvedPatch(current, patch);
|
|
652
356
|
}
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/pageSpace/pages.ts
|
|
653
359
|
/**
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
* y-axis keys (`bottom`/`top`/`y`) by `dy`, and any other numeric leaf must be
|
|
657
|
-
* unchanged. Arrays walk elementwise (same length required).
|
|
360
|
+
* A page's five boxes in page space: measured from the top-left of the crop
|
|
361
|
+
* box, the visible page, which is therefore `{ x: 0, y: 0, width, height }`.
|
|
658
362
|
*/
|
|
659
|
-
function
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const c = cur[k];
|
|
669
|
-
const n = next[k];
|
|
670
|
-
if (typeof c === "number" && typeof n === "number") {
|
|
671
|
-
if (!numEq(c + (k === "left" || k === "right" || k === "x" ? dx : k === "bottom" || k === "top" || k === "y" ? dy : 0), n)) return false;
|
|
672
|
-
} else if (!shiftedBy(c, n, dx, dy)) return false;
|
|
673
|
-
}
|
|
674
|
-
return true;
|
|
675
|
-
}
|
|
676
|
-
return cur === next;
|
|
363
|
+
function pageSpaceBoxesOf(boxes) {
|
|
364
|
+
const visible = boxes.crop;
|
|
365
|
+
return {
|
|
366
|
+
media: require_calibrate.pageBoxOf(boxes.media, visible),
|
|
367
|
+
crop: require_calibrate.pageBoxOf(boxes.crop, visible),
|
|
368
|
+
bleed: require_calibrate.pageBoxOf(boxes.bleed, visible),
|
|
369
|
+
trim: require_calibrate.pageBoxOf(boxes.trim, visible),
|
|
370
|
+
art: require_calibrate.pageBoxOf(boxes.art, visible)
|
|
371
|
+
};
|
|
677
372
|
}
|
|
678
373
|
/**
|
|
679
|
-
*
|
|
680
|
-
*
|
|
681
|
-
* height preserved; every other geometry field present on the annotation must
|
|
682
|
-
* ride along shifted by the same delta — a rect move that leaves `vertices`
|
|
683
|
-
* behind is NOT a translation (the dictionary would desync from the pixels).
|
|
684
|
-
* For box kinds the `/EMBD_Metadata` transform group is checked as an
|
|
685
|
-
* after-state: writes are tri-state (omitted preserves, null/0 clears), so an
|
|
686
|
-
* omitted rotation keeps the current one — but a preserved-yet-unshifted
|
|
687
|
-
* `unrotatedRect` still fails the congruence check via the field loop.
|
|
374
|
+
* A page's layout in page space. Its actions may go to other pages, so each
|
|
375
|
+
* destination is measured with `boxOf`, the box of the page it goes to.
|
|
688
376
|
*/
|
|
689
|
-
function
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
if (
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
return
|
|
377
|
+
function pageLayoutOf(layout, boxOf) {
|
|
378
|
+
const { actions, ...rest } = layout;
|
|
379
|
+
return {
|
|
380
|
+
...rest,
|
|
381
|
+
boxes: pageSpaceBoxesOf(layout.boxes),
|
|
382
|
+
...actions ? { actions: require_calibrate.mapPageActions(actions, (destination) => require_calibrate.pageDestinationOf(destination, boxOf)) } : {}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/** Every page's visible box, by page, from the pages' layouts. */
|
|
386
|
+
function visibleBoxesOf(pages) {
|
|
387
|
+
const boxes = new Map(pages.map((page) => [page.ref.objectNumber, page.boxes.crop]));
|
|
388
|
+
return (page) => {
|
|
389
|
+
const box = boxes.get(page.objectNumber);
|
|
390
|
+
if (!box) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `No page ${page.objectNumber} in this document`);
|
|
391
|
+
return box;
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
/** The document's pages in page space. */
|
|
395
|
+
function pageListOf(snapshot) {
|
|
396
|
+
const boxOf = visibleBoxesOf(snapshot.pages);
|
|
397
|
+
return {
|
|
398
|
+
...snapshot,
|
|
399
|
+
pages: snapshot.pages.map((page) => pageLayoutOf(page, boxOf))
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/pageSpace/rendering.ts
|
|
404
|
+
/** A page-space render target in the file's coordinates. `visible` is the page's visible box. */
|
|
405
|
+
function pdfRenderTargetOf(target, visible) {
|
|
406
|
+
return target.kind === "rect" ? {
|
|
407
|
+
...target,
|
|
408
|
+
rect: require_calibrate.pdfRectOf(target.rect, visible)
|
|
409
|
+
} : target;
|
|
710
410
|
}
|
|
711
411
|
/**
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
* 1. Value-diff: drop keys whose value semantically equals the current one,
|
|
715
|
-
* plus the always-inert metadata keys (and per-kind inert keys: `contents`
|
|
716
|
-
* where it isn't painted, advisory `rotation` on the vertex family).
|
|
717
|
-
* Nothing left → `'inert'`.
|
|
718
|
-
* 2. If every remaining key is translatable geometry for this kind AND the
|
|
719
|
-
* values are one rigid translation → `'translation'`.
|
|
720
|
-
* 3. Anything else — style, text, unknown keys, unknown kinds → `'regenerate'`.
|
|
412
|
+
* Where each rendered appearance goes, in page space: raster or encoded, each
|
|
413
|
+
* placed by its `rect`. `visible` is the page's visible box.
|
|
721
414
|
*/
|
|
722
|
-
function
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
const caption = pat.caption === void 0 ? cur.caption : pat.caption;
|
|
728
|
-
const contentsPainted = CONTENTS_PAINTED.has(subtype) || [
|
|
729
|
-
"line",
|
|
730
|
-
"polygon",
|
|
731
|
-
"polyline"
|
|
732
|
-
].includes(subtype) && !!caption?.enabled;
|
|
733
|
-
const touched = [];
|
|
734
|
-
for (const [key, value] of Object.entries(pat)) {
|
|
735
|
-
if (value === void 0 || INERT_KEYS.has(key)) continue;
|
|
736
|
-
if (key === "contents" && !contentsPainted) continue;
|
|
737
|
-
if (key === "rotation" && ADVISORY_ROTATION.has(subtype)) continue;
|
|
738
|
-
if (!semanticEqual(value, cur[key])) touched.push(key);
|
|
739
|
-
}
|
|
740
|
-
if (touched.length === 0) return "inert";
|
|
741
|
-
const baseGeometryKeys = TRANSLATABLE_GEOMETRY[subtype];
|
|
742
|
-
const geometryKeys = baseGeometryKeys && (subtype === "polygon" || subtype === "polyline") && cur.caption?.center ? [...baseGeometryKeys, "caption"] : baseGeometryKeys;
|
|
743
|
-
if (!geometryKeys) return "regenerate";
|
|
744
|
-
if (!touched.every((k) => geometryKeys.includes(k))) return "regenerate";
|
|
745
|
-
return isRigidTranslation(cur, pat, subtype, geometryKeys) ? "translation" : "regenerate";
|
|
415
|
+
function pageAppearancesOf(appearances, visible) {
|
|
416
|
+
return appearances.map((appearance) => ({
|
|
417
|
+
...appearance,
|
|
418
|
+
rect: require_calibrate.pageBoxOf(appearance.rect, visible)
|
|
419
|
+
}));
|
|
746
420
|
}
|
|
747
421
|
//#endregion
|
|
748
|
-
//#region src/
|
|
422
|
+
//#region src/pageSpace/forms.ts
|
|
423
|
+
/** A page-space widget placement in the file's coordinates, measured on its page. */
|
|
424
|
+
function pdfWidgetPlacementOf(placement, boxOf) {
|
|
425
|
+
const { actions, ...rest } = placement;
|
|
426
|
+
const visible = boxOf(placement.page);
|
|
427
|
+
return {
|
|
428
|
+
...rest,
|
|
429
|
+
...placement.rect ? { rect: require_calibrate.pdfRectOf(placement.rect, visible) } : {},
|
|
430
|
+
...placement.box ? { box: require_calibrate.pdfRectOf(placement.box, visible) } : {},
|
|
431
|
+
...actions ? { actions: require_calibrate.mapTriggerActions(actions, (destination) => require_calibrate.pdfDestinationOf(destination, boxOf)) } : {}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
/** A field draft in the file's coordinates: each widget measured on its own page. */
|
|
435
|
+
function pdfFormFieldDraftOf(draft, boxOf) {
|
|
436
|
+
if (!draft.widgets) return draft;
|
|
437
|
+
return {
|
|
438
|
+
...draft,
|
|
439
|
+
widgets: draft.widgets.map((widget) => pdfWidgetPlacementOf(widget, boxOf))
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
/** A field's actions in page space, each destination measured on its page. */
|
|
443
|
+
function pageFieldActionsOf(actions, boxOf) {
|
|
444
|
+
return require_calibrate.mapFieldActions(actions, (destination) => require_calibrate.pageDestinationOf(destination, boxOf));
|
|
445
|
+
}
|
|
446
|
+
/** A form field in page space: each destination of its actions on the page it goes to. */
|
|
447
|
+
function pageFormFieldOf(field, boxOf) {
|
|
448
|
+
if (!field.actions) return field;
|
|
449
|
+
return {
|
|
450
|
+
...field,
|
|
451
|
+
actions: pageFieldActionsOf(field.actions, boxOf)
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
/** A widget row in page space, measured on its page. */
|
|
455
|
+
function pageWidgetOf(widget, boxOf) {
|
|
456
|
+
return require_calibrate.pageAnnotationOf(widget, boxOf(widget.page), boxOf);
|
|
457
|
+
}
|
|
458
|
+
/** A form in page space: its fields, and each widget row on its page. */
|
|
459
|
+
function pageFormSnapshotOf(snapshot, boxOf) {
|
|
460
|
+
return {
|
|
461
|
+
...snapshot,
|
|
462
|
+
fields: snapshot.fields.map((field) => pageFormFieldOf(field, boxOf)),
|
|
463
|
+
widgets: snapshot.widgets.map((widget) => pageWidgetOf(widget, boxOf))
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
//#endregion
|
|
467
|
+
//#region src/forms/draft.ts
|
|
749
468
|
/**
|
|
750
|
-
*
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
* `encodeStableIdKey` (`obj:42` / `nm:…`) so the two member-key syntaxes
|
|
754
|
-
* read the same on the wire:
|
|
755
|
-
*
|
|
756
|
-
* `{ kind: 'objectNumber', fieldObjectNumber: 12 }` -> `'obj:12'`
|
|
757
|
-
* `{ kind: 'fqn', name: 'billing.name' }` -> `'fqn:billing.name'`
|
|
758
|
-
*
|
|
759
|
-
* The caller is responsible for `encodeURIComponent`-ing the result before
|
|
760
|
-
* splicing it into a URL path; the `wirePaths.layerFormField*` builders
|
|
761
|
-
* already do that. FQNs are opaque strings and may contain anything; the
|
|
762
|
-
* `fqn:` prefix keeps them unambiguous from numeric ids.
|
|
469
|
+
* Whether creating a field from `draft` takes `doc.forms.script`: a script
|
|
470
|
+
* among its actions, or a widget action that holds JavaScript, a submit or a
|
|
471
|
+
* link.
|
|
763
472
|
*/
|
|
764
|
-
function
|
|
765
|
-
|
|
766
|
-
if (!Number.isInteger(ref.fieldObjectNumber) || ref.fieldObjectNumber <= 0) throw new RangeError(`encodeFieldRefKey: fieldObjectNumber must be a positive integer, got ${ref.fieldObjectNumber}`);
|
|
767
|
-
return `obj:${ref.fieldObjectNumber}`;
|
|
768
|
-
}
|
|
769
|
-
return `fqn:${ref.name}`;
|
|
473
|
+
function draftWritesScripts(draft) {
|
|
474
|
+
return require_value.writesScripts(draft.actions) || (draft.widgets ?? []).some((placement) => require_value.writesScripts(placement.actions));
|
|
770
475
|
}
|
|
476
|
+
//#endregion
|
|
477
|
+
//#region src/forms/placement.ts
|
|
771
478
|
/**
|
|
772
|
-
*
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
*
|
|
479
|
+
* A placement as the file holds it: `/Rect`, where the widget stands, and
|
|
480
|
+
* its turn. A `box` given is turned into the rect it stands in, as a box
|
|
481
|
+
* kind's create turns it; without one, `rect` is that place.
|
|
482
|
+
*
|
|
483
|
+
* Refused with `InvalidArg`: a placement with neither, and a turn that
|
|
484
|
+
* isn't a quarter turn (a widget's contents turn only so, `/MK /R`).
|
|
777
485
|
*/
|
|
778
|
-
function
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
name
|
|
794
|
-
};
|
|
795
|
-
}
|
|
796
|
-
return null;
|
|
486
|
+
function placedWidgetOf(placement) {
|
|
487
|
+
const { box, rect, rotation, ...rest } = placement;
|
|
488
|
+
if (rotation !== void 0 && ![
|
|
489
|
+
0,
|
|
490
|
+
90,
|
|
491
|
+
180,
|
|
492
|
+
270
|
|
493
|
+
].includes(rotation)) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `a widget turns by a quarter turn (0, 90, 180 or 270), not ${rotation}`, { details: { field: "rotation" } });
|
|
494
|
+
const place = box ? require_resolveAnnotationDraft.pdfRectTurnedBounds(require_resolveAnnotationDraft.normalizePdfRect(box), rotation ?? 0) : rect;
|
|
495
|
+
if (!place) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "a widget's placement needs its `rect` or its `box`", { details: { field: "rect" } });
|
|
496
|
+
return {
|
|
497
|
+
...rest,
|
|
498
|
+
rect: place,
|
|
499
|
+
...rotation !== void 0 ? { rotation } : {}
|
|
500
|
+
};
|
|
797
501
|
}
|
|
798
502
|
//#endregion
|
|
799
503
|
//#region src/signature/analysis/pdf-value.ts
|
|
@@ -817,7 +521,7 @@ function parsePdfValue(text) {
|
|
|
817
521
|
var Parser = class {
|
|
818
522
|
constructor(text) {
|
|
819
523
|
this.text = text;
|
|
820
|
-
|
|
524
|
+
require_format._defineProperty(this, "pos", 0);
|
|
821
525
|
}
|
|
822
526
|
atEnd() {
|
|
823
527
|
return this.pos >= this.text.length;
|
|
@@ -1161,7 +865,7 @@ const ACROFORM_KEYS = /* @__PURE__ */ new Set([
|
|
|
1161
865
|
* are allowed"): everything but the field's identity and its place in
|
|
1162
866
|
* the tree. v1/08 /V+/AP, 09 /Ff, 10 /Rect, 11 /F, 18 /TU, 21 /DA; 13 /T
|
|
1163
867
|
* forbidden. /AA (v1/12) and /A are accepted by Acrobat and deliberately
|
|
1164
|
-
*
|
|
868
|
+
* not listed: an action on a signed form is executable content.
|
|
1165
869
|
*
|
|
1166
870
|
* fill (a P=2 certification): value and appearance. v1/26 /V+/AP, v3/64
|
|
1167
871
|
* /Ff (ReadOnly added), 65 /DA, 68 /AP stream; v3/66 /TU, 67 /F, v2/50
|
|
@@ -1216,7 +920,7 @@ const WIDGET_KEYS_BY_LEVEL = {
|
|
|
1216
920
|
])
|
|
1217
921
|
};
|
|
1218
922
|
/**
|
|
1219
|
-
* Signing an
|
|
923
|
+
* Signing an existing field: its value, appearance and ReadOnly at any
|
|
1220
924
|
* level; after an approval signature also its tooltip and a /Lock installed
|
|
1221
925
|
* with the signature (v1/18, 19: both valid; under P=2 the combination is
|
|
1222
926
|
* rejected, v3/69, so neither is allowed at `fill`).
|
|
@@ -1249,7 +953,7 @@ function signedFieldKeysFor(level) {
|
|
|
1249
953
|
return level === "annotate" ? SIGNED_FIELD_KEYS_BY_LEVEL.annotate : SIGNED_FIELD_KEYS_BY_LEVEL.fill;
|
|
1250
954
|
}
|
|
1251
955
|
/**
|
|
1252
|
-
* Rules whose permitted findings do not make a revision a
|
|
956
|
+
* Rules whose permitted findings do not make a revision a change of the
|
|
1253
957
|
* document: an object written again with the sealed value, an object nobody
|
|
1254
958
|
* references, a cross-reference container, the trailer's own bookkeeping.
|
|
1255
959
|
* A window with nothing else is `unchanged` (Acrobat: "not modified").
|
|
@@ -1260,7 +964,7 @@ const NON_EFFECTIVE_RULES = /* @__PURE__ */ new Set([
|
|
|
1260
964
|
"xref-container",
|
|
1261
965
|
"trailer"
|
|
1262
966
|
]);
|
|
1263
|
-
/** The level a step runs at, and the locks it enforces: what the
|
|
967
|
+
/** The level a step runs at, and the locks it enforces: what the older revision's signatures established. */
|
|
1264
968
|
function restrictionsOf(before) {
|
|
1265
969
|
const protection = require_resolver.deriveProtection(before.signatures);
|
|
1266
970
|
return {
|
|
@@ -1270,7 +974,7 @@ function restrictionsOf(before) {
|
|
|
1270
974
|
}
|
|
1271
975
|
/**
|
|
1272
976
|
* Judge one pairwise step. Every reference to a changed object, in the
|
|
1273
|
-
* older
|
|
977
|
+
* older and the newer revision, must be claimed by a rule that inspected
|
|
1274
978
|
* that use; an unclaimed reference is `unexplained` and forbidden. A
|
|
1275
979
|
* truncated value is `incomplete`, never permitted. Pure: JSON in, JSON
|
|
1276
980
|
* out, the same code in the browser worker, on the server and in tests.
|
|
@@ -1377,7 +1081,7 @@ function indexRoles(s) {
|
|
|
1377
1081
|
for (const w of f.widgets) widgetToField.set(w, f.objectNumber);
|
|
1378
1082
|
}
|
|
1379
1083
|
const signedFields = /* @__PURE__ */ new Set();
|
|
1380
|
-
for (const sig of s.signatures) if (sig.signed && sig.field.kind === "objectNumber") signedFields.add(sig.field.
|
|
1084
|
+
for (const sig of s.signatures) if (sig.signed && sig.field.kind === "objectNumber") signedFields.add(sig.field.objectNumber);
|
|
1381
1085
|
return {
|
|
1382
1086
|
fieldByObj,
|
|
1383
1087
|
widgetToField,
|
|
@@ -1394,12 +1098,12 @@ var StepContext = class {
|
|
|
1394
1098
|
this.input = input;
|
|
1395
1099
|
this.level = level;
|
|
1396
1100
|
this.locks = locks;
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1101
|
+
require_format._defineProperty(this, "findings", []);
|
|
1102
|
+
require_format._defineProperty(this, "byNum", /* @__PURE__ */ new Map());
|
|
1103
|
+
require_format._defineProperty(this, "before", void 0);
|
|
1104
|
+
require_format._defineProperty(this, "after", void 0);
|
|
1105
|
+
require_format._defineProperty(this, "claims", /* @__PURE__ */ new Map());
|
|
1106
|
+
require_format._defineProperty(this, "locked", /* @__PURE__ */ new Set());
|
|
1403
1107
|
for (const c of input.changes) this.byNum.set(c.objectNumber, c);
|
|
1404
1108
|
this.before = indexRoles(input.before);
|
|
1405
1109
|
this.after = indexRoles(input.after);
|
|
@@ -1498,9 +1202,9 @@ var StepContext = class {
|
|
|
1498
1202
|
const out = [];
|
|
1499
1203
|
for (const sig of this.input.after.signatures) {
|
|
1500
1204
|
if (!sig.signed || sig.field.kind !== "objectNumber") continue;
|
|
1501
|
-
if (this.before.signedFields.has(sig.field.
|
|
1205
|
+
if (this.before.signedFields.has(sig.field.objectNumber)) continue;
|
|
1502
1206
|
out.push({
|
|
1503
|
-
fieldObjectNumber: sig.field.
|
|
1207
|
+
fieldObjectNumber: sig.field.objectNumber,
|
|
1504
1208
|
sig
|
|
1505
1209
|
});
|
|
1506
1210
|
}
|
|
@@ -1977,7 +1681,7 @@ function ruleUnexplained(ctx) {
|
|
|
1977
1681
|
//#endregion
|
|
1978
1682
|
//#region src/signature/analysis/restrictions.ts
|
|
1979
1683
|
/**
|
|
1980
|
-
* The restrictions a window is judged under, read from the
|
|
1684
|
+
* The restrictions a window is judged under, read from the sealed
|
|
1981
1685
|
* revision's structure (what that revision declared, not what the final
|
|
1982
1686
|
* file says).
|
|
1983
1687
|
*
|
|
@@ -1987,7 +1691,7 @@ function ruleUnexplained(ctx) {
|
|
|
1987
1691
|
* Every certification's level, own or earlier, applies (inherited:
|
|
1988
1692
|
* conservative until observed otherwise), as does a /Lock's /P.
|
|
1989
1693
|
* - no `judged` (a revision-anchored analysis): every signed signature's
|
|
1990
|
-
* locks and levels
|
|
1694
|
+
* locks and levels apply.
|
|
1991
1695
|
*/
|
|
1992
1696
|
function restrictionsFor(before, judged) {
|
|
1993
1697
|
const anchors = [];
|
|
@@ -2073,9 +1777,9 @@ var EdgeResolver = class {
|
|
|
2073
1777
|
this.read = read;
|
|
2074
1778
|
this.anchors = anchors;
|
|
2075
1779
|
this.budget = budget;
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
1780
|
+
require_format._defineProperty(this, "memo", /* @__PURE__ */ new Map());
|
|
1781
|
+
require_format._defineProperty(this, "reads", 0);
|
|
1782
|
+
require_format._defineProperty(this, "exhausted", false);
|
|
2079
1783
|
}
|
|
2080
1784
|
/** Anchored edges of `objectNumber`, or `incomplete` when a budget was exceeded. */
|
|
2081
1785
|
resolve(objectNumber) {
|
|
@@ -2126,199 +1830,18 @@ var EdgeResolver = class {
|
|
|
2126
1830
|
}
|
|
2127
1831
|
};
|
|
2128
1832
|
//#endregion
|
|
2129
|
-
//#region src/search/
|
|
2130
|
-
/**
|
|
2131
|
-
|
|
2132
|
-
* folded with the same options; corpus caches key their pre-folded text
|
|
2133
|
-
* on this (the default `{}` fold is the persistable one — non-default
|
|
2134
|
-
* queries fold the original page text at query time).
|
|
2135
|
-
*/
|
|
2136
|
-
function foldOptionsFor(query) {
|
|
1833
|
+
//#region src/search/types.ts
|
|
1834
|
+
/** The query part of a request (or of any object that carries one): its text and flags, set flags only. */
|
|
1835
|
+
function searchQueryOf(query) {
|
|
2137
1836
|
return {
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
1837
|
+
text: query.text,
|
|
1838
|
+
...query.regex ? { regex: true } : {},
|
|
1839
|
+
...query.matchCase ? { matchCase: true } : {},
|
|
1840
|
+
...query.wholeWord ? { wholeWord: true } : {},
|
|
1841
|
+
...query.matchDiacritics ? { matchDiacritics: true } : {},
|
|
1842
|
+
...query.ignoreWhitespace ? { ignoreWhitespace: true } : {}
|
|
2141
1843
|
};
|
|
2142
1844
|
}
|
|
2143
|
-
const WORD_UNIT = /[\p{L}\p{N}_]/u;
|
|
2144
|
-
const MARK = /\p{M}/u;
|
|
2145
|
-
/** Whether the code point ENDING at `index` (exclusive) is a word char. */
|
|
2146
|
-
function wordBefore(text, index) {
|
|
2147
|
-
if (index <= 0) return false;
|
|
2148
|
-
const unit = text.charCodeAt(index - 1);
|
|
2149
|
-
const start = unit >= 56320 && unit <= 57343 && index >= 2 ? index - 2 : index - 1;
|
|
2150
|
-
return WORD_UNIT.test(String.fromCodePoint(text.codePointAt(start)));
|
|
2151
|
-
}
|
|
2152
|
-
/** Whether the code point starting at `index` is a word char. */
|
|
2153
|
-
function wordAt(text, index) {
|
|
2154
|
-
if (index >= text.length) return false;
|
|
2155
|
-
return WORD_UNIT.test(String.fromCodePoint(text.codePointAt(index)));
|
|
2156
|
-
}
|
|
2157
|
-
/**
|
|
2158
|
-
* Whether the folded hit at `at` sits on word boundaries. Checked on the
|
|
2159
|
-
* folded plane, except under `ignoreWhitespace`: dropping whitespace glues
|
|
2160
|
-
* neighbouring words together ("i n v o i c e 42" folds to "invoice42"), so there the
|
|
2161
|
-
* boundaries are read off the ORIGINAL text around the mapped range.
|
|
2162
|
-
*/
|
|
2163
|
-
function isWholeWordHit(haystack, at, needleLength, query) {
|
|
2164
|
-
if (!query.ignoreWhitespace) return !wordBefore(haystack.folded, at) && !wordAt(haystack.folded, at + needleLength);
|
|
2165
|
-
const { start, length } = require_derive.toOriginalRange(haystack, at, needleLength);
|
|
2166
|
-
return !wordBefore(haystack.original, start) && !wordAt(haystack.original, start + length);
|
|
2167
|
-
}
|
|
2168
|
-
/**
|
|
2169
|
-
* All non-overlapping literal matches, in original code-unit space.
|
|
2170
|
-
* `haystack` must have been folded with `foldOptionsFor(query)`.
|
|
2171
|
-
*/
|
|
2172
|
-
function matchLiteral(haystack, query) {
|
|
2173
|
-
const needle = require_derive.foldText(query.text, foldOptionsFor(query)).folded;
|
|
2174
|
-
if (needle.trim().length === 0) return [];
|
|
2175
|
-
const out = [];
|
|
2176
|
-
let from = 0;
|
|
2177
|
-
while (from <= haystack.folded.length - needle.length) {
|
|
2178
|
-
const at = haystack.folded.indexOf(needle, from);
|
|
2179
|
-
if (at < 0) break;
|
|
2180
|
-
if (query.wholeWord && !isWholeWordHit(haystack, at, needle.length, query)) {
|
|
2181
|
-
from = at + 1;
|
|
2182
|
-
continue;
|
|
2183
|
-
}
|
|
2184
|
-
if (query.matchDiacritics && at + needle.length < haystack.folded.length) {
|
|
2185
|
-
const after = haystack.folded.codePointAt(at + needle.length);
|
|
2186
|
-
if (MARK.test(String.fromCodePoint(after))) {
|
|
2187
|
-
from = at + 1;
|
|
2188
|
-
continue;
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
out.push(require_derive.toOriginalRange(haystack, at, needle.length));
|
|
2192
|
-
from = at + needle.length;
|
|
2193
|
-
}
|
|
2194
|
-
return out;
|
|
2195
|
-
}
|
|
2196
|
-
//#endregion
|
|
2197
|
-
//#region src/search/regex.ts
|
|
2198
|
-
/**
|
|
2199
|
-
* The portable search-regex dialect: JavaScript `u`-mode syntax MINUS the
|
|
2200
|
-
* features RE2 refuses (backreferences, lookaround). The local engine
|
|
2201
|
-
* executes patterns with JS `RegExp`; the server executes the SAME
|
|
2202
|
-
* pattern with RE2, whose linear-time guarantee is the ReDoS defense.
|
|
2203
|
-
* Restricting both sides to the common subset keeps one query string
|
|
2204
|
-
* valid — and equally powerful — everywhere.
|
|
2205
|
-
*/
|
|
2206
|
-
const SEARCH_REGEX_MAX_LENGTH = 512;
|
|
2207
|
-
/**
|
|
2208
|
-
* Validate a pattern against the dialect. Cheap and dependency-free —
|
|
2209
|
-
* viewers call it on keystroke for early feedback; engines re-validate
|
|
2210
|
-
* and reject bad patterns with `InvalidArg`.
|
|
2211
|
-
*/
|
|
2212
|
-
function validateSearchRegex(pattern) {
|
|
2213
|
-
if (pattern.length === 0) return {
|
|
2214
|
-
ok: false,
|
|
2215
|
-
issue: "empty",
|
|
2216
|
-
message: "Pattern is empty."
|
|
2217
|
-
};
|
|
2218
|
-
if (pattern.length > 512) return {
|
|
2219
|
-
ok: false,
|
|
2220
|
-
issue: "too-long",
|
|
2221
|
-
message: `Pattern exceeds 512 characters.`
|
|
2222
|
-
};
|
|
2223
|
-
let inClass = false;
|
|
2224
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
2225
|
-
const ch = pattern[i];
|
|
2226
|
-
if (ch === "\\") {
|
|
2227
|
-
const next = pattern[i + 1] ?? "";
|
|
2228
|
-
if (!inClass && next >= "1" && next <= "9") return {
|
|
2229
|
-
ok: false,
|
|
2230
|
-
issue: "backreference",
|
|
2231
|
-
message: `Backreference \\${next} is not supported.`
|
|
2232
|
-
};
|
|
2233
|
-
if (!inClass && next === "k" && pattern[i + 2] === "<") return {
|
|
2234
|
-
ok: false,
|
|
2235
|
-
issue: "backreference",
|
|
2236
|
-
message: "Named backreferences (\\k<…>) are not supported."
|
|
2237
|
-
};
|
|
2238
|
-
i++;
|
|
2239
|
-
continue;
|
|
2240
|
-
}
|
|
2241
|
-
if (inClass) {
|
|
2242
|
-
if (ch === "]") inClass = false;
|
|
2243
|
-
continue;
|
|
2244
|
-
}
|
|
2245
|
-
if (ch === "[") {
|
|
2246
|
-
inClass = true;
|
|
2247
|
-
continue;
|
|
2248
|
-
}
|
|
2249
|
-
if (ch === "(" && pattern[i + 1] === "?") {
|
|
2250
|
-
const tag = pattern[i + 2] ?? "";
|
|
2251
|
-
if (tag === "=" || tag === "!") return {
|
|
2252
|
-
ok: false,
|
|
2253
|
-
issue: "lookaround",
|
|
2254
|
-
message: "Lookahead ((?=…), (?!…)) is not supported."
|
|
2255
|
-
};
|
|
2256
|
-
if (tag === "<" && (pattern[i + 3] === "=" || pattern[i + 3] === "!")) return {
|
|
2257
|
-
ok: false,
|
|
2258
|
-
issue: "lookaround",
|
|
2259
|
-
message: "Lookbehind ((?<=…), (?<!…)) is not supported."
|
|
2260
|
-
};
|
|
2261
|
-
}
|
|
2262
|
-
}
|
|
2263
|
-
try {
|
|
2264
|
-
new RegExp(pattern, "mu");
|
|
2265
|
-
} catch (error) {
|
|
2266
|
-
return {
|
|
2267
|
-
ok: false,
|
|
2268
|
-
issue: "syntax",
|
|
2269
|
-
message: error.message
|
|
2270
|
-
};
|
|
2271
|
-
}
|
|
2272
|
-
return { ok: true };
|
|
2273
|
-
}
|
|
2274
|
-
function validateSearchQuery(query) {
|
|
2275
|
-
if (!query.regex) return { ok: true };
|
|
2276
|
-
if (query.matchDiacritics) return {
|
|
2277
|
-
ok: false,
|
|
2278
|
-
issue: "diacritics-with-regex",
|
|
2279
|
-
message: "Diacritic-sensitive matching is not available for regex patterns (regex runs on the raw text plane)."
|
|
2280
|
-
};
|
|
2281
|
-
if (query.ignoreWhitespace) return {
|
|
2282
|
-
ok: false,
|
|
2283
|
-
issue: "ignore-whitespace-with-regex",
|
|
2284
|
-
message: "Whitespace-insensitive matching is not available for regex patterns (regex runs on the raw text plane; use \\s* in the pattern)."
|
|
2285
|
-
};
|
|
2286
|
-
return validateSearchRegex(query.text);
|
|
2287
|
-
}
|
|
2288
|
-
/**
|
|
2289
|
-
* All matches of a dialect-valid pattern over the RAW page text (regex
|
|
2290
|
-
* does not run against folded text — case handling is the `i` flag, and
|
|
2291
|
-
* diacritic folding never applies). `wholeWord` is a boundary POST-FILTER
|
|
2292
|
-
* using the same Unicode word test as the literal path — never `\b`,
|
|
2293
|
-
* whose ASCII word set would give the toggle different semantics in regex
|
|
2294
|
-
* mode ("caf" whole-word matching inside "café"). Filtering after the
|
|
2295
|
-
* match also survives the move to RE2 server-side. Zero-length matches
|
|
2296
|
-
* are skipped: search UI cannot highlight nothing, and skipping them is
|
|
2297
|
-
* also the infinite-loop guard for patterns like `a*`.
|
|
2298
|
-
*/
|
|
2299
|
-
function matchRegex(text, query) {
|
|
2300
|
-
const valid = validateSearchQuery({
|
|
2301
|
-
...query,
|
|
2302
|
-
regex: true
|
|
2303
|
-
});
|
|
2304
|
-
if (!valid.ok) throw new Error(`Invalid search query (${valid.issue}): ${valid.message}`);
|
|
2305
|
-
const re = new RegExp(query.text, query.matchCase ? "gmu" : "gimu");
|
|
2306
|
-
const out = [];
|
|
2307
|
-
let m;
|
|
2308
|
-
while ((m = re.exec(text)) !== null) {
|
|
2309
|
-
if (m[0].length === 0) {
|
|
2310
|
-
const unit = text.charCodeAt(re.lastIndex);
|
|
2311
|
-
re.lastIndex += unit >= 55296 && unit <= 56319 ? 2 : 1;
|
|
2312
|
-
continue;
|
|
2313
|
-
}
|
|
2314
|
-
if (query.wholeWord && (wordBefore(text, m.index) || wordAt(text, m.index + m[0].length))) continue;
|
|
2315
|
-
out.push({
|
|
2316
|
-
start: m.index,
|
|
2317
|
-
length: m[0].length
|
|
2318
|
-
});
|
|
2319
|
-
}
|
|
2320
|
-
return out;
|
|
2321
|
-
}
|
|
2322
1845
|
//#endregion
|
|
2323
1846
|
//#region src/search/matcher.ts
|
|
2324
1847
|
/**
|
|
@@ -2329,8 +1852,8 @@ function matchRegex(text, query) {
|
|
|
2329
1852
|
* here.
|
|
2330
1853
|
*/
|
|
2331
1854
|
function matchPageText(text, query) {
|
|
2332
|
-
if (query.regex) return matchRegex(text, query);
|
|
2333
|
-
return matchLiteral(
|
|
1855
|
+
if (query.regex) return require_viewport.matchRegex(text, query);
|
|
1856
|
+
return require_viewport.matchLiteral(require_calibrate.foldText(text, require_viewport.foldOptionsFor(query)), query);
|
|
2334
1857
|
}
|
|
2335
1858
|
//#endregion
|
|
2336
1859
|
//#region src/search/snippet.ts
|
|
@@ -2343,13 +1866,13 @@ const isLowSurrogate = (text, index) => {
|
|
|
2343
1866
|
return unit >= 56320 && unit <= 57343;
|
|
2344
1867
|
};
|
|
2345
1868
|
/**
|
|
2346
|
-
* The
|
|
2347
|
-
* of page text on each side, trimmed to a whitespace boundary when one
|
|
1869
|
+
* The excerpt around one match (`snippets: true`): up to `context` code
|
|
1870
|
+
* units of page text on each side, trimmed to a whitespace boundary when one
|
|
2348
1871
|
* exists inside the window (so snippets start and end on whole words),
|
|
2349
|
-
* never splitting a surrogate pair, whitespace flattened
|
|
1872
|
+
* never splitting a surrogate pair, whitespace flattened to spaces.
|
|
2350
1873
|
*/
|
|
2351
1874
|
function buildSnippet(text, range, context = 48) {
|
|
2352
|
-
const matchEnd = range.start + range.
|
|
1875
|
+
const matchEnd = range.start + range.count;
|
|
2353
1876
|
let start = Math.max(0, range.start - context);
|
|
2354
1877
|
if (start > 0) {
|
|
2355
1878
|
for (let i = start; i < range.start; i++) if (WHITESPACE.test(text[i])) {
|
|
@@ -2366,484 +1889,31 @@ function buildSnippet(text, range, context = 48) {
|
|
|
2366
1889
|
}
|
|
2367
1890
|
if (isLowSurrogate(text, end)) end--;
|
|
2368
1891
|
}
|
|
1892
|
+
const flat = (from, to) => text.slice(from, to).replace(WHITESPACE_ALL, " ");
|
|
2369
1893
|
return {
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
1894
|
+
before: flat(start, range.start),
|
|
1895
|
+
match: flat(range.start, matchEnd),
|
|
1896
|
+
after: flat(matchEnd, end)
|
|
2373
1897
|
};
|
|
2374
1898
|
}
|
|
2375
1899
|
//#endregion
|
|
2376
|
-
//#region src/text/layout.ts
|
|
2377
|
-
const FLAG_EMPTY = 2;
|
|
2378
|
-
const isBoundary = (flags) => (flags & 3) !== 0;
|
|
2379
|
-
const isEmpty = (flags) => (flags & FLAG_EMPTY) !== 0;
|
|
2380
|
-
const CHAR_DISTANCE_FACTOR = 2.5;
|
|
2381
|
-
const FONT_SIZE_RATIO_THRESHOLD = 1.5;
|
|
2382
|
-
const VERTICAL_OVERLAP_THRESHOLD = .8;
|
|
2383
|
-
const LINE_OVERLAP_THRESHOLD = .5;
|
|
2384
|
-
/** Baseline directions within ~0.5° share a frame. */
|
|
2385
|
-
const FRAME_DOT_TOLERANCE = Math.cos(.0087);
|
|
2386
|
-
const EDGE_EPSILON = 1e-6;
|
|
2387
|
-
const IDENTITY_FRAME = {
|
|
2388
|
-
baseline: {
|
|
2389
|
-
x: 1,
|
|
2390
|
-
y: 0
|
|
2391
|
-
},
|
|
2392
|
-
ascent: {
|
|
2393
|
-
x: 0,
|
|
2394
|
-
y: 1
|
|
2395
|
-
}
|
|
2396
|
-
};
|
|
2397
|
-
const toFrame = (f, p) => ({
|
|
2398
|
-
x: p.x * f.baseline.x + p.y * f.baseline.y,
|
|
2399
|
-
y: p.x * f.ascent.x + p.y * f.ascent.y
|
|
2400
|
-
});
|
|
2401
|
-
const fromFrame = (f, p) => ({
|
|
2402
|
-
x: f.baseline.x * p.x + f.ascent.x * p.y,
|
|
2403
|
-
y: f.baseline.y * p.x + f.ascent.y * p.y
|
|
2404
|
-
});
|
|
2405
|
-
const ZERO_RECT = {
|
|
2406
|
-
left: 0,
|
|
2407
|
-
bottom: 0,
|
|
2408
|
-
right: 0,
|
|
2409
|
-
top: 0
|
|
2410
|
-
};
|
|
2411
|
-
/** Frame-local AABB of a page-space cell (exact under the frame's rotation;
|
|
2412
|
-
* shear residue is the documented in-frame envelope). */
|
|
2413
|
-
function frameBoxOfQuad(f, q) {
|
|
2414
|
-
const pts = [
|
|
2415
|
-
q.p1,
|
|
2416
|
-
q.p2,
|
|
2417
|
-
q.p3,
|
|
2418
|
-
q.p4
|
|
2419
|
-
].map((p) => toFrame(f, p));
|
|
2420
|
-
const xs = pts.map((p) => p.x);
|
|
2421
|
-
const ys = pts.map((p) => p.y);
|
|
2422
|
-
return {
|
|
2423
|
-
left: Math.min(...xs),
|
|
2424
|
-
bottom: Math.min(...ys),
|
|
2425
|
-
right: Math.max(...xs),
|
|
2426
|
-
top: Math.max(...ys)
|
|
2427
|
-
};
|
|
2428
|
-
}
|
|
2429
|
-
/** Find-or-create the frame for a rotated run, keyed by the baseline
|
|
2430
|
-
* direction + ascent handedness of its first classifiable glyph's edges. */
|
|
2431
|
-
function frameForRun(frames, run) {
|
|
2432
|
-
const seed = run.glyphs.find((g) => !isEmpty(g.flags));
|
|
2433
|
-
if (!seed) return 0;
|
|
2434
|
-
const q = seed.looseQuad;
|
|
2435
|
-
const bx = q.p2.x - q.p1.x;
|
|
2436
|
-
const by = q.p2.y - q.p1.y;
|
|
2437
|
-
const len = Math.hypot(bx, by);
|
|
2438
|
-
if (len <= EDGE_EPSILON) return 0;
|
|
2439
|
-
const baseline = {
|
|
2440
|
-
x: bx / len,
|
|
2441
|
-
y: by / len
|
|
2442
|
-
};
|
|
2443
|
-
const ax = q.p1.x - q.p3.x;
|
|
2444
|
-
const ay = q.p1.y - q.p3.y;
|
|
2445
|
-
const sign = baseline.x * ay - baseline.y * ax >= 0 ? 1 : -1;
|
|
2446
|
-
const ascent = {
|
|
2447
|
-
x: -baseline.y * sign,
|
|
2448
|
-
y: baseline.x * sign
|
|
2449
|
-
};
|
|
2450
|
-
for (let i = 0; i < frames.length; i++) {
|
|
2451
|
-
const f = frames[i];
|
|
2452
|
-
const dot = f.baseline.x * baseline.x + f.baseline.y * baseline.y;
|
|
2453
|
-
const sameHandedness = f.ascent.x * ascent.x + f.ascent.y * ascent.y > 0;
|
|
2454
|
-
if (dot >= FRAME_DOT_TOLERANCE && sameHandedness) return i;
|
|
2455
|
-
}
|
|
2456
|
-
frames.push({
|
|
2457
|
-
baseline,
|
|
2458
|
-
ascent
|
|
2459
|
-
});
|
|
2460
|
-
return frames.length - 1;
|
|
2461
|
-
}
|
|
2462
|
-
/**
|
|
2463
|
-
* Flatten a page's geometry snapshot into the canonical layout. Upright runs
|
|
2464
|
-
* copy their wire boxes verbatim (frame 0 — byte-identical to the
|
|
2465
|
-
* pre-orientation behavior, wire run rects included); rotated runs project
|
|
2466
|
-
* their glyph cells into their cluster's frame.
|
|
2467
|
-
*/
|
|
2468
|
-
function buildPageTextLayout(snapshot) {
|
|
2469
|
-
const glyphs = [];
|
|
2470
|
-
const runs = [];
|
|
2471
|
-
const frames = [IDENTITY_FRAME];
|
|
2472
|
-
for (const run of snapshot.runs) {
|
|
2473
|
-
if (!require_derive.isRotatedGeometryRun(run)) {
|
|
2474
|
-
for (const g of run.glyphs) glyphs.push({
|
|
2475
|
-
loose: g.looseBox,
|
|
2476
|
-
tight: g.tightBox,
|
|
2477
|
-
flags: g.flags
|
|
2478
|
-
});
|
|
2479
|
-
runs.push({
|
|
2480
|
-
charStart: run.charStart,
|
|
2481
|
-
count: run.glyphs.length,
|
|
2482
|
-
rect: run.rect,
|
|
2483
|
-
fontSize: run.fontSize,
|
|
2484
|
-
frame: 0
|
|
2485
|
-
});
|
|
2486
|
-
continue;
|
|
2487
|
-
}
|
|
2488
|
-
const frame = frameForRun(frames, run);
|
|
2489
|
-
const f = frames[frame];
|
|
2490
|
-
let runBox = null;
|
|
2491
|
-
for (const g of run.glyphs) {
|
|
2492
|
-
if (isEmpty(g.flags)) {
|
|
2493
|
-
glyphs.push({
|
|
2494
|
-
loose: ZERO_RECT,
|
|
2495
|
-
flags: g.flags
|
|
2496
|
-
});
|
|
2497
|
-
continue;
|
|
2498
|
-
}
|
|
2499
|
-
const loose = frameBoxOfQuad(f, g.looseQuad);
|
|
2500
|
-
const tight = g.tightQuad ? frameBoxOfQuad(f, g.tightQuad) : void 0;
|
|
2501
|
-
glyphs.push({
|
|
2502
|
-
loose,
|
|
2503
|
-
tight,
|
|
2504
|
-
flags: g.flags
|
|
2505
|
-
});
|
|
2506
|
-
runBox = runBox ? {
|
|
2507
|
-
left: Math.min(runBox.left, loose.left),
|
|
2508
|
-
bottom: Math.min(runBox.bottom, loose.bottom),
|
|
2509
|
-
right: Math.max(runBox.right, loose.right),
|
|
2510
|
-
top: Math.max(runBox.top, loose.top)
|
|
2511
|
-
} : loose;
|
|
2512
|
-
}
|
|
2513
|
-
runs.push({
|
|
2514
|
-
charStart: run.charStart,
|
|
2515
|
-
count: run.glyphs.length,
|
|
2516
|
-
rect: runBox ?? ZERO_RECT,
|
|
2517
|
-
fontSize: run.fontSize,
|
|
2518
|
-
frame
|
|
2519
|
-
});
|
|
2520
|
-
}
|
|
2521
|
-
return {
|
|
2522
|
-
glyphs,
|
|
2523
|
-
runs,
|
|
2524
|
-
frames
|
|
2525
|
-
};
|
|
2526
|
-
}
|
|
2527
|
-
const inRect = (r, p) => p.x >= r.left && p.x <= r.right && p.y >= r.bottom && p.y <= r.top;
|
|
2528
|
-
function avgGlyphHeight(layout) {
|
|
2529
|
-
let total = 0;
|
|
2530
|
-
let count = 0;
|
|
2531
|
-
for (const g of layout.glyphs) {
|
|
2532
|
-
if (isEmpty(g.flags)) continue;
|
|
2533
|
-
total += g.loose.top - g.loose.bottom;
|
|
2534
|
-
count++;
|
|
2535
|
-
}
|
|
2536
|
-
return count === 0 ? 0 : total / count;
|
|
2537
|
-
}
|
|
2538
|
-
/** The point expressed in every frame (index-aligned with `layout.frames`).
|
|
2539
|
-
* Frame 0 returns the point itself — no float round-trip on the fast path. */
|
|
2540
|
-
function pointPerFrame(layout, p) {
|
|
2541
|
-
return layout.frames.map((f, i) => i === 0 ? p : toFrame(f, p));
|
|
2542
|
-
}
|
|
2543
|
-
/**
|
|
2544
|
-
* The glyph (char) index at a page-space point, or null when nothing is near
|
|
2545
|
-
* (so callers can show the pointer cursor off-text). PDFium `GetIndexAtPos`:
|
|
2546
|
-
* exact tight-box containment first, then a tolerance pass (closest by
|
|
2547
|
-
* Manhattan distance within `toleranceFactor × average glyph height`). Each
|
|
2548
|
-
* run tests the point in ITS OWN frame, so rotated text hit-tests exactly.
|
|
2549
|
-
*/
|
|
2550
|
-
function textGlyphAt(layout, point, toleranceFactor = 1.5) {
|
|
2551
|
-
const pts = pointPerFrame(layout, point);
|
|
2552
|
-
for (const run of layout.runs) {
|
|
2553
|
-
const q = pts[run.frame];
|
|
2554
|
-
if (!inRect(run.rect, q)) continue;
|
|
2555
|
-
for (let i = 0; i < run.count; i++) {
|
|
2556
|
-
const g = layout.glyphs[run.charStart + i];
|
|
2557
|
-
if (inRect(g.tight ?? g.loose, q)) return run.charStart + i;
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
if (toleranceFactor <= 0) return null;
|
|
2561
|
-
const half = avgGlyphHeight(layout) * toleranceFactor / 2;
|
|
2562
|
-
let best = -1;
|
|
2563
|
-
let bestDist = Infinity;
|
|
2564
|
-
for (const run of layout.runs) {
|
|
2565
|
-
const q = pts[run.frame];
|
|
2566
|
-
const r = run.rect;
|
|
2567
|
-
if (q.x < r.left - half || q.x > r.right + half || q.y < r.bottom - half || q.y > r.top + half) continue;
|
|
2568
|
-
for (let i = 0; i < run.count; i++) {
|
|
2569
|
-
const g = layout.glyphs[run.charStart + i];
|
|
2570
|
-
if (isEmpty(g.flags)) continue;
|
|
2571
|
-
const b = g.tight ?? g.loose;
|
|
2572
|
-
if (q.x < b.left - half || q.x > b.right + half || q.y < b.bottom - half || q.y > b.top + half) continue;
|
|
2573
|
-
const dx = Math.min(Math.abs(q.x - b.left), Math.abs(q.x - b.right));
|
|
2574
|
-
const dy = Math.min(Math.abs(q.y - b.bottom), Math.abs(q.y - b.top));
|
|
2575
|
-
if (dx + dy < bestDist) {
|
|
2576
|
-
bestDist = dx + dy;
|
|
2577
|
-
best = run.charStart + i;
|
|
2578
|
-
}
|
|
2579
|
-
}
|
|
2580
|
-
}
|
|
2581
|
-
return best >= 0 ? best : null;
|
|
2582
|
-
}
|
|
2583
|
-
/** Double-click: the word around `glyph` (walk to space/empty glyphs both ways). */
|
|
2584
|
-
function expandTextRangeToWord(layout, glyph) {
|
|
2585
|
-
const n = layout.glyphs.length;
|
|
2586
|
-
if (glyph < 0 || glyph >= n) return [glyph, glyph];
|
|
2587
|
-
let from = glyph;
|
|
2588
|
-
while (from > 0 && !isBoundary(layout.glyphs[from - 1].flags)) from--;
|
|
2589
|
-
let to = glyph;
|
|
2590
|
-
while (to < n - 1 && !isBoundary(layout.glyphs[to + 1].flags)) to++;
|
|
2591
|
-
return [from, to];
|
|
2592
|
-
}
|
|
2593
|
-
/** Triple-click: the full visual line — SAME-FRAME runs whose vertical extent
|
|
2594
|
-
* overlaps the anchor run's. A differently-oriented run is a line boundary. */
|
|
2595
|
-
function expandTextRangeToLine(layout, glyph) {
|
|
2596
|
-
const ri = layout.runs.findIndex((r) => glyph >= r.charStart && glyph < r.charStart + r.count);
|
|
2597
|
-
if (ri < 0) return [glyph, glyph];
|
|
2598
|
-
const anchor = layout.runs[ri];
|
|
2599
|
-
const bottom = anchor.rect.bottom;
|
|
2600
|
-
const top = anchor.rect.top;
|
|
2601
|
-
let from = anchor.charStart;
|
|
2602
|
-
let to = anchor.charStart + anchor.count - 1;
|
|
2603
|
-
for (let r = ri - 1; r >= 0; r--) {
|
|
2604
|
-
const run = layout.runs[r];
|
|
2605
|
-
if (isZero(run.rect)) continue;
|
|
2606
|
-
if (run.frame !== anchor.frame) break;
|
|
2607
|
-
if (!overlapV(run.rect.bottom, run.rect.top, bottom, top)) break;
|
|
2608
|
-
from = run.charStart;
|
|
2609
|
-
}
|
|
2610
|
-
for (let r = ri + 1; r < layout.runs.length; r++) {
|
|
2611
|
-
const run = layout.runs[r];
|
|
2612
|
-
if (isZero(run.rect)) continue;
|
|
2613
|
-
if (run.frame !== anchor.frame) break;
|
|
2614
|
-
if (!overlapV(run.rect.bottom, run.rect.top, bottom, top)) break;
|
|
2615
|
-
to = run.charStart + run.count - 1;
|
|
2616
|
-
}
|
|
2617
|
-
return [from, to];
|
|
2618
|
-
}
|
|
2619
|
-
/**
|
|
2620
|
-
* A single glyph's oriented cell in page space, or null for degenerate
|
|
2621
|
-
* glyphs — the anchor for caret placement at a selection boundary.
|
|
2622
|
-
*/
|
|
2623
|
-
function textGlyphQuad(layout, glyph) {
|
|
2624
|
-
const g = layout.glyphs[glyph];
|
|
2625
|
-
if (!g || isEmpty(g.flags)) return null;
|
|
2626
|
-
const b = g.loose;
|
|
2627
|
-
if (b.right <= b.left || b.top <= b.bottom) return null;
|
|
2628
|
-
const run = layout.runs.find((r) => glyph >= r.charStart && glyph < r.charStart + r.count);
|
|
2629
|
-
const f = layout.frames[run?.frame ?? 0];
|
|
2630
|
-
return quadOfFrameRect(f, run?.frame ?? 0, b);
|
|
2631
|
-
}
|
|
2632
|
-
/**
|
|
2633
|
-
* Merged visual-line segments for the half-open char range
|
|
2634
|
-
* `[charStart, charStart + charCount)` — THE canonical segmentation. Chars
|
|
2635
|
-
* outside the layout are ignored.
|
|
2636
|
-
*/
|
|
2637
|
-
function textSegmentsForRange(layout, charStart, charCount) {
|
|
2638
|
-
if (charCount <= 0 || layout.glyphs.length === 0) return [];
|
|
2639
|
-
const lo = Math.max(0, charStart);
|
|
2640
|
-
const hi = Math.min(layout.glyphs.length - 1, charStart + charCount - 1);
|
|
2641
|
-
if (hi < lo) return [];
|
|
2642
|
-
const subRuns = [];
|
|
2643
|
-
for (const run of layout.runs) {
|
|
2644
|
-
const runEnd = run.charStart + run.count - 1;
|
|
2645
|
-
if (runEnd < lo || run.charStart > hi) continue;
|
|
2646
|
-
const s = Math.max(lo, run.charStart);
|
|
2647
|
-
const e = Math.min(hi, runEnd);
|
|
2648
|
-
let left = Infinity;
|
|
2649
|
-
let right = -Infinity;
|
|
2650
|
-
let bottom = Infinity;
|
|
2651
|
-
let top = -Infinity;
|
|
2652
|
-
let charCountAcc = 0;
|
|
2653
|
-
let widthSum = 0;
|
|
2654
|
-
let prevRight = -Infinity;
|
|
2655
|
-
let firstX = 0;
|
|
2656
|
-
let lastX = 0;
|
|
2657
|
-
const flush = () => {
|
|
2658
|
-
if (charCountAcc > 0 && left !== Infinity) subRuns.push({
|
|
2659
|
-
rect: {
|
|
2660
|
-
left,
|
|
2661
|
-
bottom,
|
|
2662
|
-
right,
|
|
2663
|
-
top
|
|
2664
|
-
},
|
|
2665
|
-
charCount: charCountAcc,
|
|
2666
|
-
fontSize: run.fontSize,
|
|
2667
|
-
frame: run.frame,
|
|
2668
|
-
firstX,
|
|
2669
|
-
lastX
|
|
2670
|
-
});
|
|
2671
|
-
left = Infinity;
|
|
2672
|
-
right = -Infinity;
|
|
2673
|
-
bottom = Infinity;
|
|
2674
|
-
top = -Infinity;
|
|
2675
|
-
charCountAcc = 0;
|
|
2676
|
-
widthSum = 0;
|
|
2677
|
-
prevRight = -Infinity;
|
|
2678
|
-
};
|
|
2679
|
-
for (let ci = s; ci <= e; ci++) {
|
|
2680
|
-
const g = layout.glyphs[ci];
|
|
2681
|
-
if (isEmpty(g.flags)) continue;
|
|
2682
|
-
const b = g.loose;
|
|
2683
|
-
if (charCountAcc > 0 && prevRight > -Infinity) {
|
|
2684
|
-
const avg = widthSum / charCountAcc;
|
|
2685
|
-
if (avg > 0 && Math.abs(b.left - prevRight) > CHAR_DISTANCE_FACTOR * avg) flush();
|
|
2686
|
-
}
|
|
2687
|
-
const centerX = (b.left + b.right) / 2;
|
|
2688
|
-
if (charCountAcc === 0) firstX = centerX;
|
|
2689
|
-
lastX = centerX;
|
|
2690
|
-
left = Math.min(left, b.left);
|
|
2691
|
-
right = Math.max(right, b.right);
|
|
2692
|
-
bottom = Math.min(bottom, b.bottom);
|
|
2693
|
-
top = Math.max(top, b.top);
|
|
2694
|
-
charCountAcc++;
|
|
2695
|
-
widthSum += b.right - b.left;
|
|
2696
|
-
prevRight = b.right;
|
|
2697
|
-
}
|
|
2698
|
-
flush();
|
|
2699
|
-
}
|
|
2700
|
-
return mergeAdjacentSubRuns(subRuns).map((m) => materializeSegment(layout, m));
|
|
2701
|
-
}
|
|
2702
|
-
function mergeAdjacentSubRuns(runs) {
|
|
2703
|
-
const out = [];
|
|
2704
|
-
let prev = null;
|
|
2705
|
-
let cur = null;
|
|
2706
|
-
for (const run of runs) {
|
|
2707
|
-
if (prev && cur && prev.frame === run.frame && shouldMerge(prev, run)) cur = {
|
|
2708
|
-
rect: {
|
|
2709
|
-
left: Math.min(cur.rect.left, run.rect.left),
|
|
2710
|
-
bottom: Math.min(cur.rect.bottom, run.rect.bottom),
|
|
2711
|
-
right: Math.max(cur.rect.right, run.rect.right),
|
|
2712
|
-
top: Math.max(cur.rect.top, run.rect.top)
|
|
2713
|
-
},
|
|
2714
|
-
frame: cur.frame,
|
|
2715
|
-
firstX: cur.firstX,
|
|
2716
|
-
lastX: run.lastX
|
|
2717
|
-
};
|
|
2718
|
-
else {
|
|
2719
|
-
if (cur) out.push(cur);
|
|
2720
|
-
cur = {
|
|
2721
|
-
rect: run.rect,
|
|
2722
|
-
frame: run.frame,
|
|
2723
|
-
firstX: run.firstX,
|
|
2724
|
-
lastX: run.lastX
|
|
2725
|
-
};
|
|
2726
|
-
}
|
|
2727
|
-
prev = run;
|
|
2728
|
-
}
|
|
2729
|
-
if (cur && cur.rect.right > cur.rect.left && cur.rect.top > cur.rect.bottom) out.push(cur);
|
|
2730
|
-
return out;
|
|
2731
|
-
}
|
|
2732
|
-
/** Segment quad for a frame-local rect (frame 0: the rect's own corners,
|
|
2733
|
-
* no float round-trip). Slot order US, UE, LS, LE; frame is y-up, so the
|
|
2734
|
-
* upper corners sit at the frame TOP. */
|
|
2735
|
-
function quadOfFrameRect(f, frameIndex, r) {
|
|
2736
|
-
if (frameIndex === 0) return {
|
|
2737
|
-
p1: {
|
|
2738
|
-
x: r.left,
|
|
2739
|
-
y: r.top
|
|
2740
|
-
},
|
|
2741
|
-
p2: {
|
|
2742
|
-
x: r.right,
|
|
2743
|
-
y: r.top
|
|
2744
|
-
},
|
|
2745
|
-
p3: {
|
|
2746
|
-
x: r.left,
|
|
2747
|
-
y: r.bottom
|
|
2748
|
-
},
|
|
2749
|
-
p4: {
|
|
2750
|
-
x: r.right,
|
|
2751
|
-
y: r.bottom
|
|
2752
|
-
}
|
|
2753
|
-
};
|
|
2754
|
-
return {
|
|
2755
|
-
p1: fromFrame(f, {
|
|
2756
|
-
x: r.left,
|
|
2757
|
-
y: r.top
|
|
2758
|
-
}),
|
|
2759
|
-
p2: fromFrame(f, {
|
|
2760
|
-
x: r.right,
|
|
2761
|
-
y: r.top
|
|
2762
|
-
}),
|
|
2763
|
-
p3: fromFrame(f, {
|
|
2764
|
-
x: r.left,
|
|
2765
|
-
y: r.bottom
|
|
2766
|
-
}),
|
|
2767
|
-
p4: fromFrame(f, {
|
|
2768
|
-
x: r.right,
|
|
2769
|
-
y: r.bottom
|
|
2770
|
-
})
|
|
2771
|
-
};
|
|
2772
|
-
}
|
|
2773
|
-
function materializeSegment(layout, m) {
|
|
2774
|
-
const frame = layout.frames[m.frame];
|
|
2775
|
-
const quad = quadOfFrameRect(frame, m.frame, m.rect);
|
|
2776
|
-
return {
|
|
2777
|
-
quad,
|
|
2778
|
-
rect: m.frame === 0 ? m.rect : {
|
|
2779
|
-
left: Math.min(quad.p1.x, quad.p2.x, quad.p3.x, quad.p4.x),
|
|
2780
|
-
bottom: Math.min(quad.p1.y, quad.p2.y, quad.p3.y, quad.p4.y),
|
|
2781
|
-
right: Math.max(quad.p1.x, quad.p2.x, quad.p3.x, quad.p4.x),
|
|
2782
|
-
top: Math.max(quad.p1.y, quad.p2.y, quad.p3.y, quad.p4.y)
|
|
2783
|
-
},
|
|
2784
|
-
advance: m.lastX >= m.firstX ? 1 : -1
|
|
2785
|
-
};
|
|
2786
|
-
}
|
|
2787
|
-
function shouldMerge(a, b) {
|
|
2788
|
-
if (a.fontSize != null && b.fontSize != null && a.fontSize > 0 && b.fontSize > 0) {
|
|
2789
|
-
if (Math.max(a.fontSize, b.fontSize) / Math.min(a.fontSize, b.fontSize) > FONT_SIZE_RATIO_THRESHOLD) return false;
|
|
2790
|
-
}
|
|
2791
|
-
if (verticalOverlap(a.rect, b.rect) < VERTICAL_OVERLAP_THRESHOLD) return false;
|
|
2792
|
-
const aw = (a.rect.right - a.rect.left) / a.charCount;
|
|
2793
|
-
const bw = (b.rect.right - b.rect.left) / b.charCount;
|
|
2794
|
-
const aL = a.rect.left - aw;
|
|
2795
|
-
const aR = a.rect.right + aw;
|
|
2796
|
-
const bL = b.rect.left - bw;
|
|
2797
|
-
return aL < b.rect.right + bw && aR > bL;
|
|
2798
|
-
}
|
|
2799
|
-
function verticalOverlap(a, b) {
|
|
2800
|
-
const ah = a.top - a.bottom;
|
|
2801
|
-
const bh = b.top - b.bottom;
|
|
2802
|
-
if (ah <= 0 || bh <= 0) return 0;
|
|
2803
|
-
const u = Math.max(a.top, b.top) - Math.min(a.bottom, b.bottom);
|
|
2804
|
-
if (u === ah || u === bh) return 1;
|
|
2805
|
-
return Math.max(0, Math.min(a.top, b.top) - Math.max(a.bottom, b.bottom)) / u;
|
|
2806
|
-
}
|
|
2807
|
-
const isZero = (r) => r.right === r.left && r.top === r.bottom;
|
|
2808
|
-
function overlapV(bottom1, top1, bottom2, top2) {
|
|
2809
|
-
const u = Math.max(top1, top2) - Math.min(bottom1, bottom2);
|
|
2810
|
-
if (u === 0) return false;
|
|
2811
|
-
return Math.max(0, Math.min(top1, top2) - Math.max(bottom1, bottom2)) / u >= LINE_OVERLAP_THRESHOLD;
|
|
2812
|
-
}
|
|
2813
|
-
//#endregion
|
|
2814
|
-
//#region src/search/rects.ts
|
|
2815
|
-
/**
|
|
2816
|
-
* Match-range → canonical visual-line segments. Thin wrappers over the ONE
|
|
2817
|
-
* text layout (`src/text/layout.ts`) — search owns matching and cursors,
|
|
2818
|
-
* never segmentation, so a match highlights exactly like a selection of the
|
|
2819
|
-
* same characters. No frame or merge logic lives here.
|
|
2820
|
-
*/
|
|
2821
|
-
/** Canonical segments for `[charStart, charStart + charCount)`. */
|
|
2822
|
-
function searchSegmentsForRange(snapshot, charStart, charCount) {
|
|
2823
|
-
return textSegmentsForRange(buildPageTextLayout(snapshot), charStart, charCount);
|
|
2824
|
-
}
|
|
2825
|
-
/** The segments' AABBs — for consumers that genuinely want boxes. */
|
|
2826
|
-
function searchRectsForRange(snapshot, charStart, charCount) {
|
|
2827
|
-
return searchSegmentsForRange(snapshot, charStart, charCount).map((s) => s.rect);
|
|
2828
|
-
}
|
|
2829
|
-
//#endregion
|
|
2830
1900
|
//#region src/search/epoch.ts
|
|
2831
1901
|
/**
|
|
2832
|
-
* The search
|
|
1902
|
+
* The search content epoch: a deterministic fingerprint of everything a
|
|
2833
1903
|
* search result depends on — page order/structure (`layoutVersion`) and
|
|
2834
1904
|
* each page's text content (`contentVersion`), nothing else. Annotation
|
|
2835
|
-
* and metadata churn deliberately do
|
|
1905
|
+
* and metadata churn deliberately do not move it, so cached search
|
|
2836
1906
|
* responses in a collaborative document survive comment storms.
|
|
2837
1907
|
*
|
|
2838
1908
|
* Both sides compute it from the manifest they already hold: the client
|
|
2839
1909
|
* to mint versioned search URLs, the server to validate them (mismatch →
|
|
2840
1910
|
* NotFound, the standard stale-versioned-read signal). FNV-1a 64-bit —
|
|
2841
1911
|
* dependency-free and stable; not cryptographic, and doesn't need to be:
|
|
2842
|
-
* an adversary can only vary his
|
|
1912
|
+
* an adversary can only vary his own authorized query results.
|
|
2843
1913
|
*/
|
|
2844
1914
|
function searchContentEpoch(manifest) {
|
|
2845
1915
|
let input = `${manifest.layoutVersion}`;
|
|
2846
|
-
for (const page of manifest.pages) input += `|${page.
|
|
1916
|
+
for (const page of manifest.pages) input += `|${page.page.objectNumber}:${page.cache.contentVersion}`;
|
|
2847
1917
|
return fnv1a64(input);
|
|
2848
1918
|
}
|
|
2849
1919
|
const FNV_OFFSET = 14695981039346656037n;
|
|
@@ -2858,20 +1928,108 @@ function fnv1a64(input) {
|
|
|
2858
1928
|
return hash.toString(16).padStart(16, "0");
|
|
2859
1929
|
}
|
|
2860
1930
|
/**
|
|
2861
|
-
* Canonicalize a query for
|
|
1931
|
+
* Canonicalize a query for cache keying: default-fold literal queries are
|
|
2862
1932
|
* pre-folded ("Café", "café" and "CAFE" are the same search, so they
|
|
2863
1933
|
* should be the same cache entry). Semantics are unchanged — the fold is
|
|
2864
1934
|
* idempotent and exactly what the matcher applies to the needle anyway.
|
|
2865
1935
|
* Case- or diacritic-sensitive literals and regex patterns pass through
|
|
2866
|
-
* untouched (their raw form
|
|
1936
|
+
* untouched (their raw form is the query).
|
|
2867
1937
|
*/
|
|
2868
|
-
function canonicalSearchQuery(
|
|
1938
|
+
function canonicalSearchQuery(request) {
|
|
1939
|
+
const query = searchQueryOf(request);
|
|
2869
1940
|
if (query.regex || query.matchCase || query.matchDiacritics || query.ignoreWhitespace) return query;
|
|
2870
|
-
const canonical = { text:
|
|
1941
|
+
const canonical = { text: require_calibrate.foldText(query.text).folded };
|
|
2871
1942
|
if (query.wholeWord) canonical.wholeWord = true;
|
|
2872
1943
|
return canonical;
|
|
2873
1944
|
}
|
|
2874
1945
|
//#endregion
|
|
1946
|
+
//#region src/mutation/WriteOptions.ts
|
|
1947
|
+
/** What an `opId` may be: what an HTTP header carries (`Idempotency-Key`). */
|
|
1948
|
+
const OP_ID = /^[\x21-\x7e]{1,255}$/;
|
|
1949
|
+
/**
|
|
1950
|
+
* The `opId` a write runs under: the caller's, or a fresh one. The caller's
|
|
1951
|
+
* must be 1 to 255 visible ASCII characters, on every engine; anything else
|
|
1952
|
+
* is refused with `InvalidArg`.
|
|
1953
|
+
*/
|
|
1954
|
+
function opIdOf(options) {
|
|
1955
|
+
const opId = options?.opId;
|
|
1956
|
+
if (opId === void 0) return generateUuid();
|
|
1957
|
+
if (!OP_ID.test(opId)) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "opId must be 1 to 255 visible ASCII characters", { details: { field: "opId" } });
|
|
1958
|
+
return opId;
|
|
1959
|
+
}
|
|
1960
|
+
//#endregion
|
|
1961
|
+
//#region src/mutation/changeOutcome.ts
|
|
1962
|
+
/**
|
|
1963
|
+
* The refusals a change keeps under its `opId`, like a success: the document
|
|
1964
|
+
* or the caller refused it, so asking again gets the same answer, even once
|
|
1965
|
+
* the document has changed so that it would apply. Anything else (an abort, a
|
|
1966
|
+
* lost race with another writer, an engine failure) applied nothing, is not
|
|
1967
|
+
* kept, and may run again.
|
|
1968
|
+
*/
|
|
1969
|
+
const KEPT_REFUSALS = /* @__PURE__ */ new Set([
|
|
1970
|
+
require_format.EngineErrorCode.InvalidArg,
|
|
1971
|
+
require_format.EngineErrorCode.NotFound,
|
|
1972
|
+
require_format.EngineErrorCode.Forbidden,
|
|
1973
|
+
require_format.EngineErrorCode.ProtectedDocument,
|
|
1974
|
+
require_format.EngineErrorCode.MalformedPdf,
|
|
1975
|
+
require_format.EngineErrorCode.PayloadTooLarge,
|
|
1976
|
+
require_format.EngineErrorCode.ObjectNumberUnavailable,
|
|
1977
|
+
require_format.EngineErrorCode.LayerFull,
|
|
1978
|
+
require_format.EngineErrorCode.ChangeConflict,
|
|
1979
|
+
require_format.EngineErrorCode.UndoUnavailable
|
|
1980
|
+
]);
|
|
1981
|
+
/** Whether a change refused with `code` keeps that answer (see `KEPT_REFUSALS`). */
|
|
1982
|
+
function isKeptRefusal(code) {
|
|
1983
|
+
return KEPT_REFUSALS.has(code);
|
|
1984
|
+
}
|
|
1985
|
+
/**
|
|
1986
|
+
* What a retry under the same `opId` must send: the change's fingerprint. The
|
|
1987
|
+
* same ops with the same bytes give the same fingerprint whatever the order
|
|
1988
|
+
* of their keys; bytes count by their content.
|
|
1989
|
+
*/
|
|
1990
|
+
function changeFingerprint(change) {
|
|
1991
|
+
const text = canonicalJson(change);
|
|
1992
|
+
return `${text.length.toString(36)}-${hashText(text)}`;
|
|
1993
|
+
}
|
|
1994
|
+
/** `value` as JSON with every object's keys sorted, and bytes as their length and hash. */
|
|
1995
|
+
function canonicalJson(value) {
|
|
1996
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
1997
|
+
const bytes = value instanceof ArrayBuffer ? new Uint8Array(value) : new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
1998
|
+
return JSON.stringify({ $bytes: `${bytes.byteLength.toString(36)}-${hashBytes(bytes)}` });
|
|
1999
|
+
}
|
|
2000
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
2001
|
+
if (value !== null && typeof value === "object") return `{${Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
|
|
2002
|
+
return JSON.stringify(value) ?? "null";
|
|
2003
|
+
}
|
|
2004
|
+
/** A 53-bit hash (cyrb53) of a string's UTF-16 units, in base 36. */
|
|
2005
|
+
function hashText(text) {
|
|
2006
|
+
let h1 = 3735928559;
|
|
2007
|
+
let h2 = 1103547991;
|
|
2008
|
+
for (let i = 0; i < text.length; i++) {
|
|
2009
|
+
const unit = text.charCodeAt(i);
|
|
2010
|
+
h1 = Math.imul(h1 ^ unit, 2654435761);
|
|
2011
|
+
h2 = Math.imul(h2 ^ unit, 1597334677);
|
|
2012
|
+
}
|
|
2013
|
+
return finish(h1, h2);
|
|
2014
|
+
}
|
|
2015
|
+
/** The same hash over bytes. */
|
|
2016
|
+
function hashBytes(bytes) {
|
|
2017
|
+
let h1 = 3735928559;
|
|
2018
|
+
let h2 = 1103547991;
|
|
2019
|
+
for (const byte of bytes) {
|
|
2020
|
+
h1 = Math.imul(h1 ^ byte, 2654435761);
|
|
2021
|
+
h2 = Math.imul(h2 ^ byte, 1597334677);
|
|
2022
|
+
}
|
|
2023
|
+
return finish(h1, h2);
|
|
2024
|
+
}
|
|
2025
|
+
function finish(h1, h2) {
|
|
2026
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507);
|
|
2027
|
+
h1 ^= Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
2028
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507);
|
|
2029
|
+
h2 ^= Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
2030
|
+
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
|
|
2031
|
+
}
|
|
2032
|
+
//#endregion
|
|
2875
2033
|
//#region src/auth/scope/pdf-bits.ts
|
|
2876
2034
|
/**
|
|
2877
2035
|
* ISO 32000 user-access permission bit positions, expressed as integer
|
|
@@ -2927,144 +2085,153 @@ function decodePdfBits(raw) {
|
|
|
2927
2085
|
};
|
|
2928
2086
|
}
|
|
2929
2087
|
//#endregion
|
|
2930
|
-
//#region src/auth/scope/
|
|
2088
|
+
//#region src/auth/scope/authority.ts
|
|
2931
2089
|
/**
|
|
2932
|
-
*
|
|
2933
|
-
*
|
|
2934
|
-
*
|
|
2935
|
-
* caps.doc.text.copy() // "doc.text.copy"
|
|
2936
|
-
* caps.doc.download() // "doc.download"
|
|
2937
|
-
* caps.doc.download.flattened() // "doc.download.flattened"
|
|
2938
|
-
* caps.doc.print.high() // "doc.print.high"
|
|
2939
|
-
*
|
|
2940
|
-
* Each leaf is a function returning the literal string (as `const`) so
|
|
2941
|
-
* TypeScript catches typos at the call site. Wrappers like `download`
|
|
2942
|
-
* and `print` are `Object.assign`'d to be callable AND carry child
|
|
2943
|
-
* properties for the refinement capabilities.
|
|
2090
|
+
* Check that the caller may use `capability`: `ProtectedDocument` when a
|
|
2091
|
+
* signature in the document took it away, `PermissionDenied` when the
|
|
2092
|
+
* grants never gave it.
|
|
2944
2093
|
*/
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
}
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
pages: {
|
|
2957
|
-
modify: () => "doc.pages.modify",
|
|
2958
|
-
assemble: () => "doc.pages.assemble"
|
|
2959
|
-
},
|
|
2960
|
-
forms: {
|
|
2961
|
-
read: () => "doc.forms.read",
|
|
2962
|
-
fill: () => "doc.forms.fill",
|
|
2963
|
-
modify: () => "doc.forms.modify"
|
|
2964
|
-
},
|
|
2965
|
-
annotate: {
|
|
2966
|
-
read: () => "doc.annotate.read",
|
|
2967
|
-
modify: () => "doc.annotate.modify"
|
|
2968
|
-
},
|
|
2969
|
-
metadata: { modify: () => "doc.metadata.modify" },
|
|
2970
|
-
attachments: { modify: () => "doc.attachments.modify" },
|
|
2971
|
-
redact: () => "doc.redact"
|
|
2972
|
-
} };
|
|
2094
|
+
function authorizeCapability(authority, capability) {
|
|
2095
|
+
authorizeUnprotected(authority, capability);
|
|
2096
|
+
const { grants, protection } = authority;
|
|
2097
|
+
if (grants && !require_resolver.checkCapability(capability, grants.scope, grants.pdfBits, protection)) throw new require_resolver.PermissionDenied(capability, "target");
|
|
2098
|
+
}
|
|
2099
|
+
/** Whether the caller may use `capability`: what {@link authorizeCapability} checks, as a yes or no. */
|
|
2100
|
+
function allowsCapability(authority, capability) {
|
|
2101
|
+
const { grants, protection } = authority;
|
|
2102
|
+
if (protection && require_resolver.protectedCapabilities(protection).has(capability)) return false;
|
|
2103
|
+
return !grants || require_resolver.checkCapability(capability, grants.scope, grants.pdfBits, protection);
|
|
2104
|
+
}
|
|
2973
2105
|
/**
|
|
2974
|
-
*
|
|
2975
|
-
*
|
|
2976
|
-
*
|
|
2977
|
-
* collab.annotations.create.self() → "annotations:create:self"
|
|
2978
|
-
* collab.annotations.create.group("legal") → "annotations:create:group=legal"
|
|
2979
|
-
* collab.annotations.update.group("4") → "annotations:update:group=4"
|
|
2980
|
-
* collab.annotations.delete.createdBy("u-7") → "annotations:delete:createdBy=u-7"
|
|
2981
|
-
* collab.annotations.setGroup.group("legal") → "annotations:set-group:group=legal"
|
|
2982
|
-
* collab.annotations.all.all() → "annotations:*:all" (action wildcard)
|
|
2983
|
-
*
|
|
2984
|
-
* On create, the filter is evaluated against the caller's own identity
|
|
2985
|
-
* (no impersonation), so `:self` and `:all` trivially pass; `:group=X`
|
|
2986
|
-
* is the meaningful filter — it constrains creation to callers whose
|
|
2987
|
-
* default group is X.
|
|
2106
|
+
* Check only that no signature in the document took `capability` away
|
|
2107
|
+
* (`ProtectedDocument`). Annotation creates, updates and deletes take this
|
|
2108
|
+
* for `doc.annotate.modify`; their grants are checked per annotation.
|
|
2988
2109
|
*/
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
2110
|
+
function authorizeUnprotected(authority, capability) {
|
|
2111
|
+
const { protection } = authority;
|
|
2112
|
+
if (protection && require_resolver.protectedCapabilities(protection).has(capability)) throw new require_format.EngineError(require_format.EngineErrorCode.ProtectedDocument, require_resolver.describeProtection(capability, protection));
|
|
2113
|
+
}
|
|
2114
|
+
/**
|
|
2115
|
+
* The capability writing an annotation of `subtype` takes. A widget belongs
|
|
2116
|
+
* to a form field, so creating, changing, moving or deleting one is
|
|
2117
|
+
* designing the form: `doc.forms.modify`. The annotation scopes
|
|
2118
|
+
* (`annotations:*`) never apply to it, and it has no group of its own.
|
|
2119
|
+
*/
|
|
2120
|
+
function annotationWriteCapability(subtype) {
|
|
2121
|
+
return subtype === "widget" ? "doc.forms.modify" : "doc.annotate.modify";
|
|
2122
|
+
}
|
|
2123
|
+
/** The capabilities writing all of `annotations` takes, each once. */
|
|
2124
|
+
function annotationWriteCapabilities(annotations) {
|
|
2125
|
+
return [...new Set(annotations.map((annotation) => annotationWriteCapability(annotation.subtype)))];
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Check a widget write (see {@link annotationWriteCapability}): form design,
|
|
2129
|
+
* and no group to set. Returns the actor the write stamps: the editor.
|
|
2130
|
+
*/
|
|
2131
|
+
function authorizeWidgetWrite(authority, groupId) {
|
|
2132
|
+
const { identity, grants } = authority;
|
|
2133
|
+
if (grants && !require_resolver.checkCapability("doc.forms.modify", grants.scope, grants.pdfBits)) throw new require_resolver.PermissionDenied("doc.forms.modify", "target");
|
|
2134
|
+
if (typeof groupId === "string") throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "a widget has no group of its own: a form field's group is the field's");
|
|
2135
|
+
const actor = {
|
|
2136
|
+
...identity.userId !== void 0 ? { userId: identity.userId } : {},
|
|
2137
|
+
...identity.displayName !== void 0 ? { displayName: identity.displayName } : {}
|
|
3003
2138
|
};
|
|
2139
|
+
return actor.userId || actor.displayName ? actor : void 0;
|
|
3004
2140
|
}
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
2141
|
+
/**
|
|
2142
|
+
* Check a create of a `subtype` annotation in `groupId` (the identity's own
|
|
2143
|
+
* group without one) and return the actor the write stamps: the creator, in
|
|
2144
|
+
* that group. A group other than the identity's takes the authority a
|
|
2145
|
+
* reassignment takes. A widget takes form design instead, in no group.
|
|
2146
|
+
*/
|
|
2147
|
+
function authorizeAnnotationCreate(authority, subtype, groupId) {
|
|
2148
|
+
if (subtype === "widget") return authorizeWidgetWrite(authority, groupId);
|
|
2149
|
+
const { identity, grants } = authority;
|
|
2150
|
+
const group = groupId ?? identity.groupId;
|
|
2151
|
+
if (grants) {
|
|
2152
|
+
if (group !== void 0 && !require_resolver.checkSetGroup("annotations", group, identity.groupId, grants.scope)) throw new require_resolver.PermissionDenied(`annotations:set-group:group=${group}`, "target");
|
|
2153
|
+
if (!require_resolver.checkCollab("create", require_resolver.collabTargetOf({
|
|
2154
|
+
userId: identity.userId,
|
|
2155
|
+
groupId: group
|
|
2156
|
+
}), grants.scope, identity, grants.pdfBits)) throw new require_resolver.PermissionDenied("annotations:create", "target");
|
|
2157
|
+
}
|
|
2158
|
+
const actor = {
|
|
2159
|
+
...identity.userId !== void 0 ? { userId: identity.userId } : {},
|
|
2160
|
+
...group !== void 0 ? { groupId: group } : {},
|
|
2161
|
+
...identity.displayName !== void 0 ? { displayName: identity.displayName } : {}
|
|
3009
2162
|
};
|
|
2163
|
+
return actor.userId || actor.groupId || actor.displayName ? actor : void 0;
|
|
3010
2164
|
}
|
|
3011
2165
|
/**
|
|
3012
|
-
*
|
|
3013
|
-
*
|
|
3014
|
-
*
|
|
2166
|
+
* Check an update of the annotation `owner` describes and return the actor
|
|
2167
|
+
* the write stamps: the editor, and the group only when the patch reassigns
|
|
2168
|
+
* it. An existing group can be reassigned, never removed. A widget takes form
|
|
2169
|
+
* design instead, and its patch sets no group.
|
|
3015
2170
|
*/
|
|
3016
|
-
|
|
2171
|
+
function authorizeAnnotationUpdate(authority, owner, patchGroupId) {
|
|
2172
|
+
if (owner.subtype === "widget") return authorizeWidgetWrite(authority, patchGroupId);
|
|
2173
|
+
const { identity, grants } = authority;
|
|
2174
|
+
const target = require_resolver.collabTargetOf(owner);
|
|
2175
|
+
if (grants && !require_resolver.checkCollab("update", target, grants.scope, identity, grants.pdfBits)) throw new require_resolver.PermissionDenied("annotations:update", "target");
|
|
2176
|
+
if (patchGroupId === null && target.groupId !== void 0) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "an annotation's group can't be removed");
|
|
2177
|
+
const reassigning = typeof patchGroupId === "string" && patchGroupId !== target.groupId;
|
|
2178
|
+
if (reassigning && grants && !require_resolver.checkSetGroup("annotations", patchGroupId, identity.groupId, grants.scope)) throw new require_resolver.PermissionDenied(`annotations:set-group:group=${patchGroupId}`, "target");
|
|
2179
|
+
const actor = {
|
|
2180
|
+
...identity.userId !== void 0 ? { userId: identity.userId } : {},
|
|
2181
|
+
...identity.displayName !== void 0 ? { displayName: identity.displayName } : {},
|
|
2182
|
+
...reassigning ? { groupId: patchGroupId } : {}
|
|
2183
|
+
};
|
|
2184
|
+
return actor.userId || actor.groupId || actor.displayName ? actor : void 0;
|
|
2185
|
+
}
|
|
3017
2186
|
/**
|
|
3018
|
-
*
|
|
3019
|
-
*
|
|
3020
|
-
*
|
|
3021
|
-
* Useful when the customer wants to start from PDF defaults and then
|
|
3022
|
-
* subtract specific capabilities — easier to build the JWT scope array
|
|
3023
|
-
* by filtering an explicit list than by composing virtual + denials.
|
|
3024
|
-
*
|
|
3025
|
-
* const defaults = materializePdfPermissions(pdfBits);
|
|
3026
|
-
* const scope = [
|
|
3027
|
-
* ...defaults.filter(s => s !== 'doc.text.copy'),
|
|
3028
|
-
* 'doc.download',
|
|
3029
|
-
* ];
|
|
3030
|
-
*
|
|
3031
|
-
* IMPORTANT: this MUST stay in sync with `addPdfPermissions` inside
|
|
3032
|
-
* resolver.ts. A test pins them together.
|
|
2187
|
+
* Check a delete of every annotation it removes (an annotation goes with its
|
|
2188
|
+
* thread and popups): all or nothing, `PermissionDenied` naming each one
|
|
2189
|
+
* refused. A widget takes form design, never the annotation scopes.
|
|
3033
2190
|
*/
|
|
3034
|
-
function
|
|
3035
|
-
const
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
if (b.bit5) {
|
|
3041
|
-
out.add("doc.text.select");
|
|
3042
|
-
out.add("doc.text.copy");
|
|
3043
|
-
out.add("doc.text.search");
|
|
3044
|
-
out.add("doc.content.copy");
|
|
3045
|
-
}
|
|
3046
|
-
if (b.bit3) out.add("doc.print");
|
|
3047
|
-
if (b.bit12 && b.bit3) out.add("doc.print.high");
|
|
3048
|
-
if (b.bit4) {
|
|
3049
|
-
out.add("doc.pages.modify");
|
|
3050
|
-
out.add("doc.redact");
|
|
3051
|
-
out.add("doc.metadata.modify");
|
|
3052
|
-
out.add("doc.attachments.modify");
|
|
3053
|
-
}
|
|
3054
|
-
if (b.bit11) out.add("doc.pages.assemble");
|
|
3055
|
-
if (b.bit6) out.add("doc.annotate.modify");
|
|
3056
|
-
if (b.bit6 || b.bit9) {
|
|
3057
|
-
out.add("doc.forms.fill");
|
|
3058
|
-
out.add("doc.sign");
|
|
3059
|
-
}
|
|
3060
|
-
if (b.bit6 && b.bit4) out.add("doc.forms.modify");
|
|
3061
|
-
return [...out];
|
|
2191
|
+
function authorizeAnnotationDelete(authority, members) {
|
|
2192
|
+
const { identity, grants } = authority;
|
|
2193
|
+
if (!grants) return;
|
|
2194
|
+
const mayDesign = require_resolver.checkCapability("doc.forms.modify", grants.scope, grants.pdfBits);
|
|
2195
|
+
const refused = members.filter((member) => member.subtype === "widget" ? !mayDesign : !require_resolver.checkCollab("delete", require_resolver.collabTargetOf(member), grants.scope, identity, grants.pdfBits));
|
|
2196
|
+
if (refused.length > 0) throw new require_resolver.PermissionDenied("annotations:delete", "target", void 0, refused.map((member) => member.ref));
|
|
3062
2197
|
}
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
2198
|
+
/**
|
|
2199
|
+
* Check that the caller may `action` (fill in, or sign) the field in
|
|
2200
|
+
* `groupId`: `ProtectedDocument` when a signature in the document took the
|
|
2201
|
+
* capability away, `PermissionDenied` naming the scope it would take when
|
|
2202
|
+
* the grants don't reach the field's group.
|
|
2203
|
+
*/
|
|
2204
|
+
function authorizeFieldWrite(authority, groupId, action) {
|
|
2205
|
+
authorizeUnprotected(authority, fieldCapability(action));
|
|
2206
|
+
if (!allowsFieldWrite(authority, groupId, action)) throw new require_resolver.PermissionDenied(groupId === null ? fieldCapability(action) : `fields:${action}:group=${groupId}`, "target");
|
|
2207
|
+
}
|
|
2208
|
+
/** Whether the caller may `action` the field in `groupId`: what {@link authorizeFieldWrite} checks. */
|
|
2209
|
+
function allowsFieldWrite(authority, groupId, action) {
|
|
2210
|
+
const { grants, protection } = authority;
|
|
2211
|
+
if (protection && require_resolver.protectedCapabilities(protection).has(fieldCapability(action))) return false;
|
|
2212
|
+
return !grants || require_resolver.checkFieldAction(action, groupId, grants.scope, grants.pdfBits, protection);
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* Whether the caller may `action` some field: what a form verb checks
|
|
2216
|
+
* before it knows which fields it writes. Each field is then checked in
|
|
2217
|
+
* the write with {@link authorizeFieldWrite}.
|
|
2218
|
+
*/
|
|
2219
|
+
function allowsSomeFieldWrite(authority, action) {
|
|
2220
|
+
const { grants, protection } = authority;
|
|
2221
|
+
if (protection && require_resolver.protectedCapabilities(protection).has(fieldCapability(action))) return false;
|
|
2222
|
+
return !grants || require_resolver.checkAnyFieldAction(action, grants.scope, grants.pdfBits, protection);
|
|
2223
|
+
}
|
|
2224
|
+
/**
|
|
2225
|
+
* Check that the caller may put a form field in `groupId`: their own
|
|
2226
|
+
* default group always, another with `fields:set-group` for it.
|
|
2227
|
+
*/
|
|
2228
|
+
function authorizeFieldGroup(authority, groupId) {
|
|
2229
|
+
const { identity, grants } = authority;
|
|
2230
|
+
if (grants && !require_resolver.checkSetGroup("fields", groupId, identity.groupId, grants.scope)) throw new require_resolver.PermissionDenied(`fields:set-group:group=${groupId}`, "target");
|
|
2231
|
+
}
|
|
2232
|
+
/** The broad capability a field action takes without a `fields:` scope. */
|
|
2233
|
+
function fieldCapability(action) {
|
|
2234
|
+
return action === "fill" ? "doc.forms.fill" : "doc.sign";
|
|
3068
2235
|
}
|
|
3069
2236
|
//#endregion
|
|
3070
2237
|
Object.defineProperty(exports, "DEFAULT_EDGE_RESOLVER_BUDGET", {
|
|
@@ -3073,6 +2240,12 @@ Object.defineProperty(exports, "DEFAULT_EDGE_RESOLVER_BUDGET", {
|
|
|
3073
2240
|
return DEFAULT_EDGE_RESOLVER_BUDGET;
|
|
3074
2241
|
}
|
|
3075
2242
|
});
|
|
2243
|
+
Object.defineProperty(exports, "DEFAULT_MEDIA_BOX", {
|
|
2244
|
+
enumerable: true,
|
|
2245
|
+
get: function() {
|
|
2246
|
+
return DEFAULT_MEDIA_BOX;
|
|
2247
|
+
}
|
|
2248
|
+
});
|
|
3076
2249
|
Object.defineProperty(exports, "DEFAULT_PDF_SAVE_MODE", {
|
|
3077
2250
|
enumerable: true,
|
|
3078
2251
|
get: function() {
|
|
@@ -3085,244 +2258,244 @@ Object.defineProperty(exports, "EdgeResolver", {
|
|
|
3085
2258
|
return EdgeResolver;
|
|
3086
2259
|
}
|
|
3087
2260
|
});
|
|
3088
|
-
Object.defineProperty(exports, "
|
|
2261
|
+
Object.defineProperty(exports, "PDF_BITS", {
|
|
3089
2262
|
enumerable: true,
|
|
3090
2263
|
get: function() {
|
|
3091
|
-
return
|
|
2264
|
+
return PDF_BITS;
|
|
3092
2265
|
}
|
|
3093
2266
|
});
|
|
3094
|
-
Object.defineProperty(exports, "
|
|
2267
|
+
Object.defineProperty(exports, "SEARCH_SNIPPET_CONTEXT", {
|
|
3095
2268
|
enumerable: true,
|
|
3096
2269
|
get: function() {
|
|
3097
|
-
return
|
|
2270
|
+
return SEARCH_SNIPPET_CONTEXT;
|
|
3098
2271
|
}
|
|
3099
2272
|
});
|
|
3100
|
-
Object.defineProperty(exports, "
|
|
2273
|
+
Object.defineProperty(exports, "USAGE_INCOMPLETE", {
|
|
3101
2274
|
enumerable: true,
|
|
3102
2275
|
get: function() {
|
|
3103
|
-
return
|
|
2276
|
+
return USAGE_INCOMPLETE;
|
|
3104
2277
|
}
|
|
3105
2278
|
});
|
|
3106
|
-
Object.defineProperty(exports, "
|
|
2279
|
+
Object.defineProperty(exports, "allowsCapability", {
|
|
3107
2280
|
enumerable: true,
|
|
3108
2281
|
get: function() {
|
|
3109
|
-
return
|
|
2282
|
+
return allowsCapability;
|
|
3110
2283
|
}
|
|
3111
2284
|
});
|
|
3112
|
-
Object.defineProperty(exports, "
|
|
2285
|
+
Object.defineProperty(exports, "allowsFieldWrite", {
|
|
3113
2286
|
enumerable: true,
|
|
3114
2287
|
get: function() {
|
|
3115
|
-
return
|
|
2288
|
+
return allowsFieldWrite;
|
|
3116
2289
|
}
|
|
3117
2290
|
});
|
|
3118
|
-
Object.defineProperty(exports, "
|
|
2291
|
+
Object.defineProperty(exports, "allowsSomeFieldWrite", {
|
|
3119
2292
|
enumerable: true,
|
|
3120
2293
|
get: function() {
|
|
3121
|
-
return
|
|
2294
|
+
return allowsSomeFieldWrite;
|
|
3122
2295
|
}
|
|
3123
2296
|
});
|
|
3124
|
-
Object.defineProperty(exports, "
|
|
2297
|
+
Object.defineProperty(exports, "annotationImportFacts", {
|
|
3125
2298
|
enumerable: true,
|
|
3126
2299
|
get: function() {
|
|
3127
|
-
return
|
|
2300
|
+
return annotationImportFacts;
|
|
3128
2301
|
}
|
|
3129
2302
|
});
|
|
3130
|
-
Object.defineProperty(exports, "
|
|
2303
|
+
Object.defineProperty(exports, "annotationPatchBetween", {
|
|
3131
2304
|
enumerable: true,
|
|
3132
2305
|
get: function() {
|
|
3133
|
-
return
|
|
2306
|
+
return annotationPatchBetween;
|
|
3134
2307
|
}
|
|
3135
2308
|
});
|
|
3136
|
-
Object.defineProperty(exports, "
|
|
2309
|
+
Object.defineProperty(exports, "annotationWriteCapabilities", {
|
|
3137
2310
|
enumerable: true,
|
|
3138
2311
|
get: function() {
|
|
3139
|
-
return
|
|
2312
|
+
return annotationWriteCapabilities;
|
|
3140
2313
|
}
|
|
3141
2314
|
});
|
|
3142
|
-
Object.defineProperty(exports, "
|
|
2315
|
+
Object.defineProperty(exports, "annotationWriteCapability", {
|
|
3143
2316
|
enumerable: true,
|
|
3144
2317
|
get: function() {
|
|
3145
|
-
return
|
|
2318
|
+
return annotationWriteCapability;
|
|
3146
2319
|
}
|
|
3147
2320
|
});
|
|
3148
|
-
Object.defineProperty(exports, "
|
|
2321
|
+
Object.defineProperty(exports, "assessmentOf", {
|
|
3149
2322
|
enumerable: true,
|
|
3150
2323
|
get: function() {
|
|
3151
|
-
return
|
|
2324
|
+
return assessmentOf;
|
|
3152
2325
|
}
|
|
3153
2326
|
});
|
|
3154
|
-
Object.defineProperty(exports, "
|
|
2327
|
+
Object.defineProperty(exports, "authorizeAnnotationCreate", {
|
|
3155
2328
|
enumerable: true,
|
|
3156
2329
|
get: function() {
|
|
3157
|
-
return
|
|
2330
|
+
return authorizeAnnotationCreate;
|
|
3158
2331
|
}
|
|
3159
2332
|
});
|
|
3160
|
-
Object.defineProperty(exports, "
|
|
2333
|
+
Object.defineProperty(exports, "authorizeAnnotationDelete", {
|
|
3161
2334
|
enumerable: true,
|
|
3162
2335
|
get: function() {
|
|
3163
|
-
return
|
|
2336
|
+
return authorizeAnnotationDelete;
|
|
3164
2337
|
}
|
|
3165
2338
|
});
|
|
3166
|
-
Object.defineProperty(exports, "
|
|
2339
|
+
Object.defineProperty(exports, "authorizeAnnotationUpdate", {
|
|
3167
2340
|
enumerable: true,
|
|
3168
2341
|
get: function() {
|
|
3169
|
-
return
|
|
2342
|
+
return authorizeAnnotationUpdate;
|
|
3170
2343
|
}
|
|
3171
2344
|
});
|
|
3172
|
-
Object.defineProperty(exports, "
|
|
2345
|
+
Object.defineProperty(exports, "authorizeCapability", {
|
|
3173
2346
|
enumerable: true,
|
|
3174
2347
|
get: function() {
|
|
3175
|
-
return
|
|
2348
|
+
return authorizeCapability;
|
|
3176
2349
|
}
|
|
3177
2350
|
});
|
|
3178
|
-
Object.defineProperty(exports, "
|
|
2351
|
+
Object.defineProperty(exports, "authorizeFieldGroup", {
|
|
3179
2352
|
enumerable: true,
|
|
3180
2353
|
get: function() {
|
|
3181
|
-
return
|
|
2354
|
+
return authorizeFieldGroup;
|
|
3182
2355
|
}
|
|
3183
2356
|
});
|
|
3184
|
-
Object.defineProperty(exports, "
|
|
2357
|
+
Object.defineProperty(exports, "authorizeFieldWrite", {
|
|
3185
2358
|
enumerable: true,
|
|
3186
2359
|
get: function() {
|
|
3187
|
-
return
|
|
2360
|
+
return authorizeFieldWrite;
|
|
3188
2361
|
}
|
|
3189
2362
|
});
|
|
3190
|
-
Object.defineProperty(exports, "
|
|
2363
|
+
Object.defineProperty(exports, "authorizeUnprotected", {
|
|
3191
2364
|
enumerable: true,
|
|
3192
2365
|
get: function() {
|
|
3193
|
-
return
|
|
2366
|
+
return authorizeUnprotected;
|
|
3194
2367
|
}
|
|
3195
2368
|
});
|
|
3196
|
-
Object.defineProperty(exports, "
|
|
2369
|
+
Object.defineProperty(exports, "buildSnippet", {
|
|
3197
2370
|
enumerable: true,
|
|
3198
2371
|
get: function() {
|
|
3199
|
-
return
|
|
2372
|
+
return buildSnippet;
|
|
3200
2373
|
}
|
|
3201
2374
|
});
|
|
3202
|
-
Object.defineProperty(exports, "
|
|
2375
|
+
Object.defineProperty(exports, "canonicalSearchQuery", {
|
|
3203
2376
|
enumerable: true,
|
|
3204
2377
|
get: function() {
|
|
3205
|
-
return
|
|
2378
|
+
return canonicalSearchQuery;
|
|
3206
2379
|
}
|
|
3207
2380
|
});
|
|
3208
|
-
Object.defineProperty(exports, "
|
|
2381
|
+
Object.defineProperty(exports, "changeFingerprint", {
|
|
3209
2382
|
enumerable: true,
|
|
3210
2383
|
get: function() {
|
|
3211
|
-
return
|
|
2384
|
+
return changeFingerprint;
|
|
3212
2385
|
}
|
|
3213
2386
|
});
|
|
3214
|
-
Object.defineProperty(exports, "
|
|
2387
|
+
Object.defineProperty(exports, "changedKeys", {
|
|
3215
2388
|
enumerable: true,
|
|
3216
2389
|
get: function() {
|
|
3217
|
-
return
|
|
2390
|
+
return changedKeys;
|
|
3218
2391
|
}
|
|
3219
2392
|
});
|
|
3220
|
-
Object.defineProperty(exports, "
|
|
2393
|
+
Object.defineProperty(exports, "checkImageQuality", {
|
|
3221
2394
|
enumerable: true,
|
|
3222
2395
|
get: function() {
|
|
3223
|
-
return
|
|
2396
|
+
return checkImageQuality;
|
|
3224
2397
|
}
|
|
3225
2398
|
});
|
|
3226
|
-
Object.defineProperty(exports, "
|
|
2399
|
+
Object.defineProperty(exports, "closeExportSelection", {
|
|
3227
2400
|
enumerable: true,
|
|
3228
2401
|
get: function() {
|
|
3229
|
-
return
|
|
2402
|
+
return closeExportSelection;
|
|
3230
2403
|
}
|
|
3231
2404
|
});
|
|
3232
|
-
Object.defineProperty(exports, "
|
|
2405
|
+
Object.defineProperty(exports, "combine", {
|
|
3233
2406
|
enumerable: true,
|
|
3234
2407
|
get: function() {
|
|
3235
|
-
return
|
|
2408
|
+
return combine;
|
|
3236
2409
|
}
|
|
3237
2410
|
});
|
|
3238
|
-
Object.defineProperty(exports, "
|
|
2411
|
+
Object.defineProperty(exports, "concatAnnotationLists", {
|
|
3239
2412
|
enumerable: true,
|
|
3240
2413
|
get: function() {
|
|
3241
|
-
return
|
|
2414
|
+
return concatAnnotationLists;
|
|
3242
2415
|
}
|
|
3243
2416
|
});
|
|
3244
|
-
Object.defineProperty(exports, "
|
|
2417
|
+
Object.defineProperty(exports, "conclude", {
|
|
3245
2418
|
enumerable: true,
|
|
3246
2419
|
get: function() {
|
|
3247
|
-
return
|
|
2420
|
+
return conclude;
|
|
3248
2421
|
}
|
|
3249
2422
|
});
|
|
3250
|
-
Object.defineProperty(exports, "
|
|
2423
|
+
Object.defineProperty(exports, "createPageImageHandle", {
|
|
3251
2424
|
enumerable: true,
|
|
3252
2425
|
get: function() {
|
|
3253
|
-
return
|
|
2426
|
+
return createPageImageHandle;
|
|
3254
2427
|
}
|
|
3255
2428
|
});
|
|
3256
|
-
Object.defineProperty(exports, "
|
|
2429
|
+
Object.defineProperty(exports, "decodePdfBits", {
|
|
3257
2430
|
enumerable: true,
|
|
3258
2431
|
get: function() {
|
|
3259
|
-
return
|
|
2432
|
+
return decodePdfBits;
|
|
3260
2433
|
}
|
|
3261
2434
|
});
|
|
3262
|
-
Object.defineProperty(exports, "
|
|
2435
|
+
Object.defineProperty(exports, "deletedAnnotationsOf", {
|
|
3263
2436
|
enumerable: true,
|
|
3264
2437
|
get: function() {
|
|
3265
|
-
return
|
|
2438
|
+
return deletedAnnotationsOf;
|
|
3266
2439
|
}
|
|
3267
2440
|
});
|
|
3268
|
-
Object.defineProperty(exports, "
|
|
2441
|
+
Object.defineProperty(exports, "dictEntries", {
|
|
3269
2442
|
enumerable: true,
|
|
3270
2443
|
get: function() {
|
|
3271
|
-
return
|
|
2444
|
+
return dictEntries;
|
|
3272
2445
|
}
|
|
3273
2446
|
});
|
|
3274
|
-
Object.defineProperty(exports, "
|
|
2447
|
+
Object.defineProperty(exports, "draftWritesScripts", {
|
|
3275
2448
|
enumerable: true,
|
|
3276
2449
|
get: function() {
|
|
3277
|
-
return
|
|
2450
|
+
return draftWritesScripts;
|
|
3278
2451
|
}
|
|
3279
2452
|
});
|
|
3280
|
-
Object.defineProperty(exports, "
|
|
2453
|
+
Object.defineProperty(exports, "evaluateStep", {
|
|
3281
2454
|
enumerable: true,
|
|
3282
2455
|
get: function() {
|
|
3283
|
-
return
|
|
2456
|
+
return evaluateStep;
|
|
3284
2457
|
}
|
|
3285
2458
|
});
|
|
3286
|
-
Object.defineProperty(exports, "
|
|
2459
|
+
Object.defineProperty(exports, "familyOfSubtype", {
|
|
3287
2460
|
enumerable: true,
|
|
3288
2461
|
get: function() {
|
|
3289
|
-
return
|
|
2462
|
+
return familyOfSubtype;
|
|
3290
2463
|
}
|
|
3291
2464
|
});
|
|
3292
|
-
Object.defineProperty(exports, "
|
|
2465
|
+
Object.defineProperty(exports, "generateUuid", {
|
|
3293
2466
|
enumerable: true,
|
|
3294
2467
|
get: function() {
|
|
3295
|
-
return
|
|
2468
|
+
return generateUuid;
|
|
3296
2469
|
}
|
|
3297
2470
|
});
|
|
3298
|
-
Object.defineProperty(exports, "
|
|
2471
|
+
Object.defineProperty(exports, "generateUuidV7", {
|
|
3299
2472
|
enumerable: true,
|
|
3300
2473
|
get: function() {
|
|
3301
|
-
return
|
|
2474
|
+
return generateUuidV7;
|
|
3302
2475
|
}
|
|
3303
2476
|
});
|
|
3304
|
-
Object.defineProperty(exports, "
|
|
2477
|
+
Object.defineProperty(exports, "imageSourceOfBytes", {
|
|
3305
2478
|
enumerable: true,
|
|
3306
2479
|
get: function() {
|
|
3307
|
-
return
|
|
2480
|
+
return imageSourceOfBytes;
|
|
3308
2481
|
}
|
|
3309
2482
|
});
|
|
3310
|
-
Object.defineProperty(exports, "
|
|
2483
|
+
Object.defineProperty(exports, "isKeptRefusal", {
|
|
3311
2484
|
enumerable: true,
|
|
3312
2485
|
get: function() {
|
|
3313
|
-
return
|
|
2486
|
+
return isKeptRefusal;
|
|
3314
2487
|
}
|
|
3315
2488
|
});
|
|
3316
|
-
Object.defineProperty(exports, "
|
|
2489
|
+
Object.defineProperty(exports, "matchPageText", {
|
|
3317
2490
|
enumerable: true,
|
|
3318
2491
|
get: function() {
|
|
3319
|
-
return
|
|
2492
|
+
return matchPageText;
|
|
3320
2493
|
}
|
|
3321
2494
|
});
|
|
3322
|
-
Object.defineProperty(exports, "
|
|
2495
|
+
Object.defineProperty(exports, "mergeAnnotationPatch", {
|
|
3323
2496
|
enumerable: true,
|
|
3324
2497
|
get: function() {
|
|
3325
|
-
return
|
|
2498
|
+
return mergeAnnotationPatch;
|
|
3326
2499
|
}
|
|
3327
2500
|
});
|
|
3328
2501
|
Object.defineProperty(exports, "normalizeAttachmentFileSource", {
|
|
@@ -3331,166 +2504,166 @@ Object.defineProperty(exports, "normalizeAttachmentFileSource", {
|
|
|
3331
2504
|
return normalizeAttachmentFileSource;
|
|
3332
2505
|
}
|
|
3333
2506
|
});
|
|
3334
|
-
Object.defineProperty(exports, "
|
|
2507
|
+
Object.defineProperty(exports, "opIdOf", {
|
|
3335
2508
|
enumerable: true,
|
|
3336
2509
|
get: function() {
|
|
3337
|
-
return
|
|
2510
|
+
return opIdOf;
|
|
3338
2511
|
}
|
|
3339
2512
|
});
|
|
3340
|
-
Object.defineProperty(exports, "
|
|
2513
|
+
Object.defineProperty(exports, "pageAppearancesOf", {
|
|
3341
2514
|
enumerable: true,
|
|
3342
2515
|
get: function() {
|
|
3343
|
-
return
|
|
2516
|
+
return pageAppearancesOf;
|
|
3344
2517
|
}
|
|
3345
2518
|
});
|
|
3346
|
-
Object.defineProperty(exports, "
|
|
2519
|
+
Object.defineProperty(exports, "pageBoxesOf", {
|
|
3347
2520
|
enumerable: true,
|
|
3348
2521
|
get: function() {
|
|
3349
|
-
return
|
|
2522
|
+
return pageBoxesOf;
|
|
3350
2523
|
}
|
|
3351
2524
|
});
|
|
3352
|
-
Object.defineProperty(exports, "
|
|
2525
|
+
Object.defineProperty(exports, "pageFieldActionsOf", {
|
|
3353
2526
|
enumerable: true,
|
|
3354
2527
|
get: function() {
|
|
3355
|
-
return
|
|
2528
|
+
return pageFieldActionsOf;
|
|
3356
2529
|
}
|
|
3357
2530
|
});
|
|
3358
|
-
Object.defineProperty(exports, "
|
|
2531
|
+
Object.defineProperty(exports, "pageFormFieldOf", {
|
|
3359
2532
|
enumerable: true,
|
|
3360
2533
|
get: function() {
|
|
3361
|
-
return
|
|
2534
|
+
return pageFormFieldOf;
|
|
3362
2535
|
}
|
|
3363
2536
|
});
|
|
3364
|
-
Object.defineProperty(exports, "
|
|
2537
|
+
Object.defineProperty(exports, "pageFormSnapshotOf", {
|
|
3365
2538
|
enumerable: true,
|
|
3366
2539
|
get: function() {
|
|
3367
|
-
return
|
|
2540
|
+
return pageFormSnapshotOf;
|
|
3368
2541
|
}
|
|
3369
2542
|
});
|
|
3370
|
-
Object.defineProperty(exports, "
|
|
2543
|
+
Object.defineProperty(exports, "pageLayoutOf", {
|
|
3371
2544
|
enumerable: true,
|
|
3372
2545
|
get: function() {
|
|
3373
|
-
return
|
|
2546
|
+
return pageLayoutOf;
|
|
3374
2547
|
}
|
|
3375
2548
|
});
|
|
3376
|
-
Object.defineProperty(exports, "
|
|
2549
|
+
Object.defineProperty(exports, "pageListOf", {
|
|
3377
2550
|
enumerable: true,
|
|
3378
2551
|
get: function() {
|
|
3379
|
-
return
|
|
2552
|
+
return pageListOf;
|
|
3380
2553
|
}
|
|
3381
2554
|
});
|
|
3382
|
-
Object.defineProperty(exports, "
|
|
2555
|
+
Object.defineProperty(exports, "pageRotationOf", {
|
|
3383
2556
|
enumerable: true,
|
|
3384
2557
|
get: function() {
|
|
3385
|
-
return
|
|
2558
|
+
return pageRotationOf;
|
|
3386
2559
|
}
|
|
3387
2560
|
});
|
|
3388
|
-
Object.defineProperty(exports, "
|
|
2561
|
+
Object.defineProperty(exports, "pageSpaceBoxesOf", {
|
|
3389
2562
|
enumerable: true,
|
|
3390
2563
|
get: function() {
|
|
3391
|
-
return
|
|
2564
|
+
return pageSpaceBoxesOf;
|
|
3392
2565
|
}
|
|
3393
2566
|
});
|
|
3394
|
-
Object.defineProperty(exports, "
|
|
2567
|
+
Object.defineProperty(exports, "pageWidgetOf", {
|
|
3395
2568
|
enumerable: true,
|
|
3396
2569
|
get: function() {
|
|
3397
|
-
return
|
|
2570
|
+
return pageWidgetOf;
|
|
3398
2571
|
}
|
|
3399
2572
|
});
|
|
3400
|
-
Object.defineProperty(exports, "
|
|
2573
|
+
Object.defineProperty(exports, "parsePdfValue", {
|
|
3401
2574
|
enumerable: true,
|
|
3402
2575
|
get: function() {
|
|
3403
|
-
return
|
|
2576
|
+
return parsePdfValue;
|
|
3404
2577
|
}
|
|
3405
2578
|
});
|
|
3406
|
-
Object.defineProperty(exports, "
|
|
2579
|
+
Object.defineProperty(exports, "pdfFormFieldDraftOf", {
|
|
3407
2580
|
enumerable: true,
|
|
3408
2581
|
get: function() {
|
|
3409
|
-
return
|
|
2582
|
+
return pdfFormFieldDraftOf;
|
|
3410
2583
|
}
|
|
3411
2584
|
});
|
|
3412
|
-
Object.defineProperty(exports, "
|
|
2585
|
+
Object.defineProperty(exports, "pdfRenderTargetOf", {
|
|
3413
2586
|
enumerable: true,
|
|
3414
2587
|
get: function() {
|
|
3415
|
-
return
|
|
2588
|
+
return pdfRenderTargetOf;
|
|
3416
2589
|
}
|
|
3417
2590
|
});
|
|
3418
|
-
Object.defineProperty(exports, "
|
|
2591
|
+
Object.defineProperty(exports, "pdfValueEquals", {
|
|
3419
2592
|
enumerable: true,
|
|
3420
2593
|
get: function() {
|
|
3421
|
-
return
|
|
2594
|
+
return pdfValueEquals;
|
|
3422
2595
|
}
|
|
3423
2596
|
});
|
|
3424
|
-
Object.defineProperty(exports, "
|
|
2597
|
+
Object.defineProperty(exports, "pdfWidgetPlacementOf", {
|
|
3425
2598
|
enumerable: true,
|
|
3426
2599
|
get: function() {
|
|
3427
|
-
return
|
|
2600
|
+
return pdfWidgetPlacementOf;
|
|
3428
2601
|
}
|
|
3429
2602
|
});
|
|
3430
|
-
Object.defineProperty(exports, "
|
|
2603
|
+
Object.defineProperty(exports, "placedWidgetOf", {
|
|
3431
2604
|
enumerable: true,
|
|
3432
2605
|
get: function() {
|
|
3433
|
-
return
|
|
2606
|
+
return placedWidgetOf;
|
|
3434
2607
|
}
|
|
3435
2608
|
});
|
|
3436
|
-
Object.defineProperty(exports, "
|
|
2609
|
+
Object.defineProperty(exports, "primaryFinding", {
|
|
3437
2610
|
enumerable: true,
|
|
3438
2611
|
get: function() {
|
|
3439
|
-
return
|
|
2612
|
+
return primaryFinding;
|
|
3440
2613
|
}
|
|
3441
2614
|
});
|
|
3442
|
-
Object.defineProperty(exports, "
|
|
2615
|
+
Object.defineProperty(exports, "refsOf", {
|
|
3443
2616
|
enumerable: true,
|
|
3444
2617
|
get: function() {
|
|
3445
|
-
return
|
|
2618
|
+
return refsOf;
|
|
3446
2619
|
}
|
|
3447
2620
|
});
|
|
3448
|
-
Object.defineProperty(exports, "
|
|
2621
|
+
Object.defineProperty(exports, "resolvePageLayers", {
|
|
3449
2622
|
enumerable: true,
|
|
3450
2623
|
get: function() {
|
|
3451
|
-
return
|
|
2624
|
+
return resolvePageLayers;
|
|
3452
2625
|
}
|
|
3453
2626
|
});
|
|
3454
|
-
Object.defineProperty(exports, "
|
|
2627
|
+
Object.defineProperty(exports, "restrictionsFor", {
|
|
3455
2628
|
enumerable: true,
|
|
3456
2629
|
get: function() {
|
|
3457
|
-
return
|
|
2630
|
+
return restrictionsFor;
|
|
3458
2631
|
}
|
|
3459
2632
|
});
|
|
3460
|
-
Object.defineProperty(exports, "
|
|
2633
|
+
Object.defineProperty(exports, "restrictionsOf", {
|
|
3461
2634
|
enumerable: true,
|
|
3462
2635
|
get: function() {
|
|
3463
|
-
return
|
|
2636
|
+
return restrictionsOf;
|
|
3464
2637
|
}
|
|
3465
2638
|
});
|
|
3466
|
-
Object.defineProperty(exports, "
|
|
2639
|
+
Object.defineProperty(exports, "sameEffectiveValue", {
|
|
3467
2640
|
enumerable: true,
|
|
3468
2641
|
get: function() {
|
|
3469
|
-
return
|
|
2642
|
+
return sameEffectiveValue;
|
|
3470
2643
|
}
|
|
3471
2644
|
});
|
|
3472
|
-
Object.defineProperty(exports, "
|
|
2645
|
+
Object.defineProperty(exports, "searchContentEpoch", {
|
|
3473
2646
|
enumerable: true,
|
|
3474
2647
|
get: function() {
|
|
3475
|
-
return
|
|
2648
|
+
return searchContentEpoch;
|
|
3476
2649
|
}
|
|
3477
2650
|
});
|
|
3478
|
-
Object.defineProperty(exports, "
|
|
2651
|
+
Object.defineProperty(exports, "searchQueryOf", {
|
|
3479
2652
|
enumerable: true,
|
|
3480
2653
|
get: function() {
|
|
3481
|
-
return
|
|
2654
|
+
return searchQueryOf;
|
|
3482
2655
|
}
|
|
3483
2656
|
});
|
|
3484
|
-
Object.defineProperty(exports, "
|
|
2657
|
+
Object.defineProperty(exports, "stableStringify", {
|
|
3485
2658
|
enumerable: true,
|
|
3486
2659
|
get: function() {
|
|
3487
|
-
return
|
|
2660
|
+
return stableStringify;
|
|
3488
2661
|
}
|
|
3489
2662
|
});
|
|
3490
|
-
Object.defineProperty(exports, "
|
|
2663
|
+
Object.defineProperty(exports, "visibleBoxesOf", {
|
|
3491
2664
|
enumerable: true,
|
|
3492
2665
|
get: function() {
|
|
3493
|
-
return
|
|
2666
|
+
return visibleBoxesOf;
|
|
3494
2667
|
}
|
|
3495
2668
|
});
|
|
3496
2669
|
Object.defineProperty(exports, "worstVerdict", {
|
|
@@ -3500,4 +2673,4 @@ Object.defineProperty(exports, "worstVerdict", {
|
|
|
3500
2673
|
}
|
|
3501
2674
|
});
|
|
3502
2675
|
|
|
3503
|
-
//# sourceMappingURL=
|
|
2676
|
+
//# sourceMappingURL=authority-DLMNR7ff.cjs.map
|