@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.
Files changed (134) hide show
  1. package/dist/AnnotationList-CkijRHet.d.cts +27163 -0
  2. package/dist/AnnotationList-CkijRHet.d.ts +27163 -0
  3. package/dist/Change-CKoxfTNY.js +889 -0
  4. package/dist/Change-CKoxfTNY.js.map +1 -0
  5. package/dist/Change-CjImsrN0.cjs +1020 -0
  6. package/dist/Change-CjImsrN0.cjs.map +1 -0
  7. package/dist/DocumentRenderService-BfFdFSwI.cjs +120 -0
  8. package/dist/DocumentRenderService-BfFdFSwI.cjs.map +1 -0
  9. package/dist/DocumentRenderService-DV3J9lMz.js +85 -0
  10. package/dist/DocumentRenderService-DV3J9lMz.js.map +1 -0
  11. package/dist/{DocumentSecurityService-Ca6EK3-3.d.ts → DocumentSecurityService-CU1M6Q7m.d.ts} +100 -112
  12. package/dist/{DocumentSecurityService-CIx1MT0T.d.cts → DocumentSecurityService-e6vp2de8.d.cts} +100 -112
  13. package/dist/LocalDocumentHandle-D02FMm-Z.cjs +53 -0
  14. package/dist/LocalDocumentHandle-D02FMm-Z.cjs.map +1 -0
  15. package/dist/LocalDocumentHandle-DAPdaOt_.js +30 -0
  16. package/dist/LocalDocumentHandle-DAPdaOt_.js.map +1 -0
  17. package/dist/LocalEngine-DFoBm4B3.d.cts +1565 -0
  18. package/dist/LocalEngine-DPriFujS.d.ts +1565 -0
  19. package/dist/PageInsertBlankInput-CXHAM7l6.cjs +17 -0
  20. package/dist/PageInsertBlankInput-CXHAM7l6.cjs.map +1 -0
  21. package/dist/PageInsertBlankInput-DhVYVJ_S.js +12 -0
  22. package/dist/PageInsertBlankInput-DhVYVJ_S.js.map +1 -0
  23. package/dist/authority-B3BklsB4.js +2239 -0
  24. package/dist/authority-B3BklsB4.js.map +1 -0
  25. package/dist/{viewport-BWeNHZmb.cjs → authority-DLMNR7ff.cjs} +820 -1647
  26. package/dist/authority-DLMNR7ff.cjs.map +1 -0
  27. package/dist/builders-CNj0POeY.js +161 -0
  28. package/dist/builders-CNj0POeY.js.map +1 -0
  29. package/dist/builders-Cgdp_YCn.cjs +184 -0
  30. package/dist/builders-Cgdp_YCn.cjs.map +1 -0
  31. package/dist/calibrate-7T3fnP8-.js +2404 -0
  32. package/dist/calibrate-7T3fnP8-.js.map +1 -0
  33. package/dist/calibrate-DJBXnhLE.cjs +2919 -0
  34. package/dist/calibrate-DJBXnhLE.cjs.map +1 -0
  35. package/dist/charmap-Cprti1ta.js +239 -0
  36. package/dist/charmap-Cprti1ta.js.map +1 -0
  37. package/dist/charmap-aYlefQP9.cjs +304 -0
  38. package/dist/charmap-aYlefQP9.cjs.map +1 -0
  39. package/dist/conformance.cjs +16466 -5247
  40. package/dist/conformance.cjs.map +1 -1
  41. package/dist/conformance.d.cts +924 -165
  42. package/dist/conformance.d.ts +924 -165
  43. package/dist/conformance.js +16429 -5252
  44. package/dist/conformance.js.map +1 -1
  45. package/dist/format-Bp3QFSH1.cjs +574 -0
  46. package/dist/format-Bp3QFSH1.cjs.map +1 -0
  47. package/dist/format-Dgg428Kb.js +461 -0
  48. package/dist/format-Dgg428Kb.js.map +1 -0
  49. package/dist/index.cjs +323 -116
  50. package/dist/index.d.cts +2 -2
  51. package/dist/index.d.ts +2 -2
  52. package/dist/index.js +14 -5
  53. package/dist/pageRefs-B3ur7Ckm.cjs +51 -0
  54. package/dist/pageRefs-B3ur7Ckm.cjs.map +1 -0
  55. package/dist/pageRefs-DkbuxSCV.js +40 -0
  56. package/dist/pageRefs-DkbuxSCV.js.map +1 -0
  57. package/dist/public.cjs +57 -0
  58. package/dist/public.d.cts +5 -0
  59. package/dist/public.d.ts +5 -0
  60. package/dist/public.js +9 -0
  61. package/dist/resolveAnnotationDraft-7Ke4nV7F.cjs +3646 -0
  62. package/dist/resolveAnnotationDraft-7Ke4nV7F.cjs.map +1 -0
  63. package/dist/resolveAnnotationDraft-CUpf0SMh.js +3167 -0
  64. package/dist/resolveAnnotationDraft-CUpf0SMh.js.map +1 -0
  65. package/dist/{resolver-inAVzsWt.js → resolver-CzxmD9Ck.js} +294 -144
  66. package/dist/resolver-CzxmD9Ck.js.map +1 -0
  67. package/dist/{resolver-CYVNV4hn.cjs → resolver-D2OCtE8F.cjs} +347 -143
  68. package/dist/resolver-D2OCtE8F.cjs.map +1 -0
  69. package/dist/runtime-Cl0v56mm.d.ts +2032 -0
  70. package/dist/runtime-p1WDzDo4.d.cts +2032 -0
  71. package/dist/runtime.cjs +726 -297
  72. package/dist/runtime.cjs.map +1 -1
  73. package/dist/runtime.d.cts +5 -1372
  74. package/dist/runtime.d.ts +5 -1372
  75. package/dist/runtime.js +396 -179
  76. package/dist/runtime.js.map +1 -1
  77. package/dist/schema-C-gU4vj7.cjs +3034 -0
  78. package/dist/schema-C-gU4vj7.cjs.map +1 -0
  79. package/dist/schema-DzlUNk38.js +2081 -0
  80. package/dist/schema-DzlUNk38.js.map +1 -0
  81. package/dist/schemas-Berf1swF.cjs +2481 -0
  82. package/dist/schemas-Berf1swF.cjs.map +1 -0
  83. package/dist/schemas-D6xOGjqg.js +1654 -0
  84. package/dist/schemas-D6xOGjqg.js.map +1 -0
  85. package/dist/subtype-CG4WpIRj.js +129 -0
  86. package/dist/subtype-CG4WpIRj.js.map +1 -0
  87. package/dist/subtype-aDt5TFmK.cjs +158 -0
  88. package/dist/subtype-aDt5TFmK.cjs.map +1 -0
  89. package/dist/validation.cjs +578 -0
  90. package/dist/validation.cjs.map +1 -0
  91. package/dist/validation.d.cts +174 -0
  92. package/dist/validation.d.ts +174 -0
  93. package/dist/validation.js +571 -0
  94. package/dist/validation.js.map +1 -0
  95. package/dist/value-BFS1R8ek.cjs +435 -0
  96. package/dist/value-BFS1R8ek.cjs.map +1 -0
  97. package/dist/value-Dhc8eYcx.js +340 -0
  98. package/dist/value-Dhc8eYcx.js.map +1 -0
  99. package/dist/viewport-BJW13EGZ.js +540 -0
  100. package/dist/viewport-BJW13EGZ.js.map +1 -0
  101. package/dist/viewport-DlL5Bxbg.cjs +671 -0
  102. package/dist/viewport-DlL5Bxbg.cjs.map +1 -0
  103. package/dist/wire.cjs +1051 -397
  104. package/dist/wire.cjs.map +1 -1
  105. package/dist/wire.d.cts +12403 -790
  106. package/dist/wire.d.ts +12403 -790
  107. package/dist/wire.js +821 -242
  108. package/dist/wire.js.map +1 -1
  109. package/package.json +10 -1
  110. package/dist/AbortError-DwuHPK_I.js +0 -27
  111. package/dist/AbortError-DwuHPK_I.js.map +0 -1
  112. package/dist/AbortError-P0RU0Mgg.cjs +0 -38
  113. package/dist/AbortError-P0RU0Mgg.cjs.map +0 -1
  114. package/dist/AnnotationListSnapshot-D9R5n2Kf.d.cts +0 -7101
  115. package/dist/AnnotationListSnapshot-D9R5n2Kf.d.ts +0 -7101
  116. package/dist/Engine-EWWHhEIi.d.ts +0 -1277
  117. package/dist/Engine-FNaAEjfb.d.cts +0 -1277
  118. package/dist/derive-BbsDk_Kz.cjs +0 -880
  119. package/dist/derive-BbsDk_Kz.cjs.map +0 -1
  120. package/dist/derive-DAFJolWu.js +0 -647
  121. package/dist/derive-DAFJolWu.js.map +0 -1
  122. package/dist/format-Bbphf4zR.js +0 -435
  123. package/dist/format-Bbphf4zR.js.map +0 -1
  124. package/dist/format-D_epWlob.cjs +0 -518
  125. package/dist/format-D_epWlob.cjs.map +0 -1
  126. package/dist/resolver-CYVNV4hn.cjs.map +0 -1
  127. package/dist/resolver-inAVzsWt.js.map +0 -1
  128. package/dist/schemas-CFQGvWiu.js +0 -3243
  129. package/dist/schemas-CFQGvWiu.js.map +0 -1
  130. package/dist/schemas-D0g6tKa9.cjs +0 -4694
  131. package/dist/schemas-D0g6tKa9.cjs.map +0 -1
  132. package/dist/viewport-BWeNHZmb.cjs.map +0 -1
  133. package/dist/viewport-CvMcadfQ.js +0 -3072
  134. package/dist/viewport-CvMcadfQ.js.map +0 -1
