@reportwright/viewer 0.12.0 → 0.13.0

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 (89) hide show
  1. package/CHANGELOG.md +133 -1
  2. package/README.md +43 -6
  3. package/THIRD-PARTY-NOTICES.md +52 -0
  4. package/dist/{chunk-SBD55ZES.js → chunk-BF7GCWZY.js} +103 -41
  5. package/dist/chunk-BF7GCWZY.js.map +6 -0
  6. package/dist/chunk-BR5K6SBL.js +324 -0
  7. package/dist/chunk-BR5K6SBL.js.map +6 -0
  8. package/dist/chunk-CNDUJ7IV.js +758 -0
  9. package/dist/chunk-CNDUJ7IV.js.map +6 -0
  10. package/dist/{chunk-RYHJUQSV.js → chunk-DXHLIJEY.js} +2 -2
  11. package/dist/{chunk-M6GENFAH.js → chunk-EK5CJY22.js} +4021 -4631
  12. package/dist/chunk-EK5CJY22.js.map +6 -0
  13. package/dist/{chunk-KJTRZJHN.js → chunk-F5EPQTPF.js} +4 -3
  14. package/dist/chunk-F5EPQTPF.js.map +6 -0
  15. package/dist/{chunk-SR2TQ2ZK.js → chunk-F6RMRXIN.js} +2 -2
  16. package/dist/chunk-F6RMRXIN.js.map +6 -0
  17. package/dist/chunk-FEM2QVOO.js +18 -0
  18. package/dist/{chunk-ODREGGKA.js → chunk-IFYCJZNS.js} +9 -6
  19. package/dist/chunk-IFYCJZNS.js.map +6 -0
  20. package/dist/{chunk-EOVGKHAS.js → chunk-L6YEIVVD.js} +86 -57
  21. package/dist/chunk-L6YEIVVD.js.map +6 -0
  22. package/dist/{chunk-APRPSQOD.js → chunk-PQNM6ET7.js} +28 -9
  23. package/dist/chunk-PQNM6ET7.js.map +6 -0
  24. package/dist/chunk-QFLVVM3H.js +856 -0
  25. package/dist/chunk-QFLVVM3H.js.map +6 -0
  26. package/dist/{chunk-5N6OFCHJ.js → chunk-TZXEEVKE.js} +1319 -76
  27. package/dist/chunk-TZXEEVKE.js.map +6 -0
  28. package/dist/{chunk-FARG6X2U.js → chunk-UHHURTSV.js} +15 -9
  29. package/dist/chunk-UHHURTSV.js.map +6 -0
  30. package/dist/chunk-UJL7C2AS.js +546 -0
  31. package/dist/chunk-UJL7C2AS.js.map +6 -0
  32. package/dist/chunk-YIX3OJXU.js +34 -0
  33. package/dist/designer.d.ts +19 -4
  34. package/dist/designer.js +616 -405
  35. package/dist/designer.js.map +3 -3
  36. package/dist/{peer/chunk-GBITRNHE.js → engine.worker.js} +11006 -9030
  37. package/dist/engine.worker.js.map +6 -0
  38. package/dist/peer/{chunk-NPYKZINU.js → chunk-2CD5COHN.js} +66 -37
  39. package/dist/peer/chunk-2CD5COHN.js.map +6 -0
  40. package/dist/peer/{chunk-IPU2YRL2.js → chunk-3CBV5SAI.js} +28 -9
  41. package/dist/peer/chunk-3CBV5SAI.js.map +6 -0
  42. package/dist/peer/{chunk-MCJPN2KL.js → chunk-45GVDKP5.js} +15 -9
  43. package/dist/peer/chunk-45GVDKP5.js.map +6 -0
  44. package/dist/peer/{chunk-76ZABVTI.js → chunk-LWXQX3NJ.js} +4 -3
  45. package/dist/peer/chunk-MKY3SDXU.js +758 -0
  46. package/dist/peer/chunk-MKY3SDXU.js.map +6 -0
  47. package/dist/peer/chunk-S6LSPHSU.js +17 -0
  48. package/dist/peer/chunk-S6LSPHSU.js.map +6 -0
  49. package/dist/peer/{chunk-M4AGFUWE.js → chunk-V42KN7HD.js} +2 -2
  50. package/dist/peer/{chunk-KBT6ZGGO.js → chunk-VZHHNQYB.js} +1319 -76
  51. package/dist/peer/chunk-VZHHNQYB.js.map +6 -0
  52. package/dist/peer/{chunk-Y5CAHLXS.js → chunk-YITWGAR4.js} +9 -6
  53. package/dist/peer/chunk-YITWGAR4.js.map +6 -0
  54. package/dist/peer/chunk-Z5II55QT.js +33 -0
  55. package/dist/peer/chunk-Z5II55QT.js.map +6 -0
  56. package/dist/peer/designer.js +473 -262
  57. package/dist/peer/designer.js.map +3 -3
  58. package/dist/peer/engine.worker.js +16782 -0
  59. package/dist/peer/engine.worker.js.map +6 -0
  60. package/dist/peer/viewer.js +17 -7
  61. package/dist/peer/viewer.js.map +1 -1
  62. package/dist/viewer.d.ts +11 -2
  63. package/dist/viewer.js +17 -7
  64. package/dist/viewer.js.map +1 -1
  65. package/package.json +4 -2
  66. package/dist/chunk-3D43XGIN.js +0 -1167
  67. package/dist/chunk-3D43XGIN.js.map +0 -6
  68. package/dist/chunk-5N6OFCHJ.js.map +0 -6
  69. package/dist/chunk-AH47FS6Y.js +0 -13
  70. package/dist/chunk-APRPSQOD.js.map +0 -6
  71. package/dist/chunk-EOVGKHAS.js.map +0 -6
  72. package/dist/chunk-FARG6X2U.js.map +0 -6
  73. package/dist/chunk-M6GENFAH.js.map +0 -6
  74. package/dist/chunk-ODREGGKA.js.map +0 -6
  75. package/dist/chunk-SBD55ZES.js.map +0 -6
  76. package/dist/chunk-SR2TQ2ZK.js.map +0 -6
  77. package/dist/peer/chunk-76ZABVTI.js.map +0 -6
  78. package/dist/peer/chunk-GBITRNHE.js.map +0 -6
  79. package/dist/peer/chunk-IMQRHDR4.js +0 -12
  80. package/dist/peer/chunk-IPU2YRL2.js.map +0 -6
  81. package/dist/peer/chunk-KBT6ZGGO.js.map +0 -6
  82. package/dist/peer/chunk-MCJPN2KL.js.map +0 -6
  83. package/dist/peer/chunk-NPYKZINU.js.map +0 -6
  84. package/dist/peer/chunk-Y5CAHLXS.js.map +0 -6
  85. /package/dist/{chunk-RYHJUQSV.js.map → chunk-DXHLIJEY.js.map} +0 -0
  86. /package/dist/{chunk-AH47FS6Y.js.map → chunk-FEM2QVOO.js.map} +0 -0
  87. /package/dist/{peer/chunk-IMQRHDR4.js.map → chunk-YIX3OJXU.js.map} +0 -0
  88. /package/dist/{chunk-KJTRZJHN.js.map → peer/chunk-LWXQX3NJ.js.map} +0 -0
  89. /package/dist/peer/{chunk-M4AGFUWE.js.map → chunk-V42KN7HD.js.map} +0 -0
