@broadpaper/pdf 0.1.1

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.
@@ -0,0 +1,1160 @@
1
+ // ../license/src/encoding.ts
2
+ var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
3
+ var LOOKUP = /* @__PURE__ */ (() => {
4
+ const t = new Int8Array(128).fill(-1);
5
+ for (let i = 0; i < ALPHABET.length; i++) t[ALPHABET.charCodeAt(i)] = i;
6
+ t["+".charCodeAt(0)] = 62;
7
+ t["/".charCodeAt(0)] = 63;
8
+ return t;
9
+ })();
10
+ function base64UrlToBytes(text) {
11
+ let end = text.length;
12
+ while (end > 0 && text[end - 1] === "=") end--;
13
+ const chars = [];
14
+ for (let i2 = 0; i2 < end; i2++) {
15
+ const code = text.charCodeAt(i2);
16
+ const value = code < 128 ? LOOKUP[code] : -1;
17
+ if (value < 0) throw new Error(`not base64: ${JSON.stringify(text[i2])} at ${i2}`);
18
+ chars.push(value);
19
+ }
20
+ if (chars.length % 4 === 1) throw new Error("not base64: truncated");
21
+ const out = new Uint8Array(Math.floor(chars.length * 3 / 4));
22
+ let o = 0;
23
+ let i = 0;
24
+ for (; i + 3 < chars.length; i += 4) {
25
+ const n = chars[i] << 18 | chars[i + 1] << 12 | chars[i + 2] << 6 | chars[i + 3];
26
+ out[o++] = n >>> 16 & 255;
27
+ out[o++] = n >>> 8 & 255;
28
+ out[o++] = n & 255;
29
+ }
30
+ const rest = chars.length - i;
31
+ if (rest === 2) {
32
+ out[o++] = (chars[i] << 18 | chars[i + 1] << 12) >>> 16;
33
+ } else if (rest === 3) {
34
+ const n = chars[i] << 18 | chars[i + 1] << 12 | chars[i + 2] << 6;
35
+ out[o++] = n >>> 16 & 255;
36
+ out[o++] = n >>> 8 & 255;
37
+ }
38
+ return out;
39
+ }
40
+ var encoder = /* @__PURE__ */ new TextEncoder();
41
+ var decoder = /* @__PURE__ */ new TextDecoder("utf-8", { fatal: true });
42
+ var utf8ToBytes = (text) => encoder.encode(text);
43
+ var bytesToUtf8 = (bytes) => decoder.decode(bytes);
44
+
45
+ // ../license/src/format.ts
46
+ var FORMAT_PREFIX = "BP1";
47
+ var LicenseFormatError = class extends Error {
48
+ constructor(message, kind = "invalid") {
49
+ super(message);
50
+ this.kind = kind;
51
+ this.name = "LicenseFormatError";
52
+ }
53
+ kind;
54
+ };
55
+ var ENTITLEMENTS = ["internal", "saas"];
56
+ function normalizeLicense(license) {
57
+ return license.replace(/\s+/g, "");
58
+ }
59
+ function parseLicense(license) {
60
+ const text = normalizeLicense(license);
61
+ if (!text) throw new LicenseFormatError("the licence string is empty");
62
+ const parts = text.split(".");
63
+ if (parts.length !== 3) throw new LicenseFormatError(`expected three dot-separated parts, found ${parts.length}`);
64
+ const [prefix, encodedPayload, encodedSignature] = parts;
65
+ if (prefix !== FORMAT_PREFIX) {
66
+ const known = /^BP\d+$/.test(prefix);
67
+ throw new LicenseFormatError(
68
+ known ? `licence format ${prefix} is newer than this version of BroadPaper, which reads ${FORMAT_PREFIX}` : `unrecognised licence prefix ${JSON.stringify(prefix)}`,
69
+ known ? "unsupported" : "invalid"
70
+ );
71
+ }
72
+ if (!encodedPayload || !encodedSignature) throw new LicenseFormatError("the licence string has an empty part");
73
+ let json;
74
+ let signature;
75
+ try {
76
+ json = bytesToUtf8(base64UrlToBytes(encodedPayload));
77
+ signature = base64UrlToBytes(encodedSignature);
78
+ } catch (e) {
79
+ throw new LicenseFormatError(`the licence string is not valid base64 (${e.message})`);
80
+ }
81
+ if (signature.length !== 64) throw new LicenseFormatError(`an Ed25519 signature is 64 bytes, this one is ${signature.length}`);
82
+ let raw;
83
+ try {
84
+ raw = JSON.parse(json);
85
+ } catch {
86
+ throw new LicenseFormatError("the licence payload is not valid JSON");
87
+ }
88
+ return {
89
+ prefix,
90
+ signedText: `${prefix}.${encodedPayload}`,
91
+ encodedPayload,
92
+ signature,
93
+ payload: readPayload(raw)
94
+ };
95
+ }
96
+ function readPayload(raw) {
97
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new LicenseFormatError("the licence payload is not an object");
98
+ const o = raw;
99
+ const version = o.version;
100
+ if (version !== 1) {
101
+ const numeric = typeof version === "number" && Number.isInteger(version) && version > 1;
102
+ throw new LicenseFormatError(
103
+ numeric ? `licence payload version ${version} is newer than this version of BroadPaper, which reads version 1` : "the licence payload has no usable version",
104
+ numeric ? "unsupported" : "invalid"
105
+ );
106
+ }
107
+ const text = (key) => {
108
+ const value = o[key];
109
+ if (typeof value !== "string" || value === "") throw new LicenseFormatError(`the licence payload is missing ${key}`);
110
+ return value;
111
+ };
112
+ const seconds = (key) => {
113
+ const value = o[key];
114
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new LicenseFormatError(`the licence payload is missing ${key}`);
115
+ return value;
116
+ };
117
+ const entitlement = text("entitlement");
118
+ if (!ENTITLEMENTS.includes(entitlement)) {
119
+ throw new LicenseFormatError(`this version of BroadPaper does not know the entitlement ${JSON.stringify(entitlement)}`, "unsupported");
120
+ }
121
+ return {
122
+ ...o,
123
+ version: 1,
124
+ keyId: text("keyId"),
125
+ licenseId: text("licenseId"),
126
+ customerId: text("customerId"),
127
+ customerName: text("customerName"),
128
+ product: text("product"),
129
+ entitlement,
130
+ issuedAt: seconds("issuedAt"),
131
+ expiresAt: seconds("expiresAt")
132
+ };
133
+ }
134
+
135
+ // ../../node_modules/.pnpm/@noble+ed25519@3.2.0/node_modules/@noble/ed25519/index.js
136
+ var freeze = Object.freeze;
137
+ var P = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn;
138
+ var N = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn;
139
+ var _d = 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n;
140
+ var Gx = 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an;
141
+ var Gy = 0x6666666666666666666666666666666666666666666666666666666666666658n;
142
+ var _a = P - 1n;
143
+ var ed25519_CURVE = freeze({
144
+ p: P,
145
+ n: N,
146
+ h: 8n,
147
+ a: _a,
148
+ d: _d,
149
+ Gx,
150
+ Gy
151
+ });
152
+ var LEN = 32;
153
+ var isBytes = (a) => {
154
+ return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && a.BYTES_PER_ELEMENT === 1;
155
+ };
156
+ var abytes = (value, length, title = "") => {
157
+ if (isBytes(value) && (length === void 0 || value.length === length))
158
+ return value;
159
+ const bytes = isBytes(value);
160
+ const ofLen = length !== void 0 ? ` of length ${length}` : "";
161
+ const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
162
+ const message = (title ? `"${title}" ` : "") + "expected Uint8Array" + ofLen + ", got " + got;
163
+ if (!bytes)
164
+ throw new TypeError(message);
165
+ throw new RangeError(message);
166
+ };
167
+ var snapshotBytes = (value, title = "", length) => Uint8Array.from(abytes(value, length, title));
168
+ var padh = (n, pad) => n.toString(16).padStart(pad, "0");
169
+ var bytesToHex = (bytes) => {
170
+ let hex = "";
171
+ for (const byte of abytes(bytes))
172
+ hex += padh(byte, 2);
173
+ return hex;
174
+ };
175
+ var hexToBytes = (hex) => {
176
+ const e = "hex invalid";
177
+ if (typeof hex !== "string")
178
+ throw new TypeError(e);
179
+ if (hex.length % 2 || !/^[\da-f]*$/i.test(hex))
180
+ throw new RangeError(e);
181
+ const array = new Uint8Array(hex.length / 2);
182
+ for (let ai = 0, hi = 0; ai < array.length; ai++, hi += 2) {
183
+ const n1 = hex.charCodeAt(hi);
184
+ const n2 = hex.charCodeAt(hi + 1);
185
+ array[ai] = ((n1 & 15) + (n1 >> 6) * 9) * 16 + (n2 & 15) + (n2 >> 6) * 9;
186
+ }
187
+ return array;
188
+ };
189
+ var concatBytes = (...arrays) => {
190
+ let sum = 0;
191
+ for (const a of arrays)
192
+ sum += abytes(a).length;
193
+ const res = new Uint8Array(sum);
194
+ let pad = 0;
195
+ for (const a of arrays) {
196
+ res.set(a, pad);
197
+ pad += a.length;
198
+ }
199
+ return res;
200
+ };
201
+ var arange = (n, min, max, msg = "bad number: out of range") => {
202
+ if (typeof n !== "bigint")
203
+ throw new TypeError(msg);
204
+ if (min <= n && n < max)
205
+ return n;
206
+ throw new RangeError(msg);
207
+ };
208
+ var mod = (a, b = P) => (a %= b) >= 0n ? a : b + a;
209
+ var P_MASK = (1n << 255n) - 1n;
210
+ var modP = (num) => {
211
+ if (num < 0n)
212
+ throw new RangeError("negative coordinate");
213
+ let r = (num >> 255n) * 19n + (num & P_MASK);
214
+ r = (r >> 255n) * 19n + (r & P_MASK);
215
+ return r % P;
216
+ };
217
+ var modN = (a) => mod(a, N);
218
+ var invert = (number, modulo) => {
219
+ if (number === 0n)
220
+ throw new Error("invert: expected non-zero number");
221
+ if (modulo <= 1n)
222
+ throw new Error("invert: expected modulus > 1, got " + modulo);
223
+ let a = mod(number, modulo);
224
+ let b = modulo;
225
+ let x = 0n, u = 1n;
226
+ while (a !== 0n) {
227
+ const q = b / a;
228
+ const r = b - a * q;
229
+ const m = x - u * q;
230
+ b = a, a = r, x = u, u = m;
231
+ }
232
+ const gcd = b;
233
+ if (gcd !== 1n)
234
+ throw new Error("invert: does not exist");
235
+ return mod(x, modulo);
236
+ };
237
+ var _hash = (name) => {
238
+ const fn = hashes[name];
239
+ if (typeof fn !== "function")
240
+ throw new Error("hashes." + name + " not set");
241
+ return fn;
242
+ };
243
+ var callHashAsync = async (name, ...m) => abytes(await _hash(name)(concatBytes(...m)), 64, "digest");
244
+ var apoint = (p) => {
245
+ if (p instanceof Point)
246
+ return p;
247
+ throw new TypeError("Point expected");
248
+ };
249
+ var B256 = 2n ** 256n;
250
+ var Point = class _Point {
251
+ static BASE;
252
+ static ZERO;
253
+ X;
254
+ Y;
255
+ Z;
256
+ T;
257
+ // Constructor only bounds-checks and freezes XYZT coordinates; it does not prove the point is
258
+ // on-curve or that T matches X*Y/Z.
259
+ constructor(X, Y, Z, T) {
260
+ const max = B256;
261
+ this.X = arange(X, 0n, max);
262
+ this.Y = arange(Y, 0n, max);
263
+ this.Z = arange(Z, 1n, max);
264
+ this.T = arange(T, 0n, max);
265
+ freeze(this);
266
+ }
267
+ static CURVE() {
268
+ return ed25519_CURVE;
269
+ }
270
+ static fromAffine(p) {
271
+ return new _Point(p.x, p.y, 1n, modP(p.x * p.y));
272
+ }
273
+ /** RFC8032 5.1.3: Uint8Array to Point. */
274
+ static fromBytes(bytes, zip215 = false) {
275
+ const normed = snapshotBytes(bytes, "point", LEN);
276
+ const lastByte = normed[31];
277
+ normed[31] = lastByte & ~128;
278
+ const y = bytesToNumberLE(normed);
279
+ if (!zip215)
280
+ arange(y, 0n, P);
281
+ const y2 = modP(y * y);
282
+ const u = mod(y2 - 1n);
283
+ const v = modP(_d * y2 + 1n);
284
+ let { isValid, value: x } = uvRatio(u, v);
285
+ if (!isValid)
286
+ throw new Error("bad point: y not sqrt");
287
+ const isLastByteOdd = !!(lastByte & 128);
288
+ if (!zip215 && x === 0n && isLastByteOdd)
289
+ throw new Error("bad point: x==0, isLastByteOdd");
290
+ if (isLastByteOdd !== !!(x & 1n))
291
+ x = mod(-x);
292
+ return new _Point(x, y, 1n, modP(x * y));
293
+ }
294
+ static fromHex(hex, zip215) {
295
+ return _Point.fromBytes(hexToBytes(hex), zip215);
296
+ }
297
+ get x() {
298
+ return this.toAffine().x;
299
+ }
300
+ get y() {
301
+ return this.toAffine().y;
302
+ }
303
+ /** Checks if the point is valid and on-curve. */
304
+ assertValidity() {
305
+ const a = _a;
306
+ const d = _d;
307
+ const p = this;
308
+ if (p.is0())
309
+ throw new Error("bad point: ZERO");
310
+ const { X, Y, Z, T } = p;
311
+ const X2 = modP(X * X);
312
+ const Y2 = modP(Y * Y);
313
+ const Z2 = modP(Z * Z);
314
+ const Z4 = modP(Z2 * Z2);
315
+ const aX2 = modP(X2 * a);
316
+ const left = modP(Z2 * (aX2 + Y2));
317
+ const right = mod(Z4 + modP(d * modP(X2 * Y2)));
318
+ if (left !== right)
319
+ throw new Error("bad point: equation left != right (1)");
320
+ const XY = modP(X * Y);
321
+ const ZT = modP(Z * T);
322
+ if (XY !== ZT)
323
+ throw new Error("bad point: equation left != right (2)");
324
+ return this;
325
+ }
326
+ /** Equality check: compare points P&Q. */
327
+ equals(other) {
328
+ const { X: X1, Y: Y1, Z: Z1 } = this;
329
+ const { X: X2, Y: Y2, Z: Z2 } = apoint(other);
330
+ return modP(X1 * Z2) === modP(X2 * Z1) && modP(Y1 * Z2) === modP(Y2 * Z1);
331
+ }
332
+ is0() {
333
+ return this.equals(I);
334
+ }
335
+ /** Flip point over y coordinate. */
336
+ negate() {
337
+ return new _Point(mod(-this.X), this.Y, this.Z, mod(-this.T));
338
+ }
339
+ /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */
340
+ double() {
341
+ const { X: X1, Y: Y1, Z: Z1 } = this;
342
+ const a = _a;
343
+ const A = modP(X1 * X1);
344
+ const B = modP(Y1 * Y1);
345
+ const C = modP(2n * Z1 * Z1);
346
+ const D = modP(a * A);
347
+ const x1y1 = mod(X1 + Y1);
348
+ const E = mod(modP(x1y1 * x1y1) - A - B);
349
+ const G2 = mod(D + B);
350
+ const F = mod(G2 - C);
351
+ const H = mod(D - B);
352
+ const X3 = modP(E * F);
353
+ const Y3 = modP(G2 * H);
354
+ const T3 = modP(E * H);
355
+ const Z3 = modP(F * G2);
356
+ return new _Point(X3, Y3, Z3, T3);
357
+ }
358
+ /** Point addition. Complete formula. Cost: `9M + 1*a + 1*d + 7add`. */
359
+ add(other) {
360
+ const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;
361
+ const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other);
362
+ const a = _a;
363
+ const d = _d;
364
+ const A = modP(X1 * X2);
365
+ const B = modP(Y1 * Y2);
366
+ const C = modP(modP(T1 * d) * T2);
367
+ const D = modP(Z1 * Z2);
368
+ const E = mod(modP(mod(X1 + Y1) * mod(X2 + Y2)) - A - B);
369
+ const F = mod(D - C);
370
+ const G2 = mod(D + C);
371
+ const H = mod(B - modP(a * A));
372
+ const X3 = modP(E * F);
373
+ const Y3 = modP(G2 * H);
374
+ const T3 = modP(E * H);
375
+ const Z3 = modP(F * G2);
376
+ return new _Point(X3, Y3, Z3, T3);
377
+ }
378
+ subtract(other) {
379
+ return this.add(apoint(other).negate());
380
+ }
381
+ /**
382
+ * Point-by-scalar multiplication. Safe mode requires `1 <= n < CURVE.n`.
383
+ * Unsafe mode additionally permits `n = 0` and returns the identity point for that case.
384
+ * Uses {@link wNAF} for base point.
385
+ * Uses fake point to mitigate side-channel leakage.
386
+ * @param n - scalar by which point is multiplied
387
+ * @param safe - safe mode guards against timing attacks; unsafe mode is faster
388
+ */
389
+ multiply(n, safe = true) {
390
+ if (!safe && n === 0n)
391
+ return I;
392
+ arange(n, 1n, N);
393
+ if (!safe && this.is0())
394
+ return I;
395
+ if (n === 1n)
396
+ return this;
397
+ if (this.equals(G))
398
+ return wNAF(n).p;
399
+ let p = I;
400
+ let f = G;
401
+ let d = this;
402
+ for (let i = 0; safe ? i < 256 : n > 0n; i++) {
403
+ if (n & 1n)
404
+ p = p.add(d);
405
+ else if (safe)
406
+ f = f.add(d);
407
+ d = d.double();
408
+ n >>= 1n;
409
+ }
410
+ return p;
411
+ }
412
+ multiplyUnsafe(scalar) {
413
+ return this.multiply(scalar, false);
414
+ }
415
+ /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
416
+ toAffine() {
417
+ const { X, Y, Z } = this;
418
+ if (this.equals(I))
419
+ return { x: 0n, y: 1n };
420
+ const iz = invert(Z, P);
421
+ if (modP(Z * iz) !== 1n)
422
+ throw new Error("invalid inverse");
423
+ return { x: modP(X * iz), y: modP(Y * iz) };
424
+ }
425
+ toBytes() {
426
+ const { x, y } = this.toAffine();
427
+ const b = numTo32bLE(y);
428
+ b[31] |= x & 1n ? 128 : 0;
429
+ return b;
430
+ }
431
+ toHex() {
432
+ return bytesToHex(this.toBytes());
433
+ }
434
+ clearCofactor() {
435
+ return this.multiply(8n, false);
436
+ }
437
+ isSmallOrder() {
438
+ return this.clearCofactor().is0();
439
+ }
440
+ isTorsionFree() {
441
+ return this.multiply(N / 2n, false).double().add(this).is0();
442
+ }
443
+ };
444
+ var G = new Point(Gx, Gy, 1n, mod(Gx * Gy));
445
+ var I = new Point(0n, 1n, 1n, 0n);
446
+ Point.BASE = G;
447
+ Point.ZERO = I;
448
+ var numTo32bLE = (num) => hexToBytes(padh(arange(num, 0n, B256), 64)).reverse();
449
+ var bytesToNumberLE = (b) => BigInt("0x" + bytesToHex(Uint8Array.from(abytes(b)).reverse()));
450
+ var pow2 = (x, power) => {
451
+ let r = x;
452
+ while (power-- > 0) {
453
+ r = modP(r * r);
454
+ }
455
+ return r;
456
+ };
457
+ var pow_2_252_3 = (x) => {
458
+ const x2 = modP(x * x);
459
+ const b2 = modP(x2 * x);
460
+ const b4 = modP(pow2(b2, 2) * b2);
461
+ const b5 = modP(pow2(b4, 1) * x);
462
+ const b10 = modP(pow2(b5, 5) * b5);
463
+ const b20 = modP(pow2(b10, 10) * b10);
464
+ const b40 = modP(pow2(b20, 20) * b20);
465
+ const b80 = modP(pow2(b40, 40) * b40);
466
+ const b160 = modP(pow2(b80, 80) * b80);
467
+ const b240 = modP(pow2(b160, 80) * b80);
468
+ const b250 = modP(pow2(b240, 10) * b10);
469
+ return modP(pow2(b250, 2) * x);
470
+ };
471
+ var RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n;
472
+ var uvRatio = (u, v) => {
473
+ const v3 = modP(v * modP(v * v));
474
+ const v7 = modP(modP(v3 * v3) * v);
475
+ const pow = pow_2_252_3(modP(u * v7));
476
+ let x = modP(u * modP(v3 * pow));
477
+ const vx2 = modP(v * modP(x * x));
478
+ const root1 = x;
479
+ const root2 = modP(x * RM1);
480
+ const useRoot1 = vx2 === u;
481
+ const useRoot2 = vx2 === mod(-u);
482
+ const noRoot = vx2 === mod(-u * RM1);
483
+ if (useRoot1)
484
+ x = root1;
485
+ if (useRoot2 || noRoot)
486
+ x = root2;
487
+ if ((mod(x) & 1n) === 1n)
488
+ x = mod(-x);
489
+ return { isValid: useRoot1 || useRoot2, value: x };
490
+ };
491
+ var modL_LE = (hash) => modN(bytesToNumberLE(hash));
492
+ var hashFinishAsync = async (res) => res[1](await callHashAsync("sha512Async", res[0]));
493
+ var getZip215 = (options) => {
494
+ if (options === null || typeof options !== "object")
495
+ throw new TypeError("expected valid options object");
496
+ return options.zip215 ?? true;
497
+ };
498
+ var _verify = (sig, msg, publicKey, options) => {
499
+ sig = abytes(sig, 64, "signature");
500
+ msg = abytes(msg, void 0, "message");
501
+ publicKey = abytes(publicKey, LEN, "publicKey");
502
+ const zip215 = getZip215(options);
503
+ const r = sig.subarray(0, LEN);
504
+ const s = bytesToNumberLE(sig.subarray(LEN, 64));
505
+ let A, R, SB;
506
+ let hashable = Uint8Array.of();
507
+ let finished = false;
508
+ try {
509
+ A = Point.fromBytes(publicKey, zip215);
510
+ R = Point.fromBytes(r, zip215);
511
+ SB = G.multiply(s, false);
512
+ hashable = concatBytes(r, publicKey, msg);
513
+ finished = true;
514
+ } catch (error) {
515
+ }
516
+ const finish = (hashed) => {
517
+ if (!finished)
518
+ return false;
519
+ if (!zip215 && A.isSmallOrder())
520
+ return false;
521
+ const k = modL_LE(hashed);
522
+ const RkA = R.add(A.multiply(k, false));
523
+ return RkA.subtract(SB).clearCofactor().is0();
524
+ };
525
+ return [hashable, finish];
526
+ };
527
+ var verifyAsync = async (signature, message, publicKey, opts = {}) => hashFinishAsync(_verify(signature, message, publicKey, opts));
528
+ var hashes = {
529
+ sha512Async: async (message) => {
530
+ const s = globalThis?.crypto?.subtle;
531
+ if (!s)
532
+ throw new Error("crypto.subtle must be defined, consider polyfill");
533
+ return new Uint8Array(await s.digest("SHA-512", concatBytes(message)));
534
+ },
535
+ sha512: void 0
536
+ };
537
+ var precompute = () => {
538
+ const points = [];
539
+ let p = G;
540
+ let b;
541
+ for (let w = 0; w < 33; w++) {
542
+ b = p;
543
+ points.push(b);
544
+ for (let i = 1; i < 128; i++) {
545
+ b = b.add(p);
546
+ points.push(b);
547
+ }
548
+ p = b.double();
549
+ }
550
+ return points;
551
+ };
552
+ var Gpows = void 0;
553
+ var ctneg = (cnd, p) => {
554
+ const n = p.negate();
555
+ return cnd ? n : p;
556
+ };
557
+ var wNAF = (n) => {
558
+ const comp = Gpows || (Gpows = precompute());
559
+ let p = I;
560
+ let f = G;
561
+ for (let w = 0; w < 33; w++) {
562
+ let wbits = Number(n & 255n);
563
+ n >>= 8n;
564
+ if (wbits > 128) {
565
+ wbits -= 256;
566
+ n += 1n;
567
+ }
568
+ const off = w * 128;
569
+ const offP = off + Math.abs(wbits) - 1;
570
+ const isOddW = w % 2 !== 0;
571
+ const isNeg = wbits < 0;
572
+ if (wbits === 0) {
573
+ f = f.add(ctneg(isOddW, comp[off]));
574
+ } else {
575
+ p = p.add(ctneg(isNeg, comp[offP]));
576
+ }
577
+ }
578
+ if (n !== 0n)
579
+ throw new Error("invalid wnaf");
580
+ return { p, f };
581
+ };
582
+
583
+ // ../license/src/trusted-keys.ts
584
+ var TRUSTED_KEYS = [
585
+ { keyId: "bp-2026", publicKey: "woKmWyIazae7SpGhi4dwA7zNK1lWdboq88Rl5xscTs4", note: "production, generated 2026-09-08" }
586
+ ];
587
+
588
+ // ../license/src/types.ts
589
+ var PRODUCT = "broadpaper-sdk";
590
+
591
+ // ../license/src/verify.ts
592
+ var DEFAULT_GRACE_PERIOD_DAYS = 30;
593
+ var DAY_MS = 864e5;
594
+ function unlicensed() {
595
+ return {
596
+ state: "unlicensed",
597
+ licensed: false,
598
+ payload: null,
599
+ entitlement: null,
600
+ expiresAt: null,
601
+ daysRemaining: null,
602
+ message: "No BroadPaper licence is configured, so PDFs carry the evaluation watermark. Everything else works; see https://www.broadpaper.com/docs/guide/licensing."
603
+ };
604
+ }
605
+ function failure(state, message, payload = null) {
606
+ return {
607
+ state,
608
+ licensed: false,
609
+ payload,
610
+ entitlement: null,
611
+ expiresAt: payload ? new Date(payload.expiresAt * 1e3) : null,
612
+ daysRemaining: null,
613
+ message
614
+ };
615
+ }
616
+ async function verifyLicense(license, options = {}) {
617
+ if (!license || !license.trim()) return unlicensed();
618
+ let parsed;
619
+ try {
620
+ parsed = parseLicense(license);
621
+ } catch (e) {
622
+ if (e instanceof LicenseFormatError) {
623
+ return failure(
624
+ e.kind,
625
+ e.kind === "unsupported" ? `This BroadPaper licence needs a newer version of the SDK (${e.message}). Update @broadpaper/* or the PDF will carry the evaluation watermark.` : `The BroadPaper licence could not be read (${e.message}), so PDFs carry the evaluation watermark.`
626
+ );
627
+ }
628
+ throw e;
629
+ }
630
+ const { payload } = parsed;
631
+ if (payload.product !== PRODUCT) {
632
+ return failure(
633
+ "invalid",
634
+ `This licence is for ${JSON.stringify(payload.product)}, not the BroadPaper SDK, so PDFs carry the evaluation watermark.`,
635
+ payload
636
+ );
637
+ }
638
+ const key = findKey(payload.keyId, options.trustedKeys);
639
+ if (!key) {
640
+ return failure(
641
+ "untrusted",
642
+ `This BroadPaper licence was signed with key ${JSON.stringify(payload.keyId)}, which this build does not trust. A licence issued for development is not honoured by a production build; check BROADPAPER_LICENSE points at the right one.`,
643
+ payload
644
+ );
645
+ }
646
+ let signatureOk = false;
647
+ try {
648
+ signatureOk = await verifyAsync(parsed.signature, utf8ToBytes(parsed.signedText), base64UrlToBytes(key.publicKey));
649
+ } catch {
650
+ signatureOk = false;
651
+ }
652
+ if (!signatureOk) {
653
+ return failure("invalid", "This BroadPaper licence failed its signature check \u2014 it has been altered or truncated. PDFs carry the evaluation watermark.", payload);
654
+ }
655
+ const now = options.now ?? /* @__PURE__ */ new Date();
656
+ const expiresAt = new Date(payload.expiresAt * 1e3);
657
+ const graceDays = options.gracePeriodDays ?? DEFAULT_GRACE_PERIOD_DAYS;
658
+ const msRemaining = expiresAt.getTime() - now.getTime();
659
+ const daysRemaining = Math.floor(msRemaining / DAY_MS);
660
+ if (msRemaining > 0) {
661
+ return {
662
+ state: "active",
663
+ licensed: true,
664
+ payload,
665
+ entitlement: payload.entitlement,
666
+ expiresAt,
667
+ daysRemaining,
668
+ message: null
669
+ };
670
+ }
671
+ if (msRemaining > -graceDays * DAY_MS) {
672
+ const daysOver = Math.max(1, Math.ceil(-msRemaining / DAY_MS));
673
+ return {
674
+ state: "grace",
675
+ licensed: true,
676
+ payload,
677
+ entitlement: payload.entitlement,
678
+ expiresAt,
679
+ daysRemaining,
680
+ message: `The BroadPaper licence for ${payload.customerName} expired ${daysOver} day${daysOver === 1 ? "" : "s"} ago and is inside its ${graceDays}-day grace period. Renew it and copy the new licence from your account, or PDFs will start carrying the evaluation watermark.`
681
+ };
682
+ }
683
+ return failure(
684
+ "expired",
685
+ `The BroadPaper licence for ${payload.customerName} expired on ${expiresAt.toISOString().slice(0, 10)} and its ${graceDays}-day grace period has passed, so PDFs carry the evaluation watermark. Renewing issues a new licence in your BroadPaper account.`,
686
+ payload
687
+ );
688
+ }
689
+ function findKey(keyId, extra) {
690
+ return extra?.find((k) => k.keyId === keyId) ?? TRUSTED_KEYS.find((k) => k.keyId === keyId);
691
+ }
692
+
693
+ // ../license/src/config.ts
694
+ var STORE_KEY = /* @__PURE__ */ Symbol.for("broadpaper.license.store");
695
+ function store() {
696
+ const g = globalThis;
697
+ let s = g[STORE_KEY];
698
+ if (!s) {
699
+ s = { config: {}, cache: null, logged: /* @__PURE__ */ new Set() };
700
+ g[STORE_KEY] = s;
701
+ }
702
+ return s;
703
+ }
704
+ function configure(config) {
705
+ const s = store();
706
+ s.config = { ...s.config, ...config };
707
+ s.cache = null;
708
+ s.logged.clear();
709
+ }
710
+ function getConfig() {
711
+ return { ...store().config };
712
+ }
713
+ var BroadPaper = { configure, getConfig };
714
+ function env(name) {
715
+ const p = globalThis.process;
716
+ const value = p?.env?.[name];
717
+ return value && value.trim() ? value : void 0;
718
+ }
719
+ function trustedKeysFromEnv() {
720
+ const raw = env("BROADPAPER_TRUSTED_KEYS");
721
+ if (!raw) return [];
722
+ try {
723
+ const parsed = JSON.parse(raw);
724
+ if (!Array.isArray(parsed)) throw new Error("expected a JSON array");
725
+ return parsed.map((entry, i) => {
726
+ const k = entry;
727
+ if (typeof k?.keyId !== "string" || typeof k?.publicKey !== "string") throw new Error(`entry ${i} needs keyId and publicKey`);
728
+ return { keyId: k.keyId, publicKey: k.publicKey };
729
+ });
730
+ } catch (e) {
731
+ warn(`BROADPAPER_TRUSTED_KEYS could not be read (${e.message}); it is being ignored.`);
732
+ return [];
733
+ }
734
+ }
735
+ function warn(message) {
736
+ const s = store();
737
+ if (s.logged.has(message)) return;
738
+ s.logged.add(message);
739
+ const logger = s.config.logger;
740
+ if (logger === null) return;
741
+ const line = `[BroadPaper] ${message}`;
742
+ if (logger) logger(line);
743
+ else console.warn(line);
744
+ }
745
+ async function resolveLicenseStatus(options = {}) {
746
+ const s = store();
747
+ const config = s.config;
748
+ const license = options.license !== void 0 ? options.license : config.license ?? env("BROADPAPER_LICENSE") ?? null;
749
+ const trustedKeys = [...options.trustedKeys ?? [], ...config.trustedKeys ?? [], ...trustedKeysFromEnv()];
750
+ const gracePeriodDays = options.gracePeriodDays ?? config.gracePeriodDays;
751
+ if (!license) {
752
+ const status = unlicensed();
753
+ if (status.message) warn(status.message);
754
+ return status;
755
+ }
756
+ const verify = () => verifyLicense(license, { ...options.now ? { now: options.now } : {}, trustedKeys, ...gracePeriodDays !== void 0 ? { gracePeriodDays } : {} }).then((status) => {
757
+ if (status.message) warn(status.message);
758
+ return status;
759
+ });
760
+ if (options.now || options.license !== void 0) return verify();
761
+ const key = `${license}|${trustedKeys.map((k) => k.keyId).join(",")}|${gracePeriodDays ?? ""}`;
762
+ if (s.cache?.key !== key) s.cache = { key, status: verify() };
763
+ return s.cache.status;
764
+ }
765
+
766
+ // ../license/src/watermark.ts
767
+ var EVALUATION_WATERMARK = {
768
+ text: "BroadPaper Evaluation Copy",
769
+ fontSize: 44,
770
+ angle: -35,
771
+ color: "#c8102e",
772
+ opacity: 0.12
773
+ };
774
+ function watermarkFor(status) {
775
+ return status.licensed ? null : EVALUATION_WATERMARK;
776
+ }
777
+ function producerString(status) {
778
+ if (!status.licensed || !status.payload) return "BroadPaper (evaluation)";
779
+ return `BroadPaper (${status.payload.licenseId})`;
780
+ }
781
+
782
+ // src/server/ssrf.ts
783
+ import { lookup } from "dns/promises";
784
+ import { isIP } from "net";
785
+ var PRIVATE_V4 = [
786
+ [/^10\./, "10/8"],
787
+ [/^127\./, "loopback"],
788
+ [/^169\.254\./, "link-local"],
789
+ [/^172\.(1[6-9]|2\d|3[01])\./, "172.16/12"],
790
+ [/^192\.168\./, "192.168/16"],
791
+ [/^0\./, "0/8"],
792
+ [/^100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\./, "CGNAT"]
793
+ ];
794
+ function isPrivateAddress(ip) {
795
+ const kind = isIP(ip);
796
+ if (kind === 4) return PRIVATE_V4.some(([re]) => re.test(ip));
797
+ if (kind === 6) {
798
+ const lower = ip.toLowerCase();
799
+ if (lower === "::1" || lower === "::") return true;
800
+ if (lower.startsWith("fe80:") || lower.startsWith("fc") || lower.startsWith("fd")) return true;
801
+ const mapped = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(lower);
802
+ if (mapped) return isPrivateAddress(mapped[1]);
803
+ return false;
804
+ }
805
+ return false;
806
+ }
807
+ function hostAllowed(host, allowed) {
808
+ if (!allowed || allowed.length === 0) return false;
809
+ const h = host.toLowerCase();
810
+ return allowed.some((pattern) => {
811
+ const p = pattern.toLowerCase();
812
+ if (p === "*") return true;
813
+ if (p.startsWith("*.")) return h === p.slice(2) || h.endsWith(p.slice(1));
814
+ return h === p;
815
+ });
816
+ }
817
+ async function decideRequest(url, policy, counter) {
818
+ if (url.startsWith("data:") || url === "about:blank") return { allow: true };
819
+ let u;
820
+ try {
821
+ u = new URL(url);
822
+ } catch {
823
+ return { allow: false, reason: "invalid URL" };
824
+ }
825
+ if (u.protocol !== "http:" && u.protocol !== "https:") return { allow: false, reason: `scheme ${u.protocol} not allowed` };
826
+ if (++counter.count > (policy.maxRequests ?? 200)) return { allow: false, reason: "request limit exceeded" };
827
+ if (!hostAllowed(u.hostname, policy.allowedHosts)) return { allow: false, reason: `host ${u.hostname} not in allow-list` };
828
+ if (policy.blockPrivateNetworks !== false) {
829
+ const host = u.hostname.replace(/^\[|\]$/g, "");
830
+ if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".internal")) return { allow: false, reason: "private host" };
831
+ if (isIP(host)) {
832
+ if (isPrivateAddress(host)) return { allow: false, reason: "private address" };
833
+ } else {
834
+ try {
835
+ const results = await lookup(host, { all: true });
836
+ if (results.some((r) => isPrivateAddress(r.address))) return { allow: false, reason: "resolves to a private address" };
837
+ } catch {
838
+ return { allow: false, reason: "DNS lookup failed" };
839
+ }
840
+ }
841
+ }
842
+ return { allow: true };
843
+ }
844
+
845
+ // src/server/render-pdf.ts
846
+ import { readFile } from "fs/promises";
847
+ import { fileURLToPath } from "url";
848
+ import { dirname, join } from "path";
849
+
850
+ // src/server/watermark.ts
851
+ async function stampWatermark(doc, spec) {
852
+ const { StandardFonts, degrees, rgb } = await import("pdf-lib");
853
+ const font = await doc.embedFont(StandardFonts.HelveticaBold);
854
+ const color = hexToRgb(spec.color);
855
+ const radians = spec.angle * Math.PI / 180;
856
+ const width = font.widthOfTextAtSize(spec.text, spec.fontSize);
857
+ const height = font.heightAtSize(spec.fontSize);
858
+ for (const page of doc.getPages()) {
859
+ const { width: pw, height: ph } = page.getSize();
860
+ const x = pw / 2 - Math.cos(radians) * width / 2 + Math.sin(radians) * height / 2;
861
+ const y = ph / 2 - Math.sin(radians) * width / 2 - Math.cos(radians) * height / 2;
862
+ page.drawText(spec.text, {
863
+ x,
864
+ y,
865
+ size: spec.fontSize,
866
+ font,
867
+ color: rgb(color.r, color.g, color.b),
868
+ opacity: spec.opacity,
869
+ rotate: degrees(spec.angle)
870
+ });
871
+ }
872
+ }
873
+ function hexToRgb(hex) {
874
+ const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
875
+ if (!m) return { r: 0.78, g: 0.06, b: 0.18 };
876
+ const n = parseInt(m[1], 16);
877
+ return { r: (n >> 16 & 255) / 255, g: (n >> 8 & 255) / 255, b: (n & 255) / 255 };
878
+ }
879
+
880
+ // src/server/render-pdf.ts
881
+ var PdfRenderError = class extends Error {
882
+ constructor(message, code) {
883
+ super(message);
884
+ this.code = code;
885
+ this.name = "PdfRenderError";
886
+ }
887
+ code;
888
+ };
889
+ var runtimeCache = null;
890
+ async function loadRuntime(path) {
891
+ if (path) return readFile(path, "utf8");
892
+ if (runtimeCache) return runtimeCache;
893
+ const here = dirname(fileURLToPath(import.meta.url));
894
+ const candidates = [join(here, "runtime.global.js"), join(here, "..", "dist", "runtime.global.js")];
895
+ for (const c of candidates) {
896
+ try {
897
+ runtimeCache = await readFile(c, "utf8");
898
+ return runtimeCache;
899
+ } catch {
900
+ }
901
+ }
902
+ throw new PdfRenderError("BroadPaper runtime bundle not found. Run `pnpm --filter @broadpaper/pdf build`.", "RUNTIME");
903
+ }
904
+ var BLANK_HTML = `<!doctype html><html><head><meta charset="utf-8"><title>BroadPaper</title></head><body></body></html>`;
905
+ var PdfRenderer = class {
906
+ constructor(browser) {
907
+ this.browser = browser;
908
+ }
909
+ browser;
910
+ async render(opts) {
911
+ const started = Date.now();
912
+ const timeout = opts.timeoutMs ?? 6e4;
913
+ const runtime = await loadRuntime(opts.runtimePath);
914
+ let context = null;
915
+ try {
916
+ context = await this.browser.newContext({ javaScriptEnabled: true, offline: false, viewport: { width: 1200, height: 1600 }, deviceScaleFactor: 1, bypassCSP: false, locale: opts.locale ?? "en-GB", timezoneId: opts.timeZone });
917
+ context.setDefaultTimeout(timeout);
918
+ const counter = { count: 0 };
919
+ const policy = { allowedHosts: [], blockPrivateNetworks: true, maxRequests: 200, ...opts.network ?? {} };
920
+ await context.route("**/*", async (route) => {
921
+ const url = route.request().url();
922
+ const decision = await decideRequest(url, policy, counter);
923
+ if (decision.allow) await route.continue();
924
+ else await route.abort("blockedbyclient");
925
+ });
926
+ const page = await context.newPage();
927
+ const errors = [];
928
+ page.on("pageerror", (e) => errors.push(String(e)));
929
+ await page.setContent(BLANK_HTML, { waitUntil: "load" });
930
+ await page.addScriptTag({ content: runtime });
931
+ if (opts.customBlocksScript) await page.addScriptTag({ content: opts.customBlocksScript });
932
+ const input = {
933
+ template: opts.template,
934
+ data: opts.data ?? {},
935
+ theme: opts.theme,
936
+ dataSources: opts.dataSources ?? [],
937
+ now: (opts.now ?? /* @__PURE__ */ new Date()).toISOString(),
938
+ locale: opts.locale,
939
+ currency: opts.currency,
940
+ timeZone: opts.timeZone,
941
+ mode: "preview"
942
+ };
943
+ const result = await Promise.race([
944
+ page.evaluate(async (i) => window.BroadPaper.render(i), input),
945
+ new Promise((_, reject) => setTimeout(() => reject(new PdfRenderError(`Render timed out after ${timeout}ms`, "TIMEOUT")), timeout))
946
+ ]);
947
+ if (errors.length) throw new PdfRenderError(`Runtime error: ${errors[0]}`, "RUNTIME");
948
+ const maxPages = opts.maxPages ?? 500;
949
+ if (result.pages > maxPages) throw new PdfRenderError(`Document has ${result.pages} pages, more than the limit of ${maxPages}`, "TOO_MANY_PAGES");
950
+ await page.emulateMedia({ media: "print" });
951
+ const pdf = await page.pdf({
952
+ width: `${result.width}px`,
953
+ height: `${result.height}px`,
954
+ printBackground: true,
955
+ preferCSSPageSize: true,
956
+ margin: { top: 0, right: 0, bottom: 0, left: 0 },
957
+ displayHeaderFooter: false,
958
+ tagged: opts.tagged ?? true,
959
+ outline: opts.outline ?? true
960
+ });
961
+ const license = await resolveLicenseStatus(opts.license !== void 0 ? { license: opts.license } : {});
962
+ const finished = await applyMetadata(pdf, opts.metadata, opts.now, license);
963
+ return { pdf: finished, pages: result.pages, warnings: result.warnings, durationMs: Date.now() - started };
964
+ } catch (e) {
965
+ if (e instanceof PdfRenderError) throw e;
966
+ throw new PdfRenderError(`Browser failure: ${e.message}`, "BROWSER");
967
+ } finally {
968
+ await context?.close().catch(() => void 0);
969
+ }
970
+ }
971
+ };
972
+ async function applyMetadata(pdf, meta, now, license) {
973
+ const { PDFDocument } = await import("pdf-lib");
974
+ const status = license ?? await resolveLicenseStatus();
975
+ const doc = await PDFDocument.load(pdf, { updateMetadata: false });
976
+ const when = meta?.creationDate ?? now ?? /* @__PURE__ */ new Date();
977
+ const mark = watermarkFor(status);
978
+ if (mark) await stampWatermark(doc, mark);
979
+ doc.setProducer(producerString(status));
980
+ doc.setCreator("BroadPaper");
981
+ doc.setCreationDate(when);
982
+ doc.setModificationDate(when);
983
+ if (meta?.title) doc.setTitle(meta.title, { showInWindowTitleBar: true });
984
+ if (meta?.author) doc.setAuthor(meta.author);
985
+ if (meta?.subject) doc.setSubject(meta.subject);
986
+ if (meta?.keywords?.length) doc.setKeywords(meta.keywords);
987
+ const bytes = await doc.save({ useObjectStreams: true, addDefaultPage: false });
988
+ return Buffer.from(bytes);
989
+ }
990
+ async function renderPdf(opts) {
991
+ let browser = opts.browser;
992
+ let own = false;
993
+ if (!browser) {
994
+ const launch = opts.launch ?? defaultLaunch;
995
+ browser = await launch();
996
+ own = true;
997
+ }
998
+ try {
999
+ return await new PdfRenderer(browser).render(opts);
1000
+ } finally {
1001
+ if (own) await browser.close().catch(() => void 0);
1002
+ }
1003
+ }
1004
+ async function defaultLaunch() {
1005
+ let mod2;
1006
+ try {
1007
+ mod2 = await import("playwright").catch(() => import("playwright-core"));
1008
+ } catch {
1009
+ throw new PdfRenderError(
1010
+ "The Chromium backend needs Playwright, an optional peer dependency of @broadpaper/pdf. Install playwright (or playwright-core, if you supply your own browser), or render with @broadpaper/forme, which needs no browser at all.",
1011
+ "BROWSER"
1012
+ );
1013
+ }
1014
+ return mod2.chromium.launch({ headless: true, args: ["--disable-gpu", "--font-render-hinting=none", "--disable-dev-shm-usage"] });
1015
+ }
1016
+
1017
+ // src/server/http.ts
1018
+ import { createServer } from "http";
1019
+ function readJson(req, limit) {
1020
+ return new Promise((resolve, reject) => {
1021
+ const chunks = [];
1022
+ let size = 0;
1023
+ req.on("data", (c) => {
1024
+ size += c.length;
1025
+ if (size > limit) {
1026
+ reject(new Error("Request body too large"));
1027
+ req.destroy();
1028
+ return;
1029
+ }
1030
+ chunks.push(c);
1031
+ });
1032
+ req.on("end", () => {
1033
+ try {
1034
+ resolve(JSON.parse(Buffer.concat(chunks).toString("utf8")));
1035
+ } catch {
1036
+ reject(new Error("Invalid JSON"));
1037
+ }
1038
+ });
1039
+ req.on("error", reject);
1040
+ });
1041
+ }
1042
+ function send(res, status, body, headers = {}) {
1043
+ const json = JSON.stringify(body);
1044
+ res.writeHead(status, { "content-type": "application/json; charset=utf-8", "content-length": Buffer.byteLength(json), ...headers });
1045
+ res.end(json);
1046
+ }
1047
+ async function createPdfServer(opts = {}) {
1048
+ const log = opts.log ?? (() => void 0);
1049
+ const browser = await (opts.launch ?? defaultLaunch)();
1050
+ const renderer = new PdfRenderer(browser);
1051
+ const concurrency = opts.concurrency ?? 4;
1052
+ let active = 0;
1053
+ const queue = [];
1054
+ const acquire = () => new Promise((resolve) => {
1055
+ if (active < concurrency) {
1056
+ active++;
1057
+ resolve();
1058
+ } else queue.push(resolve);
1059
+ });
1060
+ const release = () => {
1061
+ active--;
1062
+ const next = queue.shift();
1063
+ if (next) {
1064
+ active++;
1065
+ next();
1066
+ }
1067
+ };
1068
+ const server = createServer(async (req, res) => {
1069
+ const url = new URL(req.url ?? "/", "http://localhost");
1070
+ res.setHeader("x-content-type-options", "nosniff");
1071
+ if (req.method === "GET" && url.pathname === "/health") return send(res, 200, { ok: true, browser: browser.isConnected(), active, queued: queue.length });
1072
+ if (req.method === "OPTIONS") {
1073
+ res.writeHead(204, { "access-control-allow-origin": "*", "access-control-allow-headers": "authorization, content-type", "access-control-allow-methods": "POST, GET, OPTIONS" });
1074
+ return res.end();
1075
+ }
1076
+ if (req.method !== "POST" || url.pathname !== "/render") return send(res, 404, { error: "Not found" });
1077
+ if (opts.token) {
1078
+ const auth = req.headers.authorization ?? "";
1079
+ if (auth !== `Bearer ${opts.token}`) return send(res, 401, { error: "Unauthorised" });
1080
+ }
1081
+ let body;
1082
+ try {
1083
+ body = await readJson(req, opts.maxBodyBytes ?? 25 * 1024 * 1024);
1084
+ } catch (e) {
1085
+ return send(res, 400, { error: e.message });
1086
+ }
1087
+ if (!body || typeof body !== "object" || !body.template) return send(res, 400, { error: "Missing template" });
1088
+ const serverHosts = opts.network?.allowedHosts ?? [];
1089
+ const requested = body.network?.allowedHosts;
1090
+ const allowedHosts = requested ? requested.filter((h) => serverHosts.includes("*") || serverHosts.includes(h)) : serverHosts;
1091
+ await acquire();
1092
+ const started = Date.now();
1093
+ try {
1094
+ const result = await renderer.render({
1095
+ template: body.template,
1096
+ data: body.data,
1097
+ theme: body.theme,
1098
+ dataSources: body.dataSources,
1099
+ now: body.now ? new Date(body.now) : void 0,
1100
+ locale: body.locale,
1101
+ currency: body.currency,
1102
+ timeZone: body.timeZone,
1103
+ metadata: body.metadata,
1104
+ network: { ...opts.network ?? {}, allowedHosts },
1105
+ customBlocksScript: opts.customBlocksScript,
1106
+ timeoutMs: opts.timeoutMs,
1107
+ maxPages: opts.maxPages
1108
+ });
1109
+ log(`render ok pages=${result.pages} ms=${result.durationMs}`);
1110
+ res.setHeader("access-control-allow-origin", "*");
1111
+ if (body.format === "json") return send(res, 200, { pdfBase64: result.pdf.toString("base64"), pages: result.pages, warnings: result.warnings, durationMs: result.durationMs });
1112
+ res.writeHead(200, { "content-type": "application/pdf", "content-length": result.pdf.length, "x-broadpaper-pages": String(result.pages), "x-broadpaper-warnings": String(result.warnings.length), "content-disposition": `inline; filename="${(body.metadata?.title ?? "report").replace(/[^\w.-]+/g, "_")}.pdf"` });
1113
+ res.end(result.pdf);
1114
+ } catch (e) {
1115
+ const err = e;
1116
+ log(`render failed ${err.code ?? ""} ${err.message} ms=${Date.now() - started}`);
1117
+ const status = err instanceof PdfRenderError ? err.code === "TIMEOUT" ? 504 : err.code === "TOO_MANY_PAGES" ? 413 : 500 : 500;
1118
+ res.setHeader("access-control-allow-origin", "*");
1119
+ send(res, status, { error: err.message, code: err.code ?? "UNKNOWN" });
1120
+ } finally {
1121
+ release();
1122
+ }
1123
+ });
1124
+ const port = opts.port ?? 4780;
1125
+ await new Promise((resolve) => server.listen(port, opts.host ?? "0.0.0.0", resolve));
1126
+ const address = server.address();
1127
+ const actualPort = typeof address === "object" && address ? address.port : port;
1128
+ log(`BroadPaper PDF service listening on http://${opts.host ?? "0.0.0.0"}:${actualPort}`);
1129
+ return {
1130
+ server,
1131
+ port: actualPort,
1132
+ close: async () => {
1133
+ await new Promise((resolve) => server.close(() => resolve()));
1134
+ await browser.close().catch(() => void 0);
1135
+ }
1136
+ };
1137
+ }
1138
+
1139
+ export {
1140
+ parseLicense,
1141
+ verifyLicense,
1142
+ configure,
1143
+ BroadPaper,
1144
+ resolveLicenseStatus,
1145
+ isPrivateAddress,
1146
+ hostAllowed,
1147
+ decideRequest,
1148
+ PdfRenderError,
1149
+ PdfRenderer,
1150
+ applyMetadata,
1151
+ renderPdf,
1152
+ defaultLaunch,
1153
+ createPdfServer
1154
+ };
1155
+ /*! Bundled license information:
1156
+
1157
+ @noble/ed25519/index.js:
1158
+ (*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) *)
1159
+ */
1160
+ //# sourceMappingURL=chunk-4YSTS7DA.js.map