@@ -0,0 +1,161 @@
1
+ //#region src/auth/scope/builders.ts
2
+ /**
3
+ * Typed capability constants for customer-side JWT minting.
4
+ *
5
+ * The shape mirrors the dotted capability name so it reads naturally:
6
+ * caps.doc.text.copy() // "doc.text.copy"
7
+ * caps.doc.download() // "doc.download"
8
+ * caps.doc.download.flattened() // "doc.download.flattened"
9
+ * caps.doc.print.high() // "doc.print.high"
10
+ *
11
+ * Each leaf is a function returning the literal string (as `const`) so
12
+ * TypeScript catches typos at the call site. Wrappers like `download`
13
+ * and `print` are `Object.assign`'d to be callable and carry child
14
+ * properties for the refinement capabilities.
15
+ */
16
+ const caps = { doc: {
17
+ open: () => "doc.open",
18
+ render: () => "doc.render",
19
+ text: {
20
+ select: () => "doc.text.select",
21
+ copy: () => "doc.text.copy",
22
+ search: () => "doc.text.search"
23
+ },
24
+ content: { copy: () => "doc.content.copy" },
25
+ download: Object.assign(() => "doc.download", { flattened: () => "doc.download.flattened" }),
26
+ print: Object.assign(() => "doc.print", { high: () => "doc.print.high" }),
27
+ pages: {
28
+ modify: () => "doc.pages.modify",
29
+ assemble: () => "doc.pages.assemble"
30
+ },
31
+ forms: {
32
+ read: () => "doc.forms.read",
33
+ fill: () => "doc.forms.fill",
34
+ modify: () => "doc.forms.modify",
35
+ import: () => "doc.forms.import",
36
+ script: () => "doc.forms.script",
37
+ submit: () => "doc.forms.submit"
38
+ },
39
+ annotate: {
40
+ read: () => "doc.annotate.read",
41
+ modify: () => "doc.annotate.modify",
42
+ import: () => "doc.annotate.import"
43
+ },
44
+ metadata: { modify: () => "doc.metadata.modify" },
45
+ attachments: { modify: () => "doc.attachments.modify" },
46
+ redact: () => "doc.redact",
47
+ sign: Object.assign(() => "doc.sign", { certify: () => "doc.sign.certify" })
48
+ } };
49
+ /**
50
+ * Builder factory for collab scope filters. Each entity:action pair
51
+ * gets a sub-object with the four filter constructors.
52
+ *
53
+ * collab.annotations.create.self() → "annotations:create:self"
54
+ * collab.annotations.create.group("legal") → "annotations:create:group=legal"
55
+ * collab.annotations.update.group("4") → "annotations:update:group=4"
56
+ * collab.annotations.delete.createdBy("u-7") → "annotations:delete:createdBy=u-7"
57
+ * collab.annotations.setGroup.group("legal") → "annotations:set-group:group=legal"
58
+ * collab.annotations.all.all() → "annotations:*:all" (action wildcard)
59
+ * collab.fields.fill.group("buyer") → "fields:fill:group=buyer"
60
+ * collab.fields.sign.group("buyer") → "fields:sign:group=buyer"
61
+ * collab.fields.all.group("seller") → "fields:*:group=seller"
62
+ *
63
+ * On create, the filter is evaluated against the caller's own identity
64
+ * (no impersonation), so `:self` and `:all` trivially pass; `:group=X`
65
+ * is the meaningful filter — it constrains creation to callers whose
66
+ * default group is X.
67
+ */
68
+ const collab = {
69
+ annotations: {
70
+ create: makeFilterBuilder("annotations", "create"),
71
+ update: makeFilterBuilder("annotations", "update"),
72
+ delete: makeFilterBuilder("annotations", "delete"),
73
+ setGroup: makeGroupFilterBuilder("annotations", "set-group"),
74
+ /** Action wildcard — matches create, update, delete, and set-group with the given filter. */
75
+ all: makeFilterBuilder("annotations", "*")
76
+ },
77
+ /** Form fields, by group: a field records no creator, so only `:all` and `:group=X`. */
78
+ fields: {
79
+ fill: makeGroupFilterBuilder("fields", "fill"),
80
+ sign: makeGroupFilterBuilder("fields", "sign"),
81
+ setGroup: makeGroupFilterBuilder("fields", "set-group"),
82
+ /** Action wildcard — matches fill, sign, and set-group with the given filter. */
83
+ all: makeGroupFilterBuilder("fields", "*")
84
+ }
85
+ };
86
+ function makeFilterBuilder(entity, action) {
87
+ return {
88
+ all: () => `${entity}:${action}:all`,
89
+ self: () => `${entity}:${action}:self`,
90
+ createdBy: (userId) => `${entity}:${action}:createdBy=${userId}`,
91
+ group: (groupId) => `${entity}:${action}:group=${groupId}`
92
+ };
93
+ }
94
+ function makeGroupFilterBuilder(entity, action) {
95
+ return {
96
+ all: () => `${entity}:${action}:all`,
97
+ group: (groupId) => `${entity}:${action}:group=${groupId}`
98
+ };
99
+ }
100
+ /**
101
+ * Builder for the `pdf.permissions` virtual scope. Returns the literal
102
+ * string; provided as a helper for parity with caps/collab in JWT
103
+ * construction code.
104
+ */
105
+ const pdfPermissions = () => "pdf.permissions";
106
+ /**
107
+ * Materialise `pdf.permissions` into the concrete capability list it
108
+ * would expand to under the given PDF bit configuration.
109
+ *
110
+ * Useful when the customer wants to start from PDF defaults and then
111
+ * subtract specific capabilities — easier to build the JWT scope array
112
+ * by filtering an explicit list than by composing virtual + denials.
113
+ *
114
+ * const defaults = materializePdfPermissions(pdfBits);
115
+ * const scope = [
116
+ * ...defaults.filter(s => s !== 'doc.text.copy'),
117
+ * 'doc.download',
118
+ * ];
119
+ *
120
+ * This is the one reading of the bits: the scope resolver and the
121
+ * permission advisory both use it. It follows what Acrobat allows on a
122
+ * file with these bits, which is broader than ISO 32000 in two places:
123
+ * bit 4 ("changing the document") also allows filling in and signing, and
124
+ * bit 5 ("copying text and graphics") governs taking the text out, not
125
+ * finding or selecting it: Acrobat finds and selects text in a file that
126
+ * forbids copying. A search's snippets reproduce the text, so they need
127
+ * `doc.text.copy`.
128
+ */
129
+ function materializePdfPermissions(b) {
130
+ const out = /* @__PURE__ */ new Set();
131
+ out.add("doc.open");
132
+ out.add("doc.render");
133
+ out.add("doc.annotate.read");
134
+ out.add("doc.forms.read");
135
+ out.add("doc.text.search");
136
+ out.add("doc.text.select");
137
+ if (b.bit5) {
138
+ out.add("doc.text.copy");
139
+ out.add("doc.content.copy");
140
+ }
141
+ if (b.bit3) out.add("doc.print");
142
+ if (b.bit12 && b.bit3) out.add("doc.print.high");
143
+ if (b.bit4) {
144
+ out.add("doc.pages.modify");
145
+ out.add("doc.redact");
146
+ out.add("doc.metadata.modify");
147
+ out.add("doc.attachments.modify");
148
+ }
149
+ if (b.bit4 || b.bit11) out.add("doc.pages.assemble");
150
+ if (b.bit6) out.add("doc.annotate.modify");
151
+ if (b.bit4 || b.bit6 || b.bit9) {
152
+ out.add("doc.forms.fill");
153
+ out.add("doc.sign");
154
+ }
155
+ if (b.bit6 && b.bit4) out.add("doc.forms.modify");
156
+ return [...out];
157
+ }
158
+ //#endregion
159
+ export { pdfPermissions as i, collab as n, materializePdfPermissions as r, caps as t };
160
+
161
+ //# sourceMappingURL=builders-CNj0POeY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builders-CNj0POeY.js","names":[],"sources":["../src/auth/scope/builders.ts"],"sourcesContent":["import type { DocCapability, PdfBits } from './types';\n\n/**\n * Typed capability constants for customer-side JWT minting.\n *\n * The shape mirrors the dotted capability name so it reads naturally:\n * caps.doc.text.copy() // \"doc.text.copy\"\n * caps.doc.download() // \"doc.download\"\n * caps.doc.download.flattened() // \"doc.download.flattened\"\n * caps.doc.print.high() // \"doc.print.high\"\n *\n * Each leaf is a function returning the literal string (as `const`) so\n * TypeScript catches typos at the call site. Wrappers like `download`\n * and `print` are `Object.assign`'d to be callable and carry child\n * properties for the refinement capabilities.\n */\nexport const caps = {\n doc: {\n open: () => 'doc.open' as const,\n render: () => 'doc.render' as const,\n text: {\n select: () => 'doc.text.select' as const,\n copy: () => 'doc.text.copy' as const,\n search: () => 'doc.text.search' as const,\n },\n content: {\n copy: () => 'doc.content.copy' as const,\n },\n download: Object.assign(() => 'doc.download' as const, {\n flattened: () => 'doc.download.flattened' as const,\n }),\n print: Object.assign(() => 'doc.print' as const, {\n high: () => 'doc.print.high' as const,\n }),\n pages: {\n modify: () => 'doc.pages.modify' as const,\n assemble: () => 'doc.pages.assemble' as const,\n },\n forms: {\n read: () => 'doc.forms.read' as const,\n fill: () => 'doc.forms.fill' as const,\n modify: () => 'doc.forms.modify' as const,\n import: () => 'doc.forms.import' as const,\n script: () => 'doc.forms.script' as const,\n submit: () => 'doc.forms.submit' as const,\n },\n annotate: {\n read: () => 'doc.annotate.read' as const,\n modify: () => 'doc.annotate.modify' as const,\n import: () => 'doc.annotate.import' as const,\n },\n metadata: {\n modify: () => 'doc.metadata.modify' as const,\n },\n attachments: {\n modify: () => 'doc.attachments.modify' as const,\n },\n redact: () => 'doc.redact' as const,\n sign: Object.assign(() => 'doc.sign' as const, {\n certify: () => 'doc.sign.certify' as const,\n }),\n },\n} as const;\n\n/**\n * Builder factory for collab scope filters. Each entity:action pair\n * gets a sub-object with the four filter constructors.\n *\n * collab.annotations.create.self() → \"annotations:create:self\"\n * collab.annotations.create.group(\"legal\") → \"annotations:create:group=legal\"\n * collab.annotations.update.group(\"4\") → \"annotations:update:group=4\"\n * collab.annotations.delete.createdBy(\"u-7\") → \"annotations:delete:createdBy=u-7\"\n * collab.annotations.setGroup.group(\"legal\") → \"annotations:set-group:group=legal\"\n * collab.annotations.all.all() → \"annotations:*:all\" (action wildcard)\n * collab.fields.fill.group(\"buyer\") → \"fields:fill:group=buyer\"\n * collab.fields.sign.group(\"buyer\") → \"fields:sign:group=buyer\"\n * collab.fields.all.group(\"seller\") → \"fields:*:group=seller\"\n *\n * On create, the filter is evaluated against the caller's own identity\n * (no impersonation), so `:self` and `:all` trivially pass; `:group=X`\n * is the meaningful filter — it constrains creation to callers whose\n * default group is X.\n */\nexport const collab = {\n annotations: {\n create: makeFilterBuilder('annotations', 'create'),\n update: makeFilterBuilder('annotations', 'update'),\n delete: makeFilterBuilder('annotations', 'delete'),\n setGroup: makeGroupFilterBuilder('annotations', 'set-group'),\n /** Action wildcard — matches create, update, delete, and set-group with the given filter. */\n all: makeFilterBuilder('annotations', '*'),\n },\n /** Form fields, by group: a field records no creator, so only `:all` and `:group=X`. */\n fields: {\n fill: makeGroupFilterBuilder('fields', 'fill'),\n sign: makeGroupFilterBuilder('fields', 'sign'),\n setGroup: makeGroupFilterBuilder('fields', 'set-group'),\n /** Action wildcard — matches fill, sign, and set-group with the given filter. */\n all: makeGroupFilterBuilder('fields', '*'),\n },\n} as const;\n\ninterface FilterBuilder {\n all(): string;\n self(): string;\n createdBy(userId: string): string;\n group(groupId: string): string;\n}\n\nfunction makeFilterBuilder(entity: string, action: string): FilterBuilder {\n return {\n all: () => `${entity}:${action}:all`,\n self: () => `${entity}:${action}:self`,\n createdBy: (userId: string) => `${entity}:${action}:createdBy=${userId}`,\n group: (groupId: string) => `${entity}:${action}:group=${groupId}`,\n };\n}\n\n/**\n * The scopes that take only `:all` and `:group=X`: `set-group`, an\n * assignment authority rather than a per-record filter (assign-to-any vs\n * assign-to-X), and every field scope, since a field records no creator.\n * The builder exposes exactly those two — a typo at JWT mint time is caught\n * by the compiler instead of producing a JWT that fails at verify.\n */\ninterface GroupFilterBuilder {\n all(): string;\n group(groupId: string): string;\n}\n\nfunction makeGroupFilterBuilder(entity: string, action: string): GroupFilterBuilder {\n return {\n all: () => `${entity}:${action}:all`,\n group: (groupId: string) => `${entity}:${action}:group=${groupId}`,\n };\n}\n\n/**\n * Builder for the `pdf.permissions` virtual scope. Returns the literal\n * string; provided as a helper for parity with caps/collab in JWT\n * construction code.\n */\nexport const pdfPermissions = (): 'pdf.permissions' => 'pdf.permissions';\n\n/**\n * Materialise `pdf.permissions` into the concrete capability list it\n * would expand to under the given PDF bit configuration.\n *\n * Useful when the customer wants to start from PDF defaults and then\n * subtract specific capabilities — easier to build the JWT scope array\n * by filtering an explicit list than by composing virtual + denials.\n *\n * const defaults = materializePdfPermissions(pdfBits);\n * const scope = [\n * ...defaults.filter(s => s !== 'doc.text.copy'),\n * 'doc.download',\n * ];\n *\n * This is the one reading of the bits: the scope resolver and the\n * permission advisory both use it. It follows what Acrobat allows on a\n * file with these bits, which is broader than ISO 32000 in two places:\n * bit 4 (\"changing the document\") also allows filling in and signing, and\n * bit 5 (\"copying text and graphics\") governs taking the text out, not\n * finding or selecting it: Acrobat finds and selects text in a file that\n * forbids copying. A search's snippets reproduce the text, so they need\n * `doc.text.copy`.\n */\nexport function materializePdfPermissions(b: PdfBits): DocCapability[] {\n const out = new Set<DocCapability>();\n\n // Always — pdf.permissions means \"give me a working session\"\n out.add('doc.open');\n out.add('doc.render');\n // Reading existing annotations and form values is unconditional —\n // PDF bit 6 governs writes, not visibility.\n out.add('doc.annotate.read');\n out.add('doc.forms.read');\n // Finding and selecting text are too: bit 5 governs taking it out.\n out.add('doc.text.search');\n out.add('doc.text.select');\n\n if (b.bit5) {\n out.add('doc.text.copy');\n out.add('doc.content.copy');\n }\n if (b.bit3) out.add('doc.print');\n if (b.bit12 && b.bit3) out.add('doc.print.high');\n if (b.bit4) {\n out.add('doc.pages.modify');\n out.add('doc.redact');\n out.add('doc.metadata.modify');\n out.add('doc.attachments.modify');\n }\n // Bit 11 assembles pages even when bit 4 is clear; bit 4 includes it.\n if (b.bit4 || b.bit11) out.add('doc.pages.assemble');\n if (b.bit6) out.add('doc.annotate.modify');\n // Signing a signature field is filling it in. Acrobat (and PDFium's form\n // filler) let any of the three bits fill in.\n if (b.bit4 || b.bit6 || b.bit9) {\n out.add('doc.forms.fill');\n out.add('doc.sign');\n }\n // Changing existing fields takes both: Acrobat keeps them in fill mode\n // under bit 4 alone, and offers no form tools under bit 6 or 9 alone.\n if (b.bit6 && b.bit4) out.add('doc.forms.modify');\n\n return [...out];\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAa,OAAO,EAClB,KAAK;CACH,YAAY;CACZ,cAAc;CACd,MAAM;EACJ,cAAc;EACd,YAAY;EACZ,cAAc;CAChB;CACA,SAAS,EACP,YAAY,mBACd;CACA,UAAU,OAAO,aAAa,gBAAyB,EACrD,iBAAiB,yBACnB,CAAC;CACD,OAAO,OAAO,aAAa,aAAsB,EAC/C,YAAY,iBACd,CAAC;CACD,OAAO;EACL,cAAc;EACd,gBAAgB;CAClB;CACA,OAAO;EACL,YAAY;EACZ,YAAY;EACZ,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;CACA,UAAU;EACR,YAAY;EACZ,cAAc;EACd,cAAc;CAChB;CACA,UAAU,EACR,cAAc,sBAChB;CACA,aAAa,EACX,cAAc,yBAChB;CACA,cAAc;CACd,MAAM,OAAO,aAAa,YAAqB,EAC7C,eAAe,mBACjB,CAAC;AACH,EACF;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,SAAS;CACpB,aAAa;EACX,QAAQ,kBAAkB,eAAe,QAAQ;EACjD,QAAQ,kBAAkB,eAAe,QAAQ;EACjD,QAAQ,kBAAkB,eAAe,QAAQ;EACjD,UAAU,uBAAuB,eAAe,WAAW;;EAE3D,KAAK,kBAAkB,eAAe,GAAG;CAC3C;;CAEA,QAAQ;EACN,MAAM,uBAAuB,UAAU,MAAM;EAC7C,MAAM,uBAAuB,UAAU,MAAM;EAC7C,UAAU,uBAAuB,UAAU,WAAW;;EAEtD,KAAK,uBAAuB,UAAU,GAAG;CAC3C;AACF;AASA,SAAS,kBAAkB,QAAgB,QAA+B;CACxE,OAAO;EACL,WAAW,GAAG,OAAO,GAAG,OAAO;EAC/B,YAAY,GAAG,OAAO,GAAG,OAAO;EAChC,YAAY,WAAmB,GAAG,OAAO,GAAG,OAAO,aAAa;EAChE,QAAQ,YAAoB,GAAG,OAAO,GAAG,OAAO,SAAS;CAC3D;AACF;AAcA,SAAS,uBAAuB,QAAgB,QAAoC;CAClF,OAAO;EACL,WAAW,GAAG,OAAO,GAAG,OAAO;EAC/B,QAAQ,YAAoB,GAAG,OAAO,GAAG,OAAO,SAAS;CAC3D;AACF;;;;;;AAOA,MAAa,uBAA0C;;;;;;;;;;;;;;;;;;;;;;;;AAyBvD,SAAgB,0BAA0B,GAA6B;CACrE,MAAM,sBAAM,IAAI,IAAmB;CAGnC,IAAI,IAAI,UAAU;CAClB,IAAI,IAAI,YAAY;CAGpB,IAAI,IAAI,mBAAmB;CAC3B,IAAI,IAAI,gBAAgB;CAExB,IAAI,IAAI,iBAAiB;CACzB,IAAI,IAAI,iBAAiB;CAEzB,IAAI,EAAE,MAAM;EACV,IAAI,IAAI,eAAe;EACvB,IAAI,IAAI,kBAAkB;CAC5B;CACA,IAAI,EAAE,MAAM,IAAI,IAAI,WAAW;CAC/B,IAAI,EAAE,SAAS,EAAE,MAAM,IAAI,IAAI,gBAAgB;CAC/C,IAAI,EAAE,MAAM;EACV,IAAI,IAAI,kBAAkB;EAC1B,IAAI,IAAI,YAAY;EACpB,IAAI,IAAI,qBAAqB;EAC7B,IAAI,IAAI,wBAAwB;CAClC;CAEA,IAAI,EAAE,QAAQ,EAAE,OAAO,IAAI,IAAI,oBAAoB;CACnD,IAAI,EAAE,MAAM,IAAI,IAAI,qBAAqB;CAGzC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM;EAC9B,IAAI,IAAI,gBAAgB;EACxB,IAAI,IAAI,UAAU;CACpB;CAGA,IAAI,EAAE,QAAQ,EAAE,MAAM,IAAI,IAAI,kBAAkB;CAEhD,OAAO,CAAC,GAAG,GAAG;AAChB"}
@@ -0,0 +1,184 @@
1
+ //#region src/auth/scope/builders.ts
2
+ /**
3
+ * Typed capability constants for customer-side JWT minting.
4
+ *
5
+ * The shape mirrors the dotted capability name so it reads naturally:
6
+ * caps.doc.text.copy() // "doc.text.copy"
7
+ * caps.doc.download() // "doc.download"
8
+ * caps.doc.download.flattened() // "doc.download.flattened"
9
+ * caps.doc.print.high() // "doc.print.high"
10
+ *
11
+ * Each leaf is a function returning the literal string (as `const`) so
12
+ * TypeScript catches typos at the call site. Wrappers like `download`
13
+ * and `print` are `Object.assign`'d to be callable and carry child
14
+ * properties for the refinement capabilities.
15
+ */
16
+ const caps = { doc: {
17
+ open: () => "doc.open",
18
+ render: () => "doc.render",
19
+ text: {
20
+ select: () => "doc.text.select",
21
+ copy: () => "doc.text.copy",
22
+ search: () => "doc.text.search"
23
+ },
24
+ content: { copy: () => "doc.content.copy" },
25
+ download: Object.assign(() => "doc.download", { flattened: () => "doc.download.flattened" }),
26
+ print: Object.assign(() => "doc.print", { high: () => "doc.print.high" }),
27
+ pages: {
28
+ modify: () => "doc.pages.modify",
29
+ assemble: () => "doc.pages.assemble"
30
+ },
31
+ forms: {
32
+ read: () => "doc.forms.read",
33
+ fill: () => "doc.forms.fill",
34
+ modify: () => "doc.forms.modify",
35
+ import: () => "doc.forms.import",
36
+ script: () => "doc.forms.script",
37
+ submit: () => "doc.forms.submit"
38
+ },
39
+ annotate: {
40
+ read: () => "doc.annotate.read",
41
+ modify: () => "doc.annotate.modify",
42
+ import: () => "doc.annotate.import"
43
+ },
44
+ metadata: { modify: () => "doc.metadata.modify" },
45
+ attachments: { modify: () => "doc.attachments.modify" },
46
+ redact: () => "doc.redact",
47
+ sign: Object.assign(() => "doc.sign", { certify: () => "doc.sign.certify" })
48
+ } };
49
+ /**
50
+ * Builder factory for collab scope filters. Each entity:action pair
51
+ * gets a sub-object with the four filter constructors.
52
+ *
53
+ * collab.annotations.create.self() → "annotations:create:self"
54
+ * collab.annotations.create.group("legal") → "annotations:create:group=legal"
55
+ * collab.annotations.update.group("4") → "annotations:update:group=4"
56
+ * collab.annotations.delete.createdBy("u-7") → "annotations:delete:createdBy=u-7"
57
+ * collab.annotations.setGroup.group("legal") → "annotations:set-group:group=legal"
58
+ * collab.annotations.all.all() → "annotations:*:all" (action wildcard)
59
+ * collab.fields.fill.group("buyer") → "fields:fill:group=buyer"
60
+ * collab.fields.sign.group("buyer") → "fields:sign:group=buyer"
61
+ * collab.fields.all.group("seller") → "fields:*:group=seller"
62
+ *
63
+ * On create, the filter is evaluated against the caller's own identity
64
+ * (no impersonation), so `:self` and `:all` trivially pass; `:group=X`
65
+ * is the meaningful filter — it constrains creation to callers whose
66
+ * default group is X.
67
+ */
68
+ const collab = {
69
+ annotations: {
70
+ create: makeFilterBuilder("annotations", "create"),
71
+ update: makeFilterBuilder("annotations", "update"),
72
+ delete: makeFilterBuilder("annotations", "delete"),
73
+ setGroup: makeGroupFilterBuilder("annotations", "set-group"),
74
+ /** Action wildcard — matches create, update, delete, and set-group with the given filter. */
75
+ all: makeFilterBuilder("annotations", "*")
76
+ },
77
+ /** Form fields, by group: a field records no creator, so only `:all` and `:group=X`. */
78
+ fields: {
79
+ fill: makeGroupFilterBuilder("fields", "fill"),
80
+ sign: makeGroupFilterBuilder("fields", "sign"),
81
+ setGroup: makeGroupFilterBuilder("fields", "set-group"),
82
+ /** Action wildcard — matches fill, sign, and set-group with the given filter. */
83
+ all: makeGroupFilterBuilder("fields", "*")
84
+ }
85
+ };
86
+ function makeFilterBuilder(entity, action) {
87
+ return {
88
+ all: () => `${entity}:${action}:all`,
89
+ self: () => `${entity}:${action}:self`,
90
+ createdBy: (userId) => `${entity}:${action}:createdBy=${userId}`,
91
+ group: (groupId) => `${entity}:${action}:group=${groupId}`
92
+ };
93
+ }
94
+ function makeGroupFilterBuilder(entity, action) {
95
+ return {
96
+ all: () => `${entity}:${action}:all`,
97
+ group: (groupId) => `${entity}:${action}:group=${groupId}`
98
+ };
99
+ }
100
+ /**
101
+ * Builder for the `pdf.permissions` virtual scope. Returns the literal
102
+ * string; provided as a helper for parity with caps/collab in JWT
103
+ * construction code.
104
+ */
105
+ const pdfPermissions = () => "pdf.permissions";
106
+ /**
107
+ * Materialise `pdf.permissions` into the concrete capability list it
108
+ * would expand to under the given PDF bit configuration.
109
+ *
110
+ * Useful when the customer wants to start from PDF defaults and then
111
+ * subtract specific capabilities — easier to build the JWT scope array
112
+ * by filtering an explicit list than by composing virtual + denials.
113
+ *
114
+ * const defaults = materializePdfPermissions(pdfBits);
115
+ * const scope = [
116
+ * ...defaults.filter(s => s !== 'doc.text.copy'),
117
+ * 'doc.download',
118
+ * ];
119
+ *
120
+ * This is the one reading of the bits: the scope resolver and the
121
+ * permission advisory both use it. It follows what Acrobat allows on a
122
+ * file with these bits, which is broader than ISO 32000 in two places:
123
+ * bit 4 ("changing the document") also allows filling in and signing, and
124
+ * bit 5 ("copying text and graphics") governs taking the text out, not
125
+ * finding or selecting it: Acrobat finds and selects text in a file that
126
+ * forbids copying. A search's snippets reproduce the text, so they need
127
+ * `doc.text.copy`.
128
+ */
129
+ function materializePdfPermissions(b) {
130
+ const out = /* @__PURE__ */ new Set();
131
+ out.add("doc.open");
132
+ out.add("doc.render");
133
+ out.add("doc.annotate.read");
134
+ out.add("doc.forms.read");
135
+ out.add("doc.text.search");
136
+ out.add("doc.text.select");
137
+ if (b.bit5) {
138
+ out.add("doc.text.copy");
139
+ out.add("doc.content.copy");
140
+ }
141
+ if (b.bit3) out.add("doc.print");
142
+ if (b.bit12 && b.bit3) out.add("doc.print.high");
143
+ if (b.bit4) {
144
+ out.add("doc.pages.modify");
145
+ out.add("doc.redact");
146
+ out.add("doc.metadata.modify");
147
+ out.add("doc.attachments.modify");
148
+ }
149
+ if (b.bit4 || b.bit11) out.add("doc.pages.assemble");
150
+ if (b.bit6) out.add("doc.annotate.modify");
151
+ if (b.bit4 || b.bit6 || b.bit9) {
152
+ out.add("doc.forms.fill");
153
+ out.add("doc.sign");
154
+ }
155
+ if (b.bit6 && b.bit4) out.add("doc.forms.modify");
156
+ return [...out];
157
+ }
158
+ //#endregion
159
+ Object.defineProperty(exports, "caps", {
160
+ enumerable: true,
161
+ get: function() {
162
+ return caps;
163
+ }
164
+ });
165
+ Object.defineProperty(exports, "collab", {
166
+ enumerable: true,
167
+ get: function() {
168
+ return collab;
169
+ }
170
+ });
171
+ Object.defineProperty(exports, "materializePdfPermissions", {
172
+ enumerable: true,
173
+ get: function() {
174
+ return materializePdfPermissions;
175
+ }
176
+ });
177
+ Object.defineProperty(exports, "pdfPermissions", {
178
+ enumerable: true,
179
+ get: function() {
180
+ return pdfPermissions;
181
+ }
182
+ });
183
+
184
+ //# sourceMappingURL=builders-Cgdp_YCn.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builders-Cgdp_YCn.cjs","names":[],"sources":["../src/auth/scope/builders.ts"],"sourcesContent":["import type { DocCapability, PdfBits } from './types';\n\n/**\n * Typed capability constants for customer-side JWT minting.\n *\n * The shape mirrors the dotted capability name so it reads naturally:\n * caps.doc.text.copy() // \"doc.text.copy\"\n * caps.doc.download() // \"doc.download\"\n * caps.doc.download.flattened() // \"doc.download.flattened\"\n * caps.doc.print.high() // \"doc.print.high\"\n *\n * Each leaf is a function returning the literal string (as `const`) so\n * TypeScript catches typos at the call site. Wrappers like `download`\n * and `print` are `Object.assign`'d to be callable and carry child\n * properties for the refinement capabilities.\n */\nexport const caps = {\n doc: {\n open: () => 'doc.open' as const,\n render: () => 'doc.render' as const,\n text: {\n select: () => 'doc.text.select' as const,\n copy: () => 'doc.text.copy' as const,\n search: () => 'doc.text.search' as const,\n },\n content: {\n copy: () => 'doc.content.copy' as const,\n },\n download: Object.assign(() => 'doc.download' as const, {\n flattened: () => 'doc.download.flattened' as const,\n }),\n print: Object.assign(() => 'doc.print' as const, {\n high: () => 'doc.print.high' as const,\n }),\n pages: {\n modify: () => 'doc.pages.modify' as const,\n assemble: () => 'doc.pages.assemble' as const,\n },\n forms: {\n read: () => 'doc.forms.read' as const,\n fill: () => 'doc.forms.fill' as const,\n modify: () => 'doc.forms.modify' as const,\n import: () => 'doc.forms.import' as const,\n script: () => 'doc.forms.script' as const,\n submit: () => 'doc.forms.submit' as const,\n },\n annotate: {\n read: () => 'doc.annotate.read' as const,\n modify: () => 'doc.annotate.modify' as const,\n import: () => 'doc.annotate.import' as const,\n },\n metadata: {\n modify: () => 'doc.metadata.modify' as const,\n },\n attachments: {\n modify: () => 'doc.attachments.modify' as const,\n },\n redact: () => 'doc.redact' as const,\n sign: Object.assign(() => 'doc.sign' as const, {\n certify: () => 'doc.sign.certify' as const,\n }),\n },\n} as const;\n\n/**\n * Builder factory for collab scope filters. Each entity:action pair\n * gets a sub-object with the four filter constructors.\n *\n * collab.annotations.create.self() → \"annotations:create:self\"\n * collab.annotations.create.group(\"legal\") → \"annotations:create:group=legal\"\n * collab.annotations.update.group(\"4\") → \"annotations:update:group=4\"\n * collab.annotations.delete.createdBy(\"u-7\") → \"annotations:delete:createdBy=u-7\"\n * collab.annotations.setGroup.group(\"legal\") → \"annotations:set-group:group=legal\"\n * collab.annotations.all.all() → \"annotations:*:all\" (action wildcard)\n * collab.fields.fill.group(\"buyer\") → \"fields:fill:group=buyer\"\n * collab.fields.sign.group(\"buyer\") → \"fields:sign:group=buyer\"\n * collab.fields.all.group(\"seller\") → \"fields:*:group=seller\"\n *\n * On create, the filter is evaluated against the caller's own identity\n * (no impersonation), so `:self` and `:all` trivially pass; `:group=X`\n * is the meaningful filter — it constrains creation to callers whose\n * default group is X.\n */\nexport const collab = {\n annotations: {\n create: makeFilterBuilder('annotations', 'create'),\n update: makeFilterBuilder('annotations', 'update'),\n delete: makeFilterBuilder('annotations', 'delete'),\n setGroup: makeGroupFilterBuilder('annotations', 'set-group'),\n /** Action wildcard — matches create, update, delete, and set-group with the given filter. */\n all: makeFilterBuilder('annotations', '*'),\n },\n /** Form fields, by group: a field records no creator, so only `:all` and `:group=X`. */\n fields: {\n fill: makeGroupFilterBuilder('fields', 'fill'),\n sign: makeGroupFilterBuilder('fields', 'sign'),\n setGroup: makeGroupFilterBuilder('fields', 'set-group'),\n /** Action wildcard — matches fill, sign, and set-group with the given filter. */\n all: makeGroupFilterBuilder('fields', '*'),\n },\n} as const;\n\ninterface FilterBuilder {\n all(): string;\n self(): string;\n createdBy(userId: string): string;\n group(groupId: string): string;\n}\n\nfunction makeFilterBuilder(entity: string, action: string): FilterBuilder {\n return {\n all: () => `${entity}:${action}:all`,\n self: () => `${entity}:${action}:self`,\n createdBy: (userId: string) => `${entity}:${action}:createdBy=${userId}`,\n group: (groupId: string) => `${entity}:${action}:group=${groupId}`,\n };\n}\n\n/**\n * The scopes that take only `:all` and `:group=X`: `set-group`, an\n * assignment authority rather than a per-record filter (assign-to-any vs\n * assign-to-X), and every field scope, since a field records no creator.\n * The builder exposes exactly those two — a typo at JWT mint time is caught\n * by the compiler instead of producing a JWT that fails at verify.\n */\ninterface GroupFilterBuilder {\n all(): string;\n group(groupId: string): string;\n}\n\nfunction makeGroupFilterBuilder(entity: string, action: string): GroupFilterBuilder {\n return {\n all: () => `${entity}:${action}:all`,\n group: (groupId: string) => `${entity}:${action}:group=${groupId}`,\n };\n}\n\n/**\n * Builder for the `pdf.permissions` virtual scope. Returns the literal\n * string; provided as a helper for parity with caps/collab in JWT\n * construction code.\n */\nexport const pdfPermissions = (): 'pdf.permissions' => 'pdf.permissions';\n\n/**\n * Materialise `pdf.permissions` into the concrete capability list it\n * would expand to under the given PDF bit configuration.\n *\n * Useful when the customer wants to start from PDF defaults and then\n * subtract specific capabilities — easier to build the JWT scope array\n * by filtering an explicit list than by composing virtual + denials.\n *\n * const defaults = materializePdfPermissions(pdfBits);\n * const scope = [\n * ...defaults.filter(s => s !== 'doc.text.copy'),\n * 'doc.download',\n * ];\n *\n * This is the one reading of the bits: the scope resolver and the\n * permission advisory both use it. It follows what Acrobat allows on a\n * file with these bits, which is broader than ISO 32000 in two places:\n * bit 4 (\"changing the document\") also allows filling in and signing, and\n * bit 5 (\"copying text and graphics\") governs taking the text out, not\n * finding or selecting it: Acrobat finds and selects text in a file that\n * forbids copying. A search's snippets reproduce the text, so they need\n * `doc.text.copy`.\n */\nexport function materializePdfPermissions(b: PdfBits): DocCapability[] {\n const out = new Set<DocCapability>();\n\n // Always — pdf.permissions means \"give me a working session\"\n out.add('doc.open');\n out.add('doc.render');\n // Reading existing annotations and form values is unconditional —\n // PDF bit 6 governs writes, not visibility.\n out.add('doc.annotate.read');\n out.add('doc.forms.read');\n // Finding and selecting text are too: bit 5 governs taking it out.\n out.add('doc.text.search');\n out.add('doc.text.select');\n\n if (b.bit5) {\n out.add('doc.text.copy');\n out.add('doc.content.copy');\n }\n if (b.bit3) out.add('doc.print');\n if (b.bit12 && b.bit3) out.add('doc.print.high');\n if (b.bit4) {\n out.add('doc.pages.modify');\n out.add('doc.redact');\n out.add('doc.metadata.modify');\n out.add('doc.attachments.modify');\n }\n // Bit 11 assembles pages even when bit 4 is clear; bit 4 includes it.\n if (b.bit4 || b.bit11) out.add('doc.pages.assemble');\n if (b.bit6) out.add('doc.annotate.modify');\n // Signing a signature field is filling it in. Acrobat (and PDFium's form\n // filler) let any of the three bits fill in.\n if (b.bit4 || b.bit6 || b.bit9) {\n out.add('doc.forms.fill');\n out.add('doc.sign');\n }\n // Changing existing fields takes both: Acrobat keeps them in fill mode\n // under bit 4 alone, and offers no form tools under bit 6 or 9 alone.\n if (b.bit6 && b.bit4) out.add('doc.forms.modify');\n\n return [...out];\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAa,OAAO,EAClB,KAAK;CACH,YAAY;CACZ,cAAc;CACd,MAAM;EACJ,cAAc;EACd,YAAY;EACZ,cAAc;CAChB;CACA,SAAS,EACP,YAAY,mBACd;CACA,UAAU,OAAO,aAAa,gBAAyB,EACrD,iBAAiB,yBACnB,CAAC;CACD,OAAO,OAAO,aAAa,aAAsB,EAC/C,YAAY,iBACd,CAAC;CACD,OAAO;EACL,cAAc;EACd,gBAAgB;CAClB;CACA,OAAO;EACL,YAAY;EACZ,YAAY;EACZ,cAAc;EACd,cAAc;EACd,cAAc;EACd,cAAc;CAChB;CACA,UAAU;EACR,YAAY;EACZ,cAAc;EACd,cAAc;CAChB;CACA,UAAU,EACR,cAAc,sBAChB;CACA,aAAa,EACX,cAAc,yBAChB;CACA,cAAc;CACd,MAAM,OAAO,aAAa,YAAqB,EAC7C,eAAe,mBACjB,CAAC;AACH,EACF;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,SAAS;CACpB,aAAa;EACX,QAAQ,kBAAkB,eAAe,QAAQ;EACjD,QAAQ,kBAAkB,eAAe,QAAQ;EACjD,QAAQ,kBAAkB,eAAe,QAAQ;EACjD,UAAU,uBAAuB,eAAe,WAAW;;EAE3D,KAAK,kBAAkB,eAAe,GAAG;CAC3C;;CAEA,QAAQ;EACN,MAAM,uBAAuB,UAAU,MAAM;EAC7C,MAAM,uBAAuB,UAAU,MAAM;EAC7C,UAAU,uBAAuB,UAAU,WAAW;;EAEtD,KAAK,uBAAuB,UAAU,GAAG;CAC3C;AACF;AASA,SAAS,kBAAkB,QAAgB,QAA+B;CACxE,OAAO;EACL,WAAW,GAAG,OAAO,GAAG,OAAO;EAC/B,YAAY,GAAG,OAAO,GAAG,OAAO;EAChC,YAAY,WAAmB,GAAG,OAAO,GAAG,OAAO,aAAa;EAChE,QAAQ,YAAoB,GAAG,OAAO,GAAG,OAAO,SAAS;CAC3D;AACF;AAcA,SAAS,uBAAuB,QAAgB,QAAoC;CAClF,OAAO;EACL,WAAW,GAAG,OAAO,GAAG,OAAO;EAC/B,QAAQ,YAAoB,GAAG,OAAO,GAAG,OAAO,SAAS;CAC3D;AACF;;;;;;AAOA,MAAa,uBAA0C;;;;;;;;;;;;;;;;;;;;;;;;AAyBvD,SAAgB,0BAA0B,GAA6B;CACrE,MAAM,sBAAM,IAAI,IAAmB;CAGnC,IAAI,IAAI,UAAU;CAClB,IAAI,IAAI,YAAY;CAGpB,IAAI,IAAI,mBAAmB;CAC3B,IAAI,IAAI,gBAAgB;CAExB,IAAI,IAAI,iBAAiB;CACzB,IAAI,IAAI,iBAAiB;CAEzB,IAAI,EAAE,MAAM;EACV,IAAI,IAAI,eAAe;EACvB,IAAI,IAAI,kBAAkB;CAC5B;CACA,IAAI,EAAE,MAAM,IAAI,IAAI,WAAW;CAC/B,IAAI,EAAE,SAAS,EAAE,MAAM,IAAI,IAAI,gBAAgB;CAC/C,IAAI,EAAE,MAAM;EACV,IAAI,IAAI,kBAAkB;EAC1B,IAAI,IAAI,YAAY;EACpB,IAAI,IAAI,qBAAqB;EAC7B,IAAI,IAAI,wBAAwB;CAClC;CAEA,IAAI,EAAE,QAAQ,EAAE,OAAO,IAAI,IAAI,oBAAoB;CACnD,IAAI,EAAE,MAAM,IAAI,IAAI,qBAAqB;CAGzC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM;EAC9B,IAAI,IAAI,gBAAgB;EACxB,IAAI,IAAI,UAAU;CACpB;CAGA,IAAI,EAAE,QAAQ,EAAE,MAAM,IAAI,IAAI,kBAAkB;CAEhD,OAAO,CAAC,GAAG,GAAG;AAChB"}