@@ -0,0 +1,758 @@
1
+ import {
2
+ guardedFetch,
3
+ redactUrl,
4
+ resolvePage
5
+ } from "./chunk-BR5K6SBL.js";
6
+ import {
7
+ fontFamilyCss,
8
+ fontKeysOf
9
+ } from "./chunk-UJL7C2AS.js";
10
+ import {
11
+ CORE_FONT_KEY,
12
+ SHAPER,
13
+ fontFile,
14
+ isStandard,
15
+ setCustomFonts
16
+ } from "./chunk-QFLVVM3H.js";
17
+
18
+ // src/viewer/dataFetch.js
19
+ function sqlCall(body, sqlPreview) {
20
+ let b;
21
+ try {
22
+ b = JSON.parse(String(body));
23
+ } catch {
24
+ return false;
25
+ }
26
+ if (!b || typeof b !== "object" || Array.isArray(b)) return false;
27
+ const keys = Object.keys(b);
28
+ if (typeof b.report === "string" && typeof b.source === "string") return keys.every((k) => ["report", "source", "params"].includes(k));
29
+ return sqlPreview && typeof b.query === "string" && keys.every((k) => ["connection", "query", "params"].includes(k));
30
+ }
31
+ var policy = { allowHosts: [], unsafeFetch: false, fetch: null };
32
+ function setFetchPolicy({ allowHosts, unsafeFetch = false, fetch: f = null } = {}) {
33
+ policy = { allowHosts: (allowHosts || []).map((h) => String(h).toLowerCase().replace(/^\[|\]$/g, "")), unsafeFetch: !!unsafeFetch, fetch: typeof f === "function" ? f : null };
34
+ }
35
+ var POLICY_KEYS = ["allowHosts", "unsafeFetch", "allowPrivate"];
36
+ function policyKeysIn(def) {
37
+ const has = (o) => POLICY_KEYS.filter((k) => o && typeof o === "object" && Object.hasOwn(o, k));
38
+ return [...has(def), ...(Array.isArray(def?.dataSources) ? def.dataSources : []).flatMap((s) => has(s).map((k) => `${s.name}.${k}`))];
39
+ }
40
+ var fetchPolicy = () => policy;
41
+ function failed(e, url) {
42
+ if (e?.status || !(e instanceof TypeError)) return e;
43
+ return Object.assign(new Error(`the request to ${redactUrl(url)} failed (${e.message}): the server may not allow this page to read it (CORS: it must send Access-Control-Allow-Origin), the network or the server may be down, or the browser blocked it (a content security policy or an extension)`), { cause: e });
44
+ }
45
+ var DATA = [/^\/api\/sample\//, /^\/api\/data\/proxy$/];
46
+ var OURS = /^\/(?:$|api(?:\/|$)|admin(?:\/|$)|designer(?:\/|$)|viewer(?:\/|$)|login(?:\/|$)|embed(?:\/|$)|_next(?:\/|$))/i;
47
+ var BUSY = /* @__PURE__ */ new Set([429, 502, 503, 504]);
48
+ function withRetry(f, { onRetry, retries = 3, wait = (ms) => new Promise((r) => setTimeout(r, ms)) } = {}) {
49
+ return (
50
+ /** @type {any} */
51
+ (async (url, init = {}) => {
52
+ const method = String(init.method || "GET").toUpperCase();
53
+ const read = method === "GET" || method === "HEAD" || method === "POST" && /\/api\/data\/sql$/.test(new URL(String(url), "http://x").pathname);
54
+ for (let attempt = 1; ; attempt++) {
55
+ const res = await f(url, init);
56
+ if (!read || !BUSY.has(res.status) || attempt > retries) return res;
57
+ const after = Number(res.headers?.get?.("retry-after"));
58
+ const ms = Number.isFinite(after) && after >= 0 ? Math.min(1e4, after * 1e3) : Math.round(400 * 2 ** (attempt - 1) * (0.75 + Math.random() * 0.5));
59
+ onRetry?.({ attempt, max: retries, status: res.status });
60
+ await wait(ms);
61
+ }
62
+ })
63
+ );
64
+ }
65
+ function reportFetch(base, f0 = policy.fetch || ((...a) => fetch(...a)), { sqlPreview = false, onRetry, retries = 3, wait } = {}) {
66
+ const self = new URL(base).origin;
67
+ const { allowHosts, unsafeFetch } = policy;
68
+ const send = (url, init) => f0(url, init).catch((e) => {
69
+ throw failed(e, url);
70
+ });
71
+ const f = withRetry(send, { onRetry, retries, wait });
72
+ const guarded = unsafeFetch ? f : guardedFetch({ allowHosts, viaBase: true }, f);
73
+ const other = (url, init) => guarded(url, init).catch((e) => {
74
+ if (e?.code === "EPRIVATE") e.message = e.message.replace(/pass allowHosts: (\[[^\]]*\]) to render/, "mountViewer({ allowHosts: $1 })");
75
+ else if (e && typeof e === "object") e.message = String(e.message).replace("(pass your own fetch to render)", "(a browser cannot see where it leads: use the URL it redirects to, or render on the server)");
76
+ throw e;
77
+ });
78
+ const out = (
79
+ /** @type {any} */
80
+ (async (input, init = {}) => {
81
+ const u = new URL(String(input instanceof Request ? input.url : input), base);
82
+ const method = String(init.method || "GET").toUpperCase();
83
+ if (u.origin !== self) return other(u.href, { ...init, credentials: "omit" });
84
+ let path;
85
+ try {
86
+ path = decodeURIComponent(u.pathname).replace(/\/{2,}/g, "/");
87
+ } catch {
88
+ path = null;
89
+ }
90
+ const read = path !== null && ["GET", "HEAD"].includes(method) && !/%2f|%5c/i.test(u.pathname) && (DATA.some((r) => r.test(path)) || !OURS.test(path));
91
+ if (!read && !(method === "POST" && u.pathname === "/api/data/sql" && sqlCall(init.body, sqlPreview))) {
92
+ throw Object.assign(new Error(`A data source may only read data from this ReportWright server (sample data, the data proxy, saved SQL), not ${method} ${path}.`), { status: 403 });
93
+ }
94
+ const ours = DATA.some((r) => r.test(u.pathname)) || u.pathname === "/api/data/sql";
95
+ return f(u.href, { ...init, credentials: ours ? "same-origin" : "omit", redirect: "error" });
96
+ })
97
+ );
98
+ if (!unsafeFetch) out.hostRule = { allowHosts };
99
+ return out;
100
+ }
101
+
102
+ // src/exporters/subset.js
103
+ var HB_MEMORY_MODE_WRITABLE = 2;
104
+ var HB_SUBSET_SETS_DROP_TABLE_TAG = 3;
105
+ var HB_SUBSET_SETS_LAYOUT_FEATURE_TAG = 6;
106
+ var HB_SUBSET_FLAGS_RETAIN_GIDS = 2;
107
+ var HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 64;
108
+ var tag = (s) => [...s].reduce((a, c) => (a << 8) + c.charCodeAt(0), 0) >>> 0;
109
+ var WEIGHT_NAMES = { 100: "Thin", 200: "ExtraLight", 300: "Light", 400: "Regular", 500: "Medium", 600: "SemiBold", 700: "Bold", 800: "ExtraBold", 900: "Black" };
110
+ var WEIGHT_WORD = /\b(Thin|ExtraLight|UltraLight|Light|Regular|Medium|SemiBold|DemiBold|Bold|ExtraBold|UltraBold|Black|Heavy)\b/i;
111
+ var chars = (b) => {
112
+ let s = "";
113
+ for (const c of b) s += String.fromCharCode(c);
114
+ return s;
115
+ };
116
+ function sfntTables(bytes) {
117
+ const t = /* @__PURE__ */ new Map();
118
+ if (bytes.length < 12 || chars(bytes.subarray(0, 4)) === "ttcf") return t;
119
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
120
+ const n = dv.getUint16(4);
121
+ for (let i = 0; i < n; i++) {
122
+ const p = 12 + i * 16;
123
+ const off = dv.getUint32(p + 8), len = dv.getUint32(p + 12);
124
+ t.set(chars(bytes.subarray(p, p + 4)), bytes.subarray(off, off + len));
125
+ }
126
+ return t;
127
+ }
128
+ function buildSfnt(version, tables) {
129
+ const tags = [...tables.keys()].sort();
130
+ const n = tags.length, pow = 2 ** Math.floor(Math.log2(n));
131
+ const offs = /* @__PURE__ */ new Map();
132
+ let total = 12 + 16 * n;
133
+ for (const tg of tags) {
134
+ offs.set(tg, total);
135
+ total += tables.get(tg).length + 3 & ~3;
136
+ }
137
+ const out = new Uint8Array(total), dv = new DataView(out.buffer);
138
+ out.set(version.subarray ? version.subarray(0, 4) : [0, 1, 0, 0], 0);
139
+ dv.setUint16(4, n);
140
+ dv.setUint16(6, pow * 16);
141
+ dv.setUint16(8, Math.log2(pow));
142
+ dv.setUint16(10, n * 16 - pow * 16);
143
+ tags.forEach((tg, i) => {
144
+ const p = 12 + 16 * i, data = tables.get(tg), o = offs.get(tg);
145
+ for (let k = 0; k < 4; k++) out[p + k] = tg.charCodeAt(k);
146
+ out.set(data, o);
147
+ dv.setUint32(p + 4, tableSum(out, o, data.length + 3 & ~3));
148
+ dv.setUint32(p + 8, o);
149
+ dv.setUint32(p + 12, data.length);
150
+ });
151
+ if (offs.has("head")) {
152
+ const h = offs.get("head") + 8;
153
+ dv.setUint32(h, 0);
154
+ dv.setUint32(h, 2981146554 - tableSum(out, 0, out.length) >>> 0);
155
+ }
156
+ return out;
157
+ }
158
+ var tableSum = (b, o, len) => {
159
+ const dv = new DataView(b.buffer, b.byteOffset + o, len);
160
+ let s = 0;
161
+ for (let i = 0; i < len; i += 4) s = s + dv.getUint32(i) >>> 0;
162
+ return s;
163
+ };
164
+ function setNameStrings(name, strings) {
165
+ const dv = new DataView(name.buffer, name.byteOffset, name.byteLength);
166
+ const count = dv.getUint16(2), store = dv.getUint16(4);
167
+ const recs = [];
168
+ for (let i = 0; i < count; i++) {
169
+ const p = 6 + 12 * i;
170
+ const platform = dv.getUint16(p), id = dv.getUint16(p + 6), len = dv.getUint16(p + 8), off = store + dv.getUint16(p + 10);
171
+ const rec = { platform, enc: dv.getUint16(p + 2), lang: dv.getUint16(p + 4), id, raw: name.subarray(off, off + len) };
172
+ if (strings.has(id)) {
173
+ const s = strings.get(id);
174
+ rec.raw = platform === 1 ? Uint8Array.from(s, (c) => c.charCodeAt(0) & 255) : utf16(s);
175
+ }
176
+ recs.push(rec);
177
+ }
178
+ const size = 6 + 12 * count + recs.reduce((a, r) => a + r.raw.length, 0);
179
+ const out = new Uint8Array(size), o = new DataView(out.buffer);
180
+ o.setUint16(0, 0);
181
+ o.setUint16(2, count);
182
+ o.setUint16(4, 6 + 12 * count);
183
+ let at = 6 + 12 * count;
184
+ recs.forEach((r, i) => {
185
+ const p = 6 + 12 * i;
186
+ o.setUint16(p, r.platform);
187
+ o.setUint16(p + 2, r.enc);
188
+ o.setUint16(p + 4, r.lang);
189
+ o.setUint16(p + 6, r.id);
190
+ o.setUint16(p + 8, r.raw.length);
191
+ o.setUint16(p + 10, at - (6 + 12 * count));
192
+ out.set(r.raw, at);
193
+ at += r.raw.length;
194
+ });
195
+ return out;
196
+ }
197
+ var utf16 = (s) => {
198
+ const b = new Uint8Array(s.length * 2);
199
+ for (let i = 0; i < s.length; i++) {
200
+ b[2 * i] = s.charCodeAt(i) >> 8;
201
+ b[2 * i + 1] = s.charCodeAt(i) & 255;
202
+ }
203
+ return b;
204
+ };
205
+ function renameForWeight(tables, weight) {
206
+ const word = WEIGHT_NAMES[weight] || "Regular";
207
+ const nm = tables.get("name");
208
+ if (nm) {
209
+ const dv = new DataView(nm.buffer, nm.byteOffset, nm.byteLength);
210
+ const get = (id) => {
211
+ const count = dv.getUint16(2), store = dv.getUint16(4);
212
+ for (let i = 0; i < count; i++) {
213
+ const p = 6 + 12 * i;
214
+ if (dv.getUint16(p + 6) !== id) continue;
215
+ const platform = dv.getUint16(p), len = dv.getUint16(p + 8), off = store + dv.getUint16(p + 10);
216
+ const b = nm.subarray(off, off + len);
217
+ if (platform === 1) return chars(b);
218
+ let s = "";
219
+ for (let k = 0; k + 1 < b.length; k += 2) s += String.fromCharCode(b[k] << 8 | b[k + 1]);
220
+ return s;
221
+ }
222
+ return null;
223
+ };
224
+ const family = (get(16) ?? get(1) ?? "").replace(new RegExp(`\\s*\\b(${Object.values(WEIGHT_NAMES).join("|")})$`, "i"), "").trim() || get(1) || "Font";
225
+ const ps = get(6)?.replace(/-(\w+)$/, "") || family.replace(/\s+/g, "");
226
+ const strings = /* @__PURE__ */ new Map([
227
+ [1, family],
228
+ [2, word],
229
+ [3, (get(3) ?? "").replace(WEIGHT_WORD, word)],
230
+ [4, `${family} ${word}`],
231
+ [6, `${ps}-${word}`],
232
+ [16, family],
233
+ [17, word]
234
+ ]);
235
+ tables.set("name", setNameStrings(nm, strings));
236
+ }
237
+ const os2 = tables.get("OS/2");
238
+ if (os2 && os2.length >= 6) {
239
+ const copy = os2.slice();
240
+ new DataView(copy.buffer).setUint16(4, weight);
241
+ tables.set("OS/2", copy);
242
+ }
243
+ }
244
+ function createSubsetter(loadWasm) {
245
+ let hbP = null;
246
+ const hb = () => hbP || (hbP = (async () => {
247
+ const bytes = await loadWasm();
248
+ const u8 = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
249
+ const src = (
250
+ /** @type {any} */
251
+ u8
252
+ );
253
+ const instance = (
254
+ /** @type {any} */
255
+ globalThis.process?.versions?.node ? new WebAssembly.Instance(new WebAssembly.Module(src), {}) : (await WebAssembly.instantiate(src, {})).instance
256
+ );
257
+ const x = (
258
+ /** @type {any} */
259
+ instance.exports
260
+ );
261
+ x._initialize?.();
262
+ return x;
263
+ })());
264
+ return async function subset(font, codePoints, opt = {}) {
265
+ const x = await hb();
266
+ const heap = () => new Uint8Array(x.memory.buffer);
267
+ const variable = sfntTables(font).has("fvar");
268
+ const input = x.hb_subset_input_create_or_fail();
269
+ if (!input) throw new Error("HarfBuzz: no subset input");
270
+ const buf = x.malloc(font.byteLength);
271
+ heap().set(font, buf);
272
+ const blob = x.hb_blob_create(buf, font.byteLength, HB_MEMORY_MODE_WRITABLE, 0, 0);
273
+ const face = x.hb_face_create(blob, 0);
274
+ x.hb_blob_destroy(blob);
275
+ try {
276
+ if (!opt.layout) {
277
+ x.hb_set_clear(x.hb_subset_input_set(input, HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
278
+ const drop = x.hb_subset_input_set(input, HB_SUBSET_SETS_DROP_TABLE_TAG);
279
+ for (const t of ["GSUB", "GPOS", "GDEF", "kern", "morx", "mort"]) x.hb_set_add(drop, tag(t));
280
+ }
281
+ x.hb_subset_input_set_flags(input, x.hb_subset_input_get_flags(input) | HB_SUBSET_FLAGS_NOTDEF_OUTLINE);
282
+ const uni = x.hb_subset_input_unicode_set(input);
283
+ for (const cp of codePoints) x.hb_set_add(uni, cp);
284
+ if (opt.glyphs) {
285
+ x.hb_subset_input_set_flags(input, x.hb_subset_input_get_flags(input) | HB_SUBSET_FLAGS_RETAIN_GIDS);
286
+ const gs = x.hb_subset_input_glyph_set(input);
287
+ for (const g of opt.glyphs) x.hb_set_add(gs, g);
288
+ }
289
+ x.hb_subset_input_pin_all_axes_to_default(input, face);
290
+ x.hb_subset_input_pin_axis_location(input, face, tag("wght"), opt.weight ?? 400);
291
+ const sub = x.hb_subset_or_fail(face, input);
292
+ if (!sub) throw new Error("HarfBuzz: subsetting failed");
293
+ const res = x.hb_face_reference_blob(sub);
294
+ const off = x.hb_blob_get_data(res, 0);
295
+ const len = x.hb_blob_get_length(res);
296
+ let out = heap().slice(off, off + len);
297
+ x.hb_blob_destroy(res);
298
+ x.hb_face_destroy(sub);
299
+ if (!len) throw new Error("HarfBuzz: empty subset");
300
+ if (variable) {
301
+ const t = sfntTables(out);
302
+ for (const tg of ["fvar", "gvar", "avar", "cvar", "HVAR", "MVAR", "STAT"]) t.delete(tg);
303
+ renameForWeight(t, opt.weight ?? 400);
304
+ out = buildSfnt(out, t);
305
+ }
306
+ return out;
307
+ } finally {
308
+ x.hb_subset_input_destroy(input);
309
+ x.hb_face_destroy(face);
310
+ x.free(buf);
311
+ }
312
+ };
313
+ }
314
+
315
+ // src/viewer/engineClient.js
316
+ var assetBase = "";
317
+ function setAssetBase(url) {
318
+ assetBase = String(url || "").replace(/\/$/, "");
319
+ mainStore = null;
320
+ }
321
+ var origin = () => assetBase || window.location.origin;
322
+ var fontsUrl = null;
323
+ var standalone = false;
324
+ function setStandalone({ standalone: on = false, fontsUrl: f = null } = {}) {
325
+ standalone = !!on;
326
+ fontsUrl = f ? String(f).replace(/\/?$/, "/") : null;
327
+ mainStore = null;
328
+ fontList = null;
329
+ fontBytes.clear();
330
+ }
331
+ var fontsBase = () => fontsUrl || `${assetBase}/fonts/`;
332
+ var besideFonts = (file) => fontsUrl ? new URL(`../${file}`, new URL(fontsUrl, typeof location !== "undefined" ? location.href : void 0)).href : `${assetBase}/${file}`;
333
+ var subsetter = createSubsetter(async () => (await fetch(besideFonts("harfbuzz-subset.wasm"))).arrayBuffer());
334
+ var worker = null;
335
+ var workerBroken = false;
336
+ var seq = 0;
337
+ var waiting = /* @__PURE__ */ new Map();
338
+ var mainStore = null;
339
+ var bundledFonts = null;
340
+ var bundledList = null;
341
+ function setBundledFonts(map, list) {
342
+ bundledFonts = map || null;
343
+ bundledList = list || null;
344
+ mainStore = null;
345
+ fontList = null;
346
+ }
347
+ var b64ToBuffer = (b64) => {
348
+ const s = atob(b64);
349
+ const u = new Uint8Array(s.length);
350
+ for (let i = 0; i < s.length; i++) u[i] = s.charCodeAt(i);
351
+ return u.buffer;
352
+ };
353
+ var fontBytes = /* @__PURE__ */ new Map();
354
+ var fetchFont = (k) => {
355
+ if (!fontBytes.has(k)) {
356
+ const p = (async () => {
357
+ const r = await fetch(`${fontsBase()}${fontFile(k)}`);
358
+ if (!r.ok) throw new Error(`Font "${k}" did not load (HTTP ${r.status})`);
359
+ return r.arrayBuffer();
360
+ })();
361
+ p.catch(() => fontBytes.delete(k));
362
+ fontBytes.set(k, p);
363
+ }
364
+ return fontBytes.get(k);
365
+ };
366
+ var getFont = async (k) => {
367
+ if (bundledFonts?.[k]) return b64ToBuffer(bundledFonts[k]);
368
+ return (await fetchFont(k)).slice(0);
369
+ };
370
+ var engineP = null;
371
+ var loadEngine = () => engineP || (engineP = import("./chunk-YIX3OJXU.js"));
372
+ async function loadFontStore() {
373
+ const { FontStore } = await loadEngine();
374
+ return mainStore || (mainStore = new FontStore(getFont));
375
+ }
376
+ var parameterOptions = async (...a) => (await loadEngine()).parameterOptions(...a);
377
+ var makeWorker = () => new Worker(new URL("./engine.worker.js", import.meta.url), { type: "module" });
378
+ var fontList = null;
379
+ function customFonts(refresh = false) {
380
+ if (!fontList || refresh) {
381
+ fontList = (bundledList ? Promise.resolve(bundledList) : standalone ? Promise.resolve([]) : fetch(`${assetBase}/api/fonts`).then((r) => r.ok ? r.json() : []).catch(() => [])).then((list) => {
382
+ setCustomFonts(list);
383
+ return list;
384
+ });
385
+ }
386
+ return fontList;
387
+ }
388
+ var faces = /* @__PURE__ */ new Map();
389
+ function loadReportFonts(keys) {
390
+ if (typeof document === "undefined" || !document.fonts || typeof FontFace === "undefined") return Promise.resolve([]);
391
+ return Promise.all(keys.filter((k) => k !== SHAPER && !isStandard(k)).map((k) => {
392
+ if (!faces.has(k)) {
393
+ const bytes = bundledFonts?.[k] ? Promise.resolve(b64ToBuffer(bundledFonts[k])) : fetchFont(k).then((b) => b.slice(0));
394
+ faces.set(k, bytes.then((src) => {
395
+ const face = new FontFace(fontFamilyCss(k), src, { display: "block" });
396
+ document.fonts.add(face);
397
+ return face.load();
398
+ }).then(() => null, (error) => {
399
+ faces.delete(k);
400
+ return { key: k, error };
401
+ }));
402
+ }
403
+ return faces.get(k);
404
+ })).then((results) => results.filter(Boolean));
405
+ }
406
+ var loadModelFonts = (model) => loadReportFonts([.../* @__PURE__ */ new Set([CORE_FONT_KEY, ...fontKeysOf(model)])]);
407
+ var warned = false;
408
+ function workerFailed(reason) {
409
+ if (warned) return;
410
+ warned = true;
411
+ console.warn(`[reportwright] worker did not load (${reason}); rendering on the main thread`);
412
+ }
413
+ function getWorker() {
414
+ if (workerBroken || typeof Worker === "undefined" || bundledFonts || fetchPolicy().fetch || typeof window !== "undefined" && /** @type {any} */
415
+ window.__pwSnapshot) return null;
416
+ if (worker) return worker;
417
+ try {
418
+ worker = makeWorker();
419
+ worker.onmessage = (e) => {
420
+ if (e.data.font) {
421
+ const { fid } = e.data;
422
+ getFont(e.data.font).then((buf) => worker?.postMessage({ fid, buf }, [buf]), (err) => worker?.postMessage({ fid, error: String(err?.message || err) }));
423
+ return;
424
+ }
425
+ const w = waiting.get(e.data.id);
426
+ if (!w) return;
427
+ if (e.data.pagesPart) {
428
+ const ps = w.pages || (w.pages = []);
429
+ for (const p of e.data.pagesPart) ps.push(p);
430
+ return;
431
+ }
432
+ if (e.data.inParts) {
433
+ e.data.model.pages = w.pages || [];
434
+ w.pages = [];
435
+ }
436
+ if (e.data.partial) {
437
+ w.onPartial?.(e.data.model);
438
+ return;
439
+ }
440
+ if (e.data.retry) {
441
+ w.onRetry?.(e.data.retry);
442
+ return;
443
+ }
444
+ waiting.delete(e.data.id);
445
+ if (e.data.mainThread) {
446
+ workerFailed(e.data.mainThread);
447
+ w.retry();
448
+ return;
449
+ }
450
+ if (e.data.ok) w.resolve(e.data.model);
451
+ else w.reject(Object.assign(new Error(e.data.error.message), e.data.error));
452
+ };
453
+ worker.onerror = (ev) => {
454
+ workerFailed(ev?.message || "the worker file did not load: it was not found or could not be built");
455
+ workerBroken = true;
456
+ worker = null;
457
+ for (const [, w] of waiting) w.retry();
458
+ waiting.clear();
459
+ };
460
+ } catch (err) {
461
+ workerFailed(err?.message || String(err));
462
+ workerBroken = true;
463
+ worker = null;
464
+ }
465
+ return worker;
466
+ }
467
+ var bundled = /* @__PURE__ */ new Map();
468
+ function registerReports(map) {
469
+ for (const [k, v] of Object.entries(map || {})) bundled.set(k, v);
470
+ }
471
+ var loadReport = async (rid) => {
472
+ if (bundled.has(rid)) return structuredClone(bundled.get(rid));
473
+ if (standalone) throw new Error(`Report "${rid}" is not loaded: pass it in reports: { "${rid}": definition }, or set server (a self-hosted ReportWright server)`);
474
+ const r = await fetch(`${assetBase}/api/reports/${encodeURIComponent(rid)}`);
475
+ if (!r.ok) throw new Error(`Report "${rid}" not found`);
476
+ return r.json();
477
+ };
478
+ var fetchReport = loadReport;
479
+ async function renderMain(def, params, state, reportId, exportData = false, onRetry = void 0, dataOnly = false) {
480
+ const [{ render }, store] = await Promise.all([loadEngine(), loadFontStore(), customFonts()]);
481
+ return render(def, { parameters: params, state, reportId, exportData, dataOnly, fontStore: store, lazyFonts: true, baseUrl: origin(), loadReport, fetch: reportFetch(origin(), void 0, { onRetry }) });
482
+ }
483
+ async function renderReport(def, params = {}, state = {}, reportId = void 0, { onPartial, exportData = false, onRetry, dataOnly = false } = {}) {
484
+ const policyKeys = policyKeysIn(def);
485
+ if (policyKeys.length) console.warn(`ReportWright: ${policyKeys.join(", ")} in the report definition ignored: only the page's mountViewer options set allowHosts and unsafeFetch`);
486
+ const w = getWorker();
487
+ if (!w) return renderMain(def, params, state, reportId, exportData, onRetry, dataOnly);
488
+ const fonts = await customFonts();
489
+ return new Promise((resolve, reject) => {
490
+ const id = ++seq;
491
+ waiting.set(id, { resolve, reject, onPartial, onRetry, retry: () => renderMain(def, params, state, reportId, exportData, onRetry, dataOnly).then(resolve, reject) });
492
+ const { allowHosts, unsafeFetch } = fetchPolicy();
493
+ const env = { origin: origin(), standalone, reports: bundled.size ? Object.fromEntries(bundled) : null, fetchPolicy: { allowHosts, unsafeFetch } };
494
+ w.postMessage({ id, def, params, state, reportId, fonts, firstPages: onPartial && !dataOnly ? 2 : 0, exportData, dataOnly, env });
495
+ });
496
+ }
497
+ var usingWorker = () => !!worker && !workerBroken;
498
+ async function iccProfile() {
499
+ const r = await fetch(fontsUrl ? besideFonts("icc/sRGB-v2-magic.icc") : `${origin()}/icc/sRGB-v2-magic.icc`);
500
+ if (!r.ok) throw new Error(`the PDF/A colour profile did not load (HTTP ${r.status})`);
501
+ return new Uint8Array(await r.arrayBuffer());
502
+ }
503
+ async function pdfBlob(model, title, o = {}) {
504
+ const store = await loadFontStore();
505
+ await customFonts();
506
+ await store.load(fontKeysOf(model));
507
+ const { exportPdf } = await import("./chunk-TZXEEVKE.js");
508
+ const bytes = await exportPdf(model, store, {
509
+ title,
510
+ subset: subsetter,
511
+ tagged: o.tagged,
512
+ drillBase: origin(),
513
+ // drill-through links open this viewer, as in the HTML export
514
+ pdfa: o.pdfa ? { icc: await iccProfile() } : void 0,
515
+ // a report's image: a GET under the same rules as its data (no cookies to our other routes or to other sites)
516
+ fetchImage: async (src) => {
517
+ try {
518
+ const r = await reportFetch(origin())(src);
519
+ return r.ok ? new Uint8Array(await r.arrayBuffer()) : null;
520
+ } catch {
521
+ return null;
522
+ }
523
+ }
524
+ });
525
+ return new Blob([bytes], { type: "application/pdf" });
526
+ }
527
+
528
+ // src/viewer/logic.js
529
+ var TOOLBAR_GROUP_KEYS = {
530
+ export: (i) => i.group === "export" && i.id !== "print",
531
+ search: (i) => i.group === "search",
532
+ zoom: (i) => i.group === "zoom",
533
+ navigation: (i) => i.group === "paging"
534
+ };
535
+ var TOOLBAR_ID_KEYS = { sidebar: ["thumbnails", "documentMap"] };
536
+ function arrangeToolbar(builtIns, { hide = [], add = [] } = {}) {
537
+ if (!hide.length && !add.length) return builtIns;
538
+ const out = [...builtIns];
539
+ const taken = new Set(builtIns.map((i) => i.id));
540
+ for (const a of add) {
541
+ if (!a || !a.id || taken.has(a.id)) continue;
542
+ taken.add(a.id);
543
+ const at = out.findIndex((i) => i.id === a.after);
544
+ const item = { ...a, custom: true, group: at >= 0 ? out[at].group : `custom:${a.id}` };
545
+ if (at >= 0) out.splice(at + 1, 0, item);
546
+ else out.push(item);
547
+ }
548
+ const hiddenIds = /* @__PURE__ */ new Set();
549
+ const hiddenBy = [];
550
+ for (const k of hide) {
551
+ if (Object.hasOwn(TOOLBAR_GROUP_KEYS, k)) hiddenBy.push(TOOLBAR_GROUP_KEYS[k]);
552
+ else for (const id of Object.hasOwn(TOOLBAR_ID_KEYS, k) ? TOOLBAR_ID_KEYS[k] : [k]) hiddenIds.add(id);
553
+ }
554
+ let kept = out.filter((i) => i.custom || !(hiddenIds.has(i.id) || hiddenBy.some((f) => f(i))));
555
+ if (!kept.some((i) => i.format)) kept = kept.filter((i) => i.custom || i.id !== "exportOptions");
556
+ return kept;
557
+ }
558
+ function galleyDefinition(def) {
559
+ const pg = resolvePage(def.page);
560
+ if (pg.pageless) return def;
561
+ const m = pg.margins;
562
+ return { ...def, page: { size: "Pageless", width: pg.width, margins: [m.top, m.right, m.bottom, m.left] } };
563
+ }
564
+ function frozenAt(page, y) {
565
+ for (const r of page?.frozen || []) if (y > r.y && y < r.end - r.h) return r;
566
+ return null;
567
+ }
568
+ var escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
569
+ function findText(model, q, { matchCase = false, wholeWord = false } = {}) {
570
+ if (!q || !model) return [];
571
+ const W = "[\\p{L}\\p{M}\\p{N}_]";
572
+ const re = new RegExp(wholeWord ? `(?<!${W})${escapeRe(q)}(?!${W})` : escapeRe(q), `u${matchCase ? "" : "i"}`);
573
+ const out = [];
574
+ model.pages.forEach((pg, pi) => {
575
+ const rows = /* @__PURE__ */ new Map();
576
+ pg.items.forEach((it, k) => {
577
+ if (it.t !== "text") return;
578
+ for (const l of it.lines) {
579
+ const key = it.rich ? `r${it.rich.id}${it.rich.l}` : `${k}${l.y}`;
580
+ const r = rows.get(key);
581
+ if (r) r.lines.push(l);
582
+ else rows.set(key, { rich: !!it.rich, size: it.size, lines: [l] });
583
+ }
584
+ });
585
+ for (const { rich, size, lines: row } of rows.values()) {
586
+ row.sort((a, b) => a.x - b.x);
587
+ const text = row.map((l) => l.text).join(rich ? "" : " ");
588
+ if (!re.test(text)) continue;
589
+ const x0 = row[0].x, last = row[row.length - 1];
590
+ const x1 = last.x + (last.w || size * last.text.length * 0.5);
591
+ const y = Math.max(...row.map((l) => l.y));
592
+ out.push({ page: pi, x: x0 - 1, y: y - size * 0.95, w: x1 - x0 + 2, h: size * 1.25, text });
593
+ }
594
+ });
595
+ return out;
596
+ }
597
+ function rangeValue(a, b, p) {
598
+ if (a === "" && b === "") return "";
599
+ const lo = a !== "" ? a : String(p.min ?? b);
600
+ const hi = b !== "" ? b : String(p.max ?? a);
601
+ return `${lo},${hi}`;
602
+ }
603
+ function pathBox(d) {
604
+ let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity, cx = 0, cy = 0;
605
+ const add = (x, y) => {
606
+ cx = x;
607
+ cy = y;
608
+ if (x < x0) x0 = x;
609
+ if (x > x1) x1 = x;
610
+ if (y < y0) y0 = y;
611
+ if (y > y1) y1 = y;
612
+ };
613
+ for (const [, c, args] of String(d || "").matchAll(/([MLHVCSQTAZ])([^MLHVCSQTAZ]*)/gi)) {
614
+ const n = (args.match(/-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?/gi) || []).map(Number);
615
+ const C = c.toUpperCase();
616
+ if (C === "H") n.forEach((x) => add(x, cy));
617
+ else if (C === "V") n.forEach((y) => add(cx, y));
618
+ else if (C === "A") for (let i = 0; i + 6 < n.length; i += 7) add(n[i + 5], n[i + 6]);
619
+ else if (C !== "Z") for (let i = 0; i + 1 < n.length; i += 2) add(n[i], n[i + 1]);
620
+ }
621
+ return x0 <= x1 ? { x: x0, y: y0, w: x1 - x0, h: y1 - y0 } : null;
622
+ }
623
+ var itemsOf = (page) => (page?.items || []).flatMap((i) => i.t === "field" ? i.draw || [] : [i]);
624
+ function pageLinks(page) {
625
+ const items = itemsOf(page);
626
+ const texts = items.filter((i) => i.t === "text");
627
+ const out = [];
628
+ for (const it of items) {
629
+ if (it.t !== "link" || !it.action) continue;
630
+ let box = { x: it.x, y: it.y, w: it.w, h: it.h };
631
+ if (it.d) {
632
+ const b = pathBox(it.d);
633
+ if (!b) continue;
634
+ box = { ...b, x: b.x + (it.x - (it.x0 ?? it.x)), y: b.y + (it.y - (it.y0 ?? it.y)) };
635
+ }
636
+ if (!(box.w > 0 && box.h > 0)) continue;
637
+ const words = [];
638
+ for (const t of texts) for (const l of t.lines || []) {
639
+ const top = l.y - (t.size || 9) * 0.9, w = l.w || (t.size || 9) * String(l.text).length * 0.5;
640
+ if (l.x < box.x + box.w && l.x + w > box.x && top < box.y + box.h && l.y > box.y) words.push(String(l.text));
641
+ }
642
+ out.push({ action: it.action, ...box, path: !!it.d, tip: it.tip ? String(it.tip) : "", text: words.join(" ").replace(/^[▶▼]\s*/, "").replace(/\s*[↑↓]$/, "").trim() });
643
+ }
644
+ return out.sort((a, b) => Math.abs(a.y - b.y) > 2 ? a.y - b.y : a.x - b.x);
645
+ }
646
+ function readingText(page) {
647
+ const rows = /* @__PURE__ */ new Map();
648
+ for (const it of itemsOf(page)) {
649
+ if (it.t !== "text") continue;
650
+ for (const l of it.lines || []) {
651
+ const k = Math.round(l.y);
652
+ const r = rows.get(k);
653
+ if (r) r.push(l);
654
+ else rows.set(k, [l]);
655
+ }
656
+ }
657
+ return [...rows.entries()].sort((a, b) => a[0] - b[0]).map(([, ls]) => ls.sort((a, b) => a.x - b.x).map((l) => l.text).join(" ").trim()).filter(Boolean);
658
+ }
659
+ var EXPORT_DEFAULTS = { pdfua: false, pdfa: false, formulas: true, html: "tables" };
660
+ function exportOptionsFrom(stored) {
661
+ const { v, ...rest } = stored && typeof stored === "object" ? stored : {};
662
+ if (v !== 2) delete rest.html;
663
+ return { ...EXPORT_DEFAULTS, ...rest };
664
+ }
665
+ function pruneSnapshot(snapshot, defs) {
666
+ const text = defs.map((d) => JSON.stringify(d)).join("\n");
667
+ const seen = /* @__PURE__ */ new Map();
668
+ const used = (k) => {
669
+ let u = seen.get(k);
670
+ if (u === void 0) {
671
+ u = text.includes(JSON.stringify(k).slice(1, -1));
672
+ seen.set(k, u);
673
+ }
674
+ return u;
675
+ };
676
+ const walk = (x) => {
677
+ if (Array.isArray(x)) return x.map(walk);
678
+ if (!x || typeof x !== "object") return x;
679
+ const o = {};
680
+ for (const [k, y] of Object.entries(x)) if (y && typeof y === "object" || used(k)) o[k] = walk(y);
681
+ return o;
682
+ };
683
+ return Object.fromEntries(Object.entries(snapshot).map(([url, x]) => [url, walk(x)]));
684
+ }
685
+ var SERVER_PDF_ROWS = 2e4;
686
+ var SERVER_PDF_PAGES = 800;
687
+ function serverPdfUrl(model, { reportId, params = {}, origin: origin2, timeZone, dirty = false }) {
688
+ if (!reportId || dirty || !model) return null;
689
+ const rows = Object.values(model.stats?.rows || {}).reduce((a, n) => a + (Number(n) || 0), 0);
690
+ if (rows <= SERVER_PDF_ROWS && (model.pages?.length || 0) <= SERVER_PDF_PAGES) return null;
691
+ const q = new URLSearchParams();
692
+ for (const [k, v0] of Object.entries(params)) {
693
+ const v = Array.isArray(v0) ? v0.length > 1 ? void 0 : v0[0] : v0;
694
+ if (v === void 0 && Array.isArray(v0)) return null;
695
+ if (v == null) continue;
696
+ q.set(k, v instanceof Date ? v.toISOString() : String(v));
697
+ }
698
+ if (timeZone) q.set("timeZone", timeZone);
699
+ const s = q.toString();
700
+ return `${origin2}/api/reports/${encodeURIComponent(reportId)}/pdf${s ? `?${s}` : ""}`;
701
+ }
702
+ function paramChoices(def, fetched) {
703
+ const out = { ...fetched };
704
+ for (const p of def?.parameters || []) {
705
+ if (!Array.isArray(p.options) || !p.optionsFrom || !Array.isArray(fetched?.[p.name])) continue;
706
+ const fixed = p.options.map((o) => typeof o === "object" && o ? { value: o.value, label: String(o.label ?? o.value) } : { value: o, label: String(o) });
707
+ const seen = new Set(fixed.map((o) => String(o.value)));
708
+ out[p.name] = [...fixed, ...fetched[p.name].filter((o) => !seen.has(String(o.value)))];
709
+ }
710
+ return out;
711
+ }
712
+ function clearStaleParams(def, params, choices) {
713
+ let out = params;
714
+ for (const p of def?.parameters || []) {
715
+ const list = choices?.[p.name], v = params[p.name];
716
+ if (!p.optionsFrom || !Array.isArray(list) || v == null || v === "") continue;
717
+ const ok = new Set(list.map((o) => String(o.value)));
718
+ const fresh = ok.has(String(p.default)) ? String(p.default) : list.length ? String(list[0].value) : "";
719
+ const next = p.multi ? String(v).split(",").filter((x) => ok.has(x)).join(",") : ok.has(String(v)) ? v : fresh;
720
+ if (next !== v) out = { ...out, [p.name]: next };
721
+ }
722
+ return out;
723
+ }
724
+
725
+ export {
726
+ setFetchPolicy,
727
+ reportFetch,
728
+ setAssetBase,
729
+ origin,
730
+ setStandalone,
731
+ fontsBase,
732
+ subsetter,
733
+ setBundledFonts,
734
+ loadFontStore,
735
+ parameterOptions,
736
+ customFonts,
737
+ loadReportFonts,
738
+ loadModelFonts,
739
+ registerReports,
740
+ fetchReport,
741
+ renderReport,
742
+ usingWorker,
743
+ pdfBlob,
744
+ arrangeToolbar,
745
+ galleyDefinition,
746
+ frozenAt,
747
+ findText,
748
+ rangeValue,
749
+ pageLinks,
750
+ readingText,
751
+ EXPORT_DEFAULTS,
752
+ exportOptionsFrom,
753
+ pruneSnapshot,
754
+ serverPdfUrl,
755
+ paramChoices,
756
+ clearStaleParams
757
+ };
758
+ //# sourceMappingURL=chunk-CNDUJ7IV.js.map