@broadpaper/pdf 0.4.1 → 1.0.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.
package/LICENSE CHANGED
@@ -10,7 +10,7 @@ production use. The full agreement is the Terms and Conditions at
10
10
  https://www.broadpaper.com/legal/terms/ ; this notice is the part of it you need
11
11
  in the package, and where the two differ, those Terms prevail.
12
12
 
13
- Version of 9 September 2026.
13
+ Version of 27 September 2026.
14
14
 
15
15
 
16
16
  1. DEFINITIONS
@@ -25,6 +25,9 @@ and updates.
25
25
  Organisation, and the rights granted with it. A Licence belongs to the
26
26
  Organisation, not to an individual.
27
27
 
28
+ "Evaluation Licence" means a free, time-limited licence certificate we issue
29
+ under section 2. It is not a paid Licence.
30
+
28
31
  "Product" means an application your Organisation builds that incorporates the
29
32
  Software.
30
33
 
@@ -49,6 +52,17 @@ charge for it and whether or not the mark is present in the output. Removing,
49
52
  suppressing or circumventing the mark does not make unlicensed production use
50
53
  permitted.
51
54
 
55
+ We may issue your Organisation an Evaluation Licence, which lets the Software
56
+ generate documents without the evaluation mark for a limited period, currently
57
+ sixty days. It is part of this evaluation grant and gives no further rights: it
58
+ is for development, testing and evaluation only, and does not permit
59
+ production use. We issue at most one Evaluation Licence to each Organisation
60
+ and to each person, and we may refuse to issue one, or revoke one by telling
61
+ you, at our discretion. It ends on the expiry date it records, with no grace
62
+ period, after which documents carry the evaluation mark again. We may extend
63
+ one at our discretion by issuing a replacement. Section 3 does not apply to an
64
+ Evaluation Licence.
65
+
52
66
 
53
67
  3. PAID LICENCES
54
68
 
package/README.md CHANGED
@@ -10,6 +10,8 @@ Part of [**BroadPaper**](https://www.broadpaper.com/developers/?utm_source=npm&u
10
10
  Your users design the report in your application; BroadPaper owns the layout, the branding,
11
11
  the pagination and the output.
12
12
 
13
+ **[Try the demo](https://www.broadpaper.com/demo/?utm_source=npm&utm_medium=readme)** · **[Get a free evaluation key](https://www.broadpaper.com/eval/)** · [Pricing](https://www.broadpaper.com/developers/pricing/?utm_source=npm&utm_medium=readme)
14
+
13
15
  ## Install
14
16
 
15
17
  ```bash
@@ -31,11 +33,14 @@ Install it, use every feature and evaluate it against your real data for as long
31
33
  Production use needs a licence.
32
34
 
33
35
  In the software, the only difference without a licence is that generated PDFs carry an
34
- evaluation mark, and a licence removes it. Contractually, the licence is also what permits
35
- production use. No seats, no activation, no machine binding, no telemetry, and no call home at
36
- any point.
36
+ evaluation mark. A free 60-day [evaluation key](https://www.broadpaper.com/eval/) removes it
37
+ while you evaluate, and a paid licence removes it in production. Contractually, the paid
38
+ licence is also what permits production use. Evaluation keys need BroadPaper 1.0.0 or
39
+ later. No seats, no activation, no machine binding, no telemetry, and no call home at any
40
+ point.
37
41
 
38
42
  - [How licensing works](https://www.broadpaper.com/docs/guide/licensing/)
43
+ - [Get a free evaluation key](https://www.broadpaper.com/eval/)
39
44
  - [Pricing](https://www.broadpaper.com/developers/pricing/?utm_source=npm&utm_medium=readme)
40
45
  - [Licence agreement](https://www.broadpaper.com/legal/terms/)
41
46
 
@@ -52,7 +52,7 @@ var LicenseFormatError = class extends Error {
52
52
  }
53
53
  kind;
54
54
  };
55
- var PLANS = ["internal", "saas"];
55
+ var PLANS = ["internal", "saas", "evaluation"];
56
56
  var LICENSE_TYPES = ["subscription"];
57
57
  function normalizeLicense(license) {
58
58
  return license.replace(/\s+/g, "");
@@ -124,6 +124,9 @@ function readPayload(raw) {
124
124
  if (!PLANS.includes(plan)) {
125
125
  throw new LicenseFormatError(`this version of BroadPaper does not know the plan ${JSON.stringify(plan)}`, "unsupported");
126
126
  }
127
+ if (plan === "evaluation" && o.validUntil === null) {
128
+ throw new LicenseFormatError("an evaluation licence must have an end date");
129
+ }
127
130
  const licenseType = text("licenseType");
128
131
  if (!LICENSE_TYPES.includes(licenseType)) {
129
132
  throw new LicenseFormatError(`this version of BroadPaper cannot honour a ${JSON.stringify(licenseType)} licence`, "unsupported");
@@ -598,10 +601,12 @@ var TRUSTED_KEYS = [
598
601
  ];
599
602
 
600
603
  // ../license/src/types.ts
604
+ var EVALUATION_PLAN = "evaluation";
601
605
  var PRODUCT = "broadpaper-sdk";
602
606
 
603
607
  // ../license/src/verify.ts
604
608
  var DEFAULT_GRACE_PERIOD_DAYS = 30;
609
+ var EVALUATION_KEY_URL = "https://www.broadpaper.com/eval";
605
610
  var DAY_MS = 864e5;
606
611
  function unlicensed() {
607
612
  return {
@@ -611,7 +616,7 @@ function unlicensed() {
611
616
  plan: null,
612
617
  validUntil: null,
613
618
  daysRemaining: null,
614
- message: "No BroadPaper licence is configured, so PDFs carry the evaluation watermark. Everything else works; see https://www.broadpaper.com/docs/guide/licensing."
619
+ message: `BroadPaper is running in evaluation mode. Get a free evaluation key: ${EVALUATION_KEY_URL}`
615
620
  };
616
621
  }
617
622
  function failure(state, message, payload = null) {
@@ -669,7 +674,9 @@ async function verifyLicense(license, options = {}) {
669
674
  return { state: "active", licensed: true, payload, plan: payload.plan, validUntil: null, daysRemaining: null, message: null };
670
675
  }
671
676
  const validUntil = new Date(payload.validUntil * 1e3);
672
- const graceDays = options.gracePeriodDays ?? DEFAULT_GRACE_PERIOD_DAYS;
677
+ const evaluation = payload.plan === EVALUATION_PLAN;
678
+ const graceDays = evaluation ? 0 : options.gracePeriodDays ?? DEFAULT_GRACE_PERIOD_DAYS;
679
+ const day = validUntil.toISOString().slice(0, 10);
673
680
  const msRemaining = validUntil.getTime() - now.getTime();
674
681
  const daysRemaining = Math.floor(msRemaining / DAY_MS);
675
682
  if (msRemaining > 0) {
@@ -680,9 +687,17 @@ async function verifyLicense(license, options = {}) {
680
687
  plan: payload.plan,
681
688
  validUntil,
682
689
  daysRemaining,
683
- message: null
690
+ message: null,
691
+ notice: evaluation ? `BroadPaper is running on an evaluation licence for ${payload.organisationName}, which ends on ${day}. It is for evaluation and development, not production use.` : null
684
692
  };
685
693
  }
694
+ if (evaluation) {
695
+ return failure(
696
+ "expired",
697
+ `The BroadPaper evaluation licence for ${payload.organisationName} ended on ${day}, so PDFs carry the evaluation watermark again. Need longer? Reply to your licence email or write to hello@broadpaper.com.`,
698
+ payload
699
+ );
700
+ }
686
701
  if (msRemaining > -graceDays * DAY_MS) {
687
702
  const daysOver = Math.max(1, Math.ceil(-msRemaining / DAY_MS));
688
703
  return {
@@ -697,7 +712,7 @@ async function verifyLicense(license, options = {}) {
697
712
  }
698
713
  return failure(
699
714
  "expired",
700
- `The BroadPaper licence for ${payload.organisationName} expired on ${validUntil.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.`,
715
+ `The BroadPaper licence for ${payload.organisationName} expired on ${day} and its ${graceDays}-day grace period has passed, so PDFs carry the evaluation watermark. Renewing issues a new licence in your BroadPaper account.`,
701
716
  payload
702
717
  );
703
718
  }
@@ -748,15 +763,26 @@ function trustedKeysFromEnv() {
748
763
  }
749
764
  }
750
765
  function warn(message) {
766
+ log(message, "warn");
767
+ }
768
+ function info(message) {
769
+ log(message, "info");
770
+ }
771
+ function log(message, level) {
751
772
  const s = store();
752
773
  if (s.logged.has(message)) return;
753
774
  s.logged.add(message);
754
775
  const logger = s.config.logger;
755
776
  if (logger === null) return;
756
777
  const line = `[BroadPaper] ${message}`;
757
- if (logger) logger(line);
778
+ if (logger) logger(line, level);
779
+ else if (level === "info") console.info(line);
758
780
  else console.warn(line);
759
781
  }
782
+ function report(status) {
783
+ if (status.message) warn(status.message);
784
+ if (status.notice) info(status.notice);
785
+ }
760
786
  async function resolveLicenseStatus(options = {}) {
761
787
  const s = store();
762
788
  const config = s.config;
@@ -765,11 +791,11 @@ async function resolveLicenseStatus(options = {}) {
765
791
  const gracePeriodDays = options.gracePeriodDays ?? config.gracePeriodDays;
766
792
  if (!license) {
767
793
  const status = unlicensed();
768
- if (status.message) warn(status.message);
794
+ report(status);
769
795
  return status;
770
796
  }
771
797
  const verify = () => verifyLicense(license, { ...options.now ? { now: options.now } : {}, trustedKeys, ...gracePeriodDays !== void 0 ? { gracePeriodDays } : {} }).then((status) => {
772
- if (status.message) warn(status.message);
798
+ report(status);
773
799
  return status;
774
800
  });
775
801
  if (options.now || options.license !== void 0) return verify();
@@ -779,12 +805,38 @@ async function resolveLicenseStatus(options = {}) {
779
805
  }
780
806
 
781
807
  // ../license/src/watermark.ts
808
+ function expandWatermarks(marks) {
809
+ const out = [];
810
+ for (const mark of marks) {
811
+ if (!mark) continue;
812
+ out.push(mark);
813
+ if (mark.footnote) out.push(mark.footnote);
814
+ }
815
+ return out;
816
+ }
782
817
  var EVALUATION_WATERMARK = {
783
818
  text: "BroadPaper Evaluation Copy",
784
819
  fontSize: 44,
785
820
  angle: -35,
786
821
  color: "#c8102e",
787
- opacity: 0.12
822
+ opacity: 0.12,
823
+ /*
824
+ * The line that says what to do about the stamp. The stamp itself is never a
825
+ * link — it is there to be seen. This line is the opposite: it exists to be
826
+ * followed, so the Forme backend links it; Chromium stamps text into a finished
827
+ * file and draws it unlinked. Darker than the stamp because at eight points
828
+ * the stamp's opacity is unreadable, and still grey enough to leave the page
829
+ * a page. A full stop rather than a dash, for the reason above.
830
+ */
831
+ footnote: {
832
+ text: "Evaluation copy. Remove this mark with a free key: broadpaper.com/eval",
833
+ fontSize: 8,
834
+ angle: 0,
835
+ color: "#6b6b6b",
836
+ opacity: 0.9,
837
+ placement: "bottom",
838
+ href: "https://www.broadpaper.com/eval"
839
+ }
788
840
  };
789
841
  function watermarkFor(status) {
790
842
  return status.licensed ? null : EVALUATION_WATERMARK;
@@ -1003,7 +1055,7 @@ async function applyMetadata(pdf, meta, now, license, extraWatermark) {
1003
1055
  const status = license ?? await resolveLicenseStatus();
1004
1056
  const doc = await PDFDocument.load(pdf, { updateMetadata: false });
1005
1057
  const when = meta?.creationDate ?? now ?? /* @__PURE__ */ new Date();
1006
- for (const mark of [watermarkFor(status), extraWatermark]) if (mark) await stampWatermark(doc, mark);
1058
+ for (const mark of expandWatermarks([watermarkFor(status), extraWatermark])) await stampWatermark(doc, mark);
1007
1059
  doc.setProducer(producerString(status));
1008
1060
  doc.setCreator("BroadPaper");
1009
1061
  doc.setCreationDate(when);
@@ -1073,7 +1125,7 @@ function send(res, status, body, headers = {}) {
1073
1125
  res.end(json);
1074
1126
  }
1075
1127
  async function createPdfServer(opts = {}) {
1076
- const log = opts.log ?? (() => void 0);
1128
+ const log2 = opts.log ?? (() => void 0);
1077
1129
  const browser = await (opts.launch ?? defaultLaunch)();
1078
1130
  const renderer = new PdfRenderer(browser);
1079
1131
  const concurrency = opts.concurrency ?? 4;
@@ -1134,14 +1186,14 @@ async function createPdfServer(opts = {}) {
1134
1186
  timeoutMs: opts.timeoutMs,
1135
1187
  maxPages: opts.maxPages
1136
1188
  });
1137
- log(`render ok pages=${result.pages} ms=${result.durationMs}`);
1189
+ log2(`render ok pages=${result.pages} ms=${result.durationMs}`);
1138
1190
  res.setHeader("access-control-allow-origin", "*");
1139
1191
  if (body.format === "json") return send(res, 200, { pdfBase64: result.pdf.toString("base64"), pages: result.pages, warnings: result.warnings, durationMs: result.durationMs });
1140
1192
  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"` });
1141
1193
  res.end(result.pdf);
1142
1194
  } catch (e) {
1143
1195
  const err = e;
1144
- log(`render failed ${err.code ?? ""} ${err.message} ms=${Date.now() - started}`);
1196
+ log2(`render failed ${err.code ?? ""} ${err.message} ms=${Date.now() - started}`);
1145
1197
  const status = err instanceof PdfRenderError ? err.code === "TIMEOUT" ? 504 : err.code === "TOO_MANY_PAGES" ? 413 : 500 : 500;
1146
1198
  res.setHeader("access-control-allow-origin", "*");
1147
1199
  send(res, status, { error: err.message, code: err.code ?? "UNKNOWN" });
@@ -1153,7 +1205,7 @@ async function createPdfServer(opts = {}) {
1153
1205
  await new Promise((resolve) => server.listen(port, opts.host ?? "0.0.0.0", resolve));
1154
1206
  const address = server.address();
1155
1207
  const actualPort = typeof address === "object" && address ? address.port : port;
1156
- log(`BroadPaper PDF service listening on http://${opts.host ?? "0.0.0.0"}:${actualPort}`);
1208
+ log2(`BroadPaper PDF service listening on http://${opts.host ?? "0.0.0.0"}:${actualPort}`);
1157
1209
  return {
1158
1210
  server,
1159
1211
  port: actualPort,
@@ -1185,4 +1237,4 @@ export {
1185
1237
  @noble/ed25519/index.js:
1186
1238
  (*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) *)
1187
1239
  */
1188
- //# sourceMappingURL=chunk-OHMUXC7H.js.map
1240
+ //# sourceMappingURL=chunk-H5HVLT2H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../license/src/encoding.ts","../../license/src/format.ts","../../../node_modules/.pnpm/@noble+ed25519@3.2.0/node_modules/@noble/ed25519/index.js","../../license/src/trusted-keys.ts","../../license/src/types.ts","../../license/src/verify.ts","../../license/src/config.ts","../../license/src/watermark.ts","../src/server/ssrf.ts","../src/server/render-pdf.ts","../src/server/watermark.ts","../src/server/http.ts"],"sourcesContent":["/**\n * base64url and UTF-8, without depending on Node or on the DOM.\n *\n * The SDK runs in Node, in edge runtimes, in a worker and in a browser, and the\n * licence string has to decode identically in all four. `atob`/`btoa` exist\n * everywhere modern but are byte-oriented and mangle anything above U+00FF, so\n * text goes through `TextEncoder`/`TextDecoder` first and only bytes are\n * base64'd. The tables below are the whole implementation, which is smaller\n * than the runtime detection needed to use `Buffer` where it happens to exist.\n */\n\nconst ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\nconst LOOKUP = /* @__PURE__ */ (() => {\n const t = new Int8Array(128).fill(-1);\n for (let i = 0; i < ALPHABET.length; i++) t[ALPHABET.charCodeAt(i)] = i;\n // Accept standard base64 as well, so a licence that survived a round trip\n // through a system that rewrote the alphabet still reads.\n t[\"+\".charCodeAt(0)] = 62;\n t[\"/\".charCodeAt(0)] = 63;\n return t;\n})();\n\nexport function bytesToBase64Url(bytes: Uint8Array): string {\n let out = \"\";\n let i = 0;\n for (; i + 2 < bytes.length; i += 3) {\n const n = (bytes[i]! << 16) | (bytes[i + 1]! << 8) | bytes[i + 2]!;\n out += ALPHABET[(n >>> 18) & 63]! + ALPHABET[(n >>> 12) & 63]! + ALPHABET[(n >>> 6) & 63]! + ALPHABET[n & 63]!;\n }\n const rest = bytes.length - i;\n if (rest === 1) {\n const n = bytes[i]! << 16;\n out += ALPHABET[(n >>> 18) & 63]! + ALPHABET[(n >>> 12) & 63]!;\n } else if (rest === 2) {\n const n = (bytes[i]! << 16) | (bytes[i + 1]! << 8);\n out += ALPHABET[(n >>> 18) & 63]! + ALPHABET[(n >>> 12) & 63]! + ALPHABET[(n >>> 6) & 63]!;\n }\n return out;\n}\n\n/** Throws on anything that is not base64/base64url. Padding is optional. */\nexport function base64UrlToBytes(text: string): Uint8Array {\n let end = text.length;\n while (end > 0 && text[end - 1] === \"=\") end--;\n const chars: number[] = [];\n for (let i = 0; i < end; i++) {\n const code = text.charCodeAt(i);\n const value = code < 128 ? LOOKUP[code]! : -1;\n if (value < 0) throw new Error(`not base64: ${JSON.stringify(text[i])} at ${i}`);\n chars.push(value);\n }\n // 4 base64 characters carry 3 bytes; a group of 1 is never valid.\n if (chars.length % 4 === 1) throw new Error(\"not base64: truncated\");\n const out = new Uint8Array(Math.floor((chars.length * 3) / 4));\n let o = 0;\n let i = 0;\n for (; i + 3 < chars.length; i += 4) {\n const n = (chars[i]! << 18) | (chars[i + 1]! << 12) | (chars[i + 2]! << 6) | chars[i + 3]!;\n out[o++] = (n >>> 16) & 255;\n out[o++] = (n >>> 8) & 255;\n out[o++] = n & 255;\n }\n const rest = chars.length - i;\n if (rest === 2) {\n out[o++] = ((chars[i]! << 18) | (chars[i + 1]! << 12)) >>> 16;\n } else if (rest === 3) {\n const n = (chars[i]! << 18) | (chars[i + 1]! << 12) | (chars[i + 2]! << 6);\n out[o++] = (n >>> 16) & 255;\n out[o++] = (n >>> 8) & 255;\n }\n return out;\n}\n\nconst encoder = /* @__PURE__ */ new TextEncoder();\nconst decoder = /* @__PURE__ */ new TextDecoder(\"utf-8\", { fatal: true });\n\nexport const utf8ToBytes = (text: string): Uint8Array => encoder.encode(text);\nexport const bytesToUtf8 = (bytes: Uint8Array): string => decoder.decode(bytes);\n","/**\n * The licence string.\n *\n * BP1.<base64url payload>.<base64url signature>\n *\n * Three parts, dot-separated, safe in an environment variable, a YAML file, a\n * URL and a shell argument without quoting. The leading `BP1` is the *string\n * format* version and `payload.version` is the *payload schema* version; they\n * move independently, and both are checked, so a licence issued for a later\n * format is reported as unsupported rather than as corrupt.\n *\n * What is signed is the bytes of `BP1.<payload>` — prefix included. Signing the\n * encoded text rather than the decoded object means verification never depends\n * on two JSON serialisers agreeing about key order or number formatting, and\n * covering the prefix stops a payload being lifted into a future format that\n * might read a field differently.\n */\nimport { base64UrlToBytes, bytesToBase64Url, bytesToUtf8, utf8ToBytes } from \"./encoding.js\";\nimport { PRODUCT, type LicensePayload, type LicenseType, type Plan } from \"./types.js\";\n\n/** The only string format this SDK can read. */\nexport const FORMAT_PREFIX = \"BP1\";\n\n/** A licence string split into its parts, before any signature check. */\nexport interface ParsedLicense {\n prefix: string;\n /** The exact text that was signed. */\n signedText: string;\n encodedPayload: string;\n signature: Uint8Array;\n payload: LicensePayload;\n}\n\nexport class LicenseFormatError extends Error {\n constructor(\n message: string,\n /** `unsupported` when the licence is well-formed but newer than this SDK. */\n readonly kind: \"invalid\" | \"unsupported\" = \"invalid\"\n ) {\n super(message);\n this.name = \"LicenseFormatError\";\n }\n}\n\nconst PLANS: readonly Plan[] = [\"internal\", \"saas\", \"evaluation\"];\n\n/**\n * The licence types this SDK can actually honour.\n *\n * Only `subscription`. A perpetual licence's whole meaning is that the right to\n * use outlives the right to updates, which needs the running build's release\n * date to enforce — a fact a certificate cannot carry, because it is issued\n * before the versions it covers exist. A build with no such date could only\n * honour a perpetual licence by honouring *every* future version forever, which\n * is not what was sold. So it is refused, and refused as `unsupported` rather\n * than `invalid`: the fix is to upgrade, and saying so is more use than calling\n * a valid certificate corrupt.\n */\nconst LICENSE_TYPES: readonly LicenseType[] = [\"subscription\"];\n\n/** Whitespace is stripped: licences get pasted, wrapped and indented. */\nexport function normalizeLicense(license: string): string {\n return license.replace(/\\s+/g, \"\");\n}\n\n/**\n * Reads a licence string without verifying it.\n *\n * Nothing here decides whether a licence is *honoured* — that needs the\n * signature — but a structurally broken string can be rejected before any\n * cryptography happens, and the account UI can display a licence's contents\n * without holding a public key.\n */\nexport function parseLicense(license: string): ParsedLicense {\n const text = normalizeLicense(license);\n if (!text) throw new LicenseFormatError(\"the licence string is empty\");\n\n const parts = text.split(\".\");\n if (parts.length !== 3) throw new LicenseFormatError(`expected three dot-separated parts, found ${parts.length}`);\n const [prefix, encodedPayload, encodedSignature] = parts as [string, string, string];\n\n if (prefix !== FORMAT_PREFIX) {\n // A licence issued in a format this SDK predates is a version problem, not\n // a corrupt string, and the fix is to upgrade rather than to re-copy it.\n const known = /^BP\\d+$/.test(prefix);\n throw new LicenseFormatError(\n known\n ? `licence format ${prefix} is newer than this version of BroadPaper, which reads ${FORMAT_PREFIX}`\n : `unrecognised licence prefix ${JSON.stringify(prefix)}`,\n known ? \"unsupported\" : \"invalid\"\n );\n }\n if (!encodedPayload || !encodedSignature) throw new LicenseFormatError(\"the licence string has an empty part\");\n\n let json: string;\n let signature: Uint8Array;\n try {\n json = bytesToUtf8(base64UrlToBytes(encodedPayload));\n signature = base64UrlToBytes(encodedSignature);\n } catch (e) {\n throw new LicenseFormatError(`the licence string is not valid base64 (${(e as Error).message})`);\n }\n if (signature.length !== 64) throw new LicenseFormatError(`an Ed25519 signature is 64 bytes, this one is ${signature.length}`);\n\n let raw: unknown;\n try {\n raw = JSON.parse(json);\n } catch {\n throw new LicenseFormatError(\"the licence payload is not valid JSON\");\n }\n\n return {\n prefix,\n signedText: `${prefix}.${encodedPayload}`,\n encodedPayload,\n signature,\n payload: readPayload(raw)\n };\n}\n\n/**\n * Validates the payload's shape.\n *\n * Unknown properties are kept, not rejected: they are inside the signature, so\n * a licence issued by a later BroadPaper carrying a field this SDK has never\n * heard of is still a licence this SDK can honour.\n */\nfunction readPayload(raw: unknown): LicensePayload {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) throw new LicenseFormatError(\"the licence payload is not an object\");\n const o = raw as Record<string, unknown>;\n\n const schemaVersion = o.schemaVersion;\n if (schemaVersion !== 1) {\n const numeric = typeof schemaVersion === \"number\" && Number.isInteger(schemaVersion) && schemaVersion > 1;\n throw new LicenseFormatError(\n numeric\n ? `licence payload schema version ${schemaVersion} is newer than this version of BroadPaper, which reads version 1`\n : \"the licence payload has no usable schemaVersion\",\n numeric ? \"unsupported\" : \"invalid\"\n );\n }\n\n const text = (key: string): string => {\n const value = o[key];\n if (typeof value !== \"string\" || value === \"\") throw new LicenseFormatError(`the licence payload is missing ${key}`);\n return value;\n };\n const seconds = (key: string): number => {\n const value = o[key];\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new LicenseFormatError(`the licence payload is missing ${key}`);\n return value;\n };\n // `null` is the honest encoding of \"no end date\" — a sentinel year 9999 would\n // be a date somebody eventually compares against. Absent is still an error;\n // only an explicit null means never.\n const secondsOrNever = (key: string): number | null => {\n const value = o[key];\n if (value === null) return null;\n return seconds(key);\n };\n\n const plan = text(\"plan\");\n if (!PLANS.includes(plan as Plan)) {\n // A plan this SDK does not know is a newer commercial model, and refusing\n // to honour a licence we cannot classify would punish the customer for\n // buying something new. It is reported as unsupported so the developer is\n // told to upgrade.\n throw new LicenseFormatError(`this version of BroadPaper does not know the plan ${JSON.stringify(plan)}`, \"unsupported\");\n }\n\n // An evaluation licence is a term by definition. One with no end date could\n // only be a mistake, and honouring it would be a free licence forever.\n if (plan === \"evaluation\" && o.validUntil === null) {\n throw new LicenseFormatError(\"an evaluation licence must have an end date\");\n }\n\n const licenseType = text(\"licenseType\");\n if (!LICENSE_TYPES.includes(licenseType as LicenseType)) {\n throw new LicenseFormatError(`this version of BroadPaper cannot honour a ${JSON.stringify(licenseType)} licence`, \"unsupported\");\n }\n\n return {\n ...o,\n schemaVersion: 1,\n keyId: text(\"keyId\"),\n licenseId: text(\"licenseId\"),\n organisationId: text(\"organisationId\"),\n organisationName: text(\"organisationName\"),\n product: text(\"product\") as typeof PRODUCT,\n plan: plan as Plan,\n licenseType: licenseType as LicenseType,\n issuedAt: seconds(\"issuedAt\"),\n validUntil: secondsOrNever(\"validUntil\"),\n updatesUntil: seconds(\"updatesUntil\")\n };\n}\n\n/**\n * Encodes a payload into the text that gets signed.\n *\n * Exported because BroadPaper's own licence issuer must produce byte-identical\n * input to what the SDK verifies, and the only way to guarantee that is for\n * both to call this function.\n */\nexport function encodeSigningInput(payload: LicensePayload): { signedText: string; encodedPayload: string } {\n const encodedPayload = bytesToBase64Url(utf8ToBytes(JSON.stringify(payload)));\n return { encodedPayload, signedText: `${FORMAT_PREFIX}.${encodedPayload}` };\n}\n\n/** Assembles the final licence string from a payload and its signature. */\nexport function formatLicense(payload: LicensePayload, signature: Uint8Array): string {\n if (signature.length !== 64) throw new LicenseFormatError(`an Ed25519 signature is 64 bytes, this one is ${signature.length}`);\n const { encodedPayload } = encodeSigningInput(payload);\n return `${FORMAT_PREFIX}.${encodedPayload}.${bytesToBase64Url(signature)}`;\n}\n","/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */\n/**\n * 5KB JS implementation of ed25519 EdDSA signatures.\n * Targets RFC8032, FIPS 186-5, and ZIP215 behavior.\n * @module\n * @example\n * ```js\nimport * as ed from '@noble/ed25519';\n(async () => {\n const secretKey = ed.utils.randomSecretKey();\n const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);\n const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present\n const signature = await ed.signAsync(message, secretKey);\n const isValid = await ed.verifyAsync(signature, message, pubKey);\n})();\n```\n */\n/**\n * Curve params. edwards25519 uses the RFC equation `-x² + y² = 1 + dx²y²`.\n * The stored `a` literal below is `p - 1`, i.e. the field-element encoding of RFC `a = -1`.\n * * P = `2n**255n - 19n` // field over which calculations are done\n * * N = `2n**252n + 27742317777372353535851937790883648493n` // prime-order subgroup order\n * * h = 8 // cofactor\n * * a = `Fp.create(BigInt(-1))` // equation param, stored here as `p - 1`\n * * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param\n * * Gx, Gy are coordinates of Generator / base point\n *\n * Mirror noble-curves: Point.CURVE() exposes shared params, but callers must not be able to mutate\n * that shared view and desynchronize it from the arithmetic constants captured below.\n */\nconst freeze = Object.freeze;\nconst P = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn;\nconst N = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn;\nconst _d = 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n;\nconst Gx = 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an;\nconst Gy = 0x6666666666666666666666666666666666666666666666666666666666666658n;\nconst _a = P - 1n; // field-element encoding of RFC `a = -1`\nconst ed25519_CURVE = freeze({\n p: P,\n n: N,\n h: 8n,\n a: _a,\n d: _d,\n Gx,\n Gy,\n});\n// Shared 32-byte encoded width for Ed25519 points, scalars, signatures/2, and keys. Named LEN\n// rather than RFC 8032's `L`, which names the group order (stored here as `N`).\nconst LEN = 32;\n// Helpers and Precomputes sections are reused between libraries\n// ## Helpers\n// ----------\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nconst isBytes = (a) => {\n // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases.\n // The fallback still requires a real ArrayBuffer view, so plain\n // JSON-deserialized `{ constructor: ... }` spoofing is rejected, and\n // `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.\n return (a instanceof Uint8Array ||\n (ArrayBuffer.isView(a) &&\n a.constructor.name === 'Uint8Array' &&\n a.BYTES_PER_ELEMENT === 1));\n};\n/** Asserts something is Bytes. */\nconst abytes = (value, length, title = '') => {\n // Success path first: this runs at the start of every update() / digestInto(), and the\n // common `abytes(data)` form must not pay for length handling it does not use.\n if (isBytes(value) && (length === undefined || value.length === length))\n return value;\n // Error path: recompute freely to build the exact message.\n const bytes = isBytes(value);\n const ofLen = length !== undefined ? ` of length ${length}` : '';\n const got = bytes ? `length=${value.length}` : `type=${typeof value}`;\n const message = (title ? `\"${title}\" ` : '') + 'expected Uint8Array' + ofLen + ', got ' + got;\n if (!bytes)\n throw new TypeError(message);\n throw new RangeError(message);\n};\n// Validate, then take one owned copy, so later caller mutation cannot be observed — e.g. cannot\n// make sign()'s nonce derivation and challenge derivation see different messages.\nconst snapshotBytes = (value, title = '', length) => Uint8Array.from(abytes(value, length, title));\n// Callers keep values non-negative and within the requested width; padStart() won't truncate over-wide inputs.\nconst padh = (n, pad) => n.toString(16).padStart(pad, '0');\n/** Convert byte array to hex string. */\nconst bytesToHex = (bytes) => {\n let hex = '';\n for (const byte of abytes(bytes))\n hex += padh(byte, 2);\n return hex;\n};\n/** Convert hex string to byte array. */\nconst hexToBytes = (hex) => {\n const e = 'hex invalid'; // Strict ASCII hex only, with one generic error for parse failures.\n if (typeof hex !== 'string')\n throw new TypeError(e);\n if (hex.length % 2 || !/^[\\da-f]*$/i.test(hex))\n throw new RangeError(e);\n const array = new Uint8Array(hex.length / 2);\n for (let ai = 0, hi = 0; ai < array.length; ai++, hi += 2) {\n const n1 = hex.charCodeAt(hi);\n const n2 = hex.charCodeAt(hi + 1);\n // Regex guarantees ASCII. For 0..9/A..F/a..f, this maps char codes to 0..15.\n array[ai] = ((n1 & 15) + (n1 >> 6) * 9) * 16 + (n2 & 15) + (n2 >> 6) * 9;\n }\n return array;\n};\n// WebCrypto is available in all modern environments\n/** Copies several Uint8Arrays into one. */\nconst concatBytes = (...arrays) => {\n let sum = 0;\n for (const a of arrays)\n sum += abytes(a).length;\n const res = new Uint8Array(sum);\n let pad = 0;\n for (const a of arrays) {\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n};\n/**\n * WebCrypto OS-level CSPRNG (random number generator).\n * Will throw when not available; large-request ceilings are delegated to getRandomValues().\n */\nconst randomBytes = (len = LEN) => {\n const c = globalThis?.crypto;\n if (typeof c?.getRandomValues !== 'function')\n throw new Error('crypto.getRandomValues must be defined, consider polyfill');\n return c.getRandomValues(new Uint8Array(len));\n};\n/** Inclusive-lower, exclusive-upper bigint range assertion. */\nconst arange = (n, min, max, msg = 'bad number: out of range') => {\n if (typeof n !== 'bigint')\n throw new TypeError(msg);\n if (min <= n && n < max)\n return n;\n throw new RangeError(msg);\n};\n/** Canonical modular reduction. Callers must provide a positive modulus. */\nconst mod = (a, b = P) => ((a %= b) >= 0n ? a : b + a);\n// Low-255-bit mask used by the `2^255 - 19` fast reduction in `modP(...)`.\nconst P_MASK = (1n << 255n) - 1n;\n// Fast reduction for the special prime `2^255 - 19`. This path assumes nonnegative inputs; the\n// generic fallback would simply be `mod(num, P)`.\nconst modP = (num) => {\n if (num < 0n)\n throw new RangeError('negative coordinate');\n let r = (num >> 255n) * 19n + (num & P_MASK);\n r = (r >> 255n) * 19n + (r & P_MASK);\n return r % P;\n};\n// Reduce modulo the subgroup order stored in implementation constant `N` (RFC 8032's `L`).\nconst modN = (a) => mod(a, N);\n/** Modular inversion using extended euclidean GCD. Variable-time (non-CT). */\nconst invert = (number, modulo) => {\n if (number === 0n)\n throw new Error('invert: expected non-zero number');\n // modulo = 1 is the zero ring: gcd(x, 1) = 1 makes the loop below \"succeed\" and return the\n // useless inverse 0. Reject it like pow() and invertCt() do.\n if (modulo <= 1n)\n throw new Error('invert: expected modulus > 1, got ' + modulo);\n // This is variable-time: the loop count depends on `number`.\n let a = mod(number, modulo);\n let b = modulo;\n // Only the Bézout coefficient of `number` (x/u chain) is tracked; the coefficient of `modulo`\n // never affects the output, so it is not computed.\n // prettier-ignore\n let x = 0n, u = 1n;\n while (a !== 0n) {\n const q = b / a;\n const r = b - a * q;\n const m = x - u * q;\n // prettier-ignore\n b = a, a = r, x = u, u = m;\n }\n const gcd = b;\n if (gcd !== 1n)\n throw new Error('invert: does not exist');\n return mod(x, modulo);\n};\n// Dynamic lookup keeps sync/async hash providers configurable at runtime. Both exported slots are\n// caller-owned and may be unset; wrapper helpers use this lookup first and then enforce the digest\n// contract instead of trusting provider output.\nconst _hash = (name) => {\n // @ts-ignore\n const fn = hashes[name];\n if (typeof fn !== 'function')\n throw new Error('hashes.' + name + ' not set');\n return fn;\n};\n// All exported provider slots are caller-configurable and may be unset or return arbitrary values,\n// so wrapper helpers must enforce the exact 64-byte SHA-512 digest contract instead of trusting providers.\nconst callHash = (name, ...m) => abytes(_hash(name)(concatBytes(...m)), 64, 'digest');\nconst callHashAsync = async (name, ...m) => abytes(await _hash(name)(concatBytes(...m)), 64, 'digest');\n/**\n * SHA-512 helper used by the synchronous API.\n * @param msg - Message bytes to hash.\n * @returns 64-byte SHA-512 digest.\n * @example\n * Hash message bytes after wiring the synchronous SHA-512 implementation.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const digest = ed.hash(new Uint8Array([1, 2, 3]));\n * ```\n */\n// Public helper validates the message boundary explicitly; the configured provider is still looked\n// up dynamically and its output is checked with `callHash(...)`.\nconst hash = (msg) => callHash('sha512', abytes(msg, undefined, 'message'));\n// Runtime class guard: this is `instanceof Point`, so cross-realm / duplicate-bundle Point objects\n// are rejected even if they are structurally identical.\nconst apoint = (p) => {\n if (p instanceof Point)\n return p;\n throw new TypeError('Point expected');\n};\n// ## End of Helpers\n// -----------------\n// Exclusive upper bound `2^256` used by 32-byte decode/serialization range checks.\nconst B256 = 2n ** 256n;\n/**\n * Point in XYZT extended coordinates.\n * @param X - X coordinate.\n * @param Y - Y coordinate.\n * @param Z - Projective Z coordinate.\n * @param T - Cached cross-product term.\n * @example\n * Do point arithmetic with the built-in base point and encode the result as hex.\n *\n * ```ts\n * const hex = Point.BASE.double().toHex();\n * ```\n */\nclass Point {\n static BASE;\n static ZERO;\n X;\n Y;\n Z;\n T;\n // Constructor only bounds-checks and freezes XYZT coordinates; it does not prove the point is\n // on-curve or that T matches X*Y/Z.\n constructor(X, Y, Z, T) {\n const max = B256;\n this.X = arange(X, 0n, max);\n this.Y = arange(Y, 0n, max);\n this.Z = arange(Z, 1n, max);\n this.T = arange(T, 0n, max);\n freeze(this);\n }\n static CURVE() {\n return ed25519_CURVE;\n }\n static fromAffine(p) {\n return new Point(p.x, p.y, 1n, modP(p.x * p.y));\n }\n /** RFC8032 5.1.3: Uint8Array to Point. */\n static fromBytes(bytes, zip215 = false) {\n const normed = snapshotBytes(bytes, 'point', LEN); // owned copy: sign-bit mask below mutates it\n // adjust first LE byte = last BE byte\n const lastByte = normed[31];\n normed[31] = lastByte & ~0x80;\n const y = bytesToNumberLE(normed);\n // After clearing the sign bit, parsed `y` is always < 2^255. ZIP-215 still accepts the full\n // post-mask range here, while strict RFC8032 decoding further requires `y < p`.\n if (!zip215)\n arange(y, 0n, P);\n const y2 = modP(y * y); // y²\n const u = mod(y2 - 1n); // u=y²-1\n const v = modP(_d * y2 + 1n); // v=dy²+1\n let { isValid, value: x } = uvRatio(u, v); // (uv³)(uv⁷)^(p-5)/8; square root\n if (!isValid)\n throw new Error('bad point: y not sqrt'); // not square root: bad point\n const isLastByteOdd = !!(lastByte & 0x80); // x_0, last bit\n // ZIP-215-compatible decoding keeps the x=0 / sign-bit=1 encoding accepted; strict RFC 8032\n // rejects it, but the vendored ZIP-215 compliance vectors include this form in A/R bytes.\n if (!zip215 && x === 0n && isLastByteOdd)\n throw new Error('bad point: x==0, isLastByteOdd'); // x=0, x_0=1\n if (isLastByteOdd !== !!(x & 1n))\n x = mod(-x); // adjust sign of x coordinate\n return new Point(x, y, 1n, modP(x * y)); // Z=1, T=xy\n }\n static fromHex(hex, zip215) {\n return Point.fromBytes(hexToBytes(hex), zip215);\n }\n get x() {\n return this.toAffine().x;\n }\n get y() {\n return this.toAffine().y;\n }\n /** Checks if the point is valid and on-curve. */\n assertValidity() {\n const a = _a;\n const d = _d;\n const p = this;\n // Intentional stricter-than-on-curve policy: reject ZERO by default because many protocols\n // require a non-zero point, and silently accepting identity points is a common caller mistake.\n if (p.is0())\n throw new Error('bad point: ZERO');\n // Equation in affine coordinates: ax² + y² = 1 + dx²y²\n // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²\n const { X, Y, Z, T } = p;\n const X2 = modP(X * X); // X²\n const Y2 = modP(Y * Y); // Y²\n const Z2 = modP(Z * Z); // Z²\n const Z4 = modP(Z2 * Z2); // Z⁴\n const aX2 = modP(X2 * a); // aX²\n const left = modP(Z2 * (aX2 + Y2)); // (aX² + Y²)Z²\n const right = mod(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²\n if (left !== right)\n throw new Error('bad point: equation left != right (1)');\n // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T\n const XY = modP(X * Y);\n const ZT = modP(Z * T);\n if (XY !== ZT)\n throw new Error('bad point: equation left != right (2)');\n return this;\n }\n /** Equality check: compare points P&Q. */\n equals(other) {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality\n return modP(X1 * Z2) === modP(X2 * Z1) && modP(Y1 * Z2) === modP(Y2 * Z1);\n }\n is0() {\n return this.equals(I);\n }\n /** Flip point over y coordinate. */\n negate() {\n return new Point(mod(-this.X), this.Y, this.Z, mod(-this.T));\n }\n /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */\n double() {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const a = _a;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd\n const A = modP(X1 * X1);\n const B = modP(Y1 * Y1);\n const C = modP(2n * Z1 * Z1);\n const D = modP(a * A);\n const x1y1 = mod(X1 + Y1);\n const E = mod(modP(x1y1 * x1y1) - A - B);\n const G = mod(D + B);\n const F = mod(G - C);\n const H = mod(D - B);\n const X3 = modP(E * F);\n const Y3 = modP(G * H);\n const T3 = modP(E * H);\n const Z3 = modP(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n /** Point addition. Complete formula. Cost: `9M + 1*a + 1*d + 7add`. */\n add(other) {\n const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;\n const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); // doesn't check if other on-curve\n const a = _a;\n const d = _d;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd\n const A = modP(X1 * X2);\n const B = modP(Y1 * Y2);\n const C = modP(modP(T1 * d) * T2);\n const D = modP(Z1 * Z2);\n const E = mod(modP(mod(X1 + Y1) * mod(X2 + Y2)) - A - B);\n const F = mod(D - C);\n const G = mod(D + C);\n const H = mod(B - modP(a * A));\n const X3 = modP(E * F);\n const Y3 = modP(G * H);\n const T3 = modP(E * H);\n const Z3 = modP(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n subtract(other) {\n return this.add(apoint(other).negate());\n }\n /**\n * Point-by-scalar multiplication. Safe mode requires `1 <= n < CURVE.n`.\n * Unsafe mode additionally permits `n = 0` and returns the identity point for that case.\n * Uses {@link wNAF} for base point.\n * Uses fake point to mitigate side-channel leakage.\n * @param n - scalar by which point is multiplied\n * @param safe - safe mode guards against timing attacks; unsafe mode is faster\n */\n multiply(n, safe = true) {\n // Mirror noble-curves: unsafe mode still validates scalar range first, but intentionally keeps\n // `n = 0` as the one extra accepted case used by verification-style callers.\n if (!safe && n === 0n)\n return I;\n arange(n, 1n, N);\n if (!safe && this.is0())\n return I;\n if (n === 1n)\n return this;\n if (this.equals(G))\n return wNAF(n).p;\n // init result point & fake point\n let p = I;\n let f = G;\n let d = this;\n // Safe mode always runs 256 iterations so ladder length can't leak the scalar's\n // leading zero bits; unsafe mode stops at the top set bit for speed.\n for (let i = 0; safe ? i < 256 : n > 0n; i++) {\n // if bit is present, add to point\n // if not present, add to fake, for timing safety\n if (n & 1n)\n p = p.add(d);\n else if (safe)\n f = f.add(d);\n d = d.double();\n n >>= 1n;\n }\n return p;\n }\n multiplyUnsafe(scalar) {\n return this.multiply(scalar, false);\n }\n /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */\n toAffine() {\n const { X, Y, Z } = this;\n // Fast-path only for the identity point; all other inputs still go through inversion.\n if (this.equals(I))\n return { x: 0n, y: 1n };\n const iz = invert(Z, P);\n // (Z * Z^-1) must be 1, otherwise bad math\n if (modP(Z * iz) !== 1n)\n throw new Error('invalid inverse');\n // x = X*Z^-1; y = Y*Z^-1\n return { x: modP(X * iz), y: modP(Y * iz) };\n }\n toBytes() {\n const { x, y } = this.toAffine();\n const b = numTo32bLE(y);\n // store sign in first LE byte\n b[31] |= x & 1n ? 0x80 : 0;\n return b;\n }\n toHex() {\n return bytesToHex(this.toBytes());\n }\n clearCofactor() {\n return this.multiply(8n, false); // h = 8\n }\n isSmallOrder() {\n return this.clearCofactor().is0();\n }\n isTorsionFree() {\n // Multiply by big number N. We can't `mul(N)` because of checks. Instead, we `mul(N/2)*2+1`;\n // N is odd, so N/2 truncates and the final `add(this)` is always needed.\n return this.multiply(N / 2n, false)\n .double()\n .add(this)\n .is0();\n }\n}\n/** Generator / base point */\nconst G = new Point(Gx, Gy, 1n, mod(Gx * Gy));\n/** Identity / zero point */\nconst I = new Point(0n, 1n, 1n, 0n);\n// Static aliases\nPoint.BASE = G;\nPoint.ZERO = I;\nconst numTo32bLE = (num) => hexToBytes(padh(arange(num, 0n, B256), 64)).reverse();\n// Caller-enforced width: some sites require 32-byte RFC encodings, while others intentionally feed\n// wider SHA-512 output chunks through the same little-endian parser.\nconst bytesToNumberLE = (b) => BigInt('0x' + bytesToHex(Uint8Array.from(abytes(b)).reverse()));\nconst pow2 = (x, power) => {\n // pow2(x, 4) == x^(2^4)\n // Negative `power` values are not rejected here and currently leave `x` unchanged.\n let r = x;\n while (power-- > 0) {\n r = modP(r * r);\n }\n return r;\n};\n// prettier-ignore\nconst pow_2_252_3 = (x) => {\n const x2 = modP(x * x); // x^2, bits 1\n const b2 = modP(x2 * x); // x^3, bits 11\n const b4 = modP(pow2(b2, 2) * b2); // x^(2^4-1), bits 1111\n const b5 = modP(pow2(b4, 1) * x); // x^(2^5-1), bits 11111\n const b10 = modP(pow2(b5, 5) * b5); // x^(2^10-1)\n const b20 = modP(pow2(b10, 10) * b10); // x^(2^20-1)\n const b40 = modP(pow2(b20, 20) * b20); // x^(2^40-1)\n const b80 = modP(pow2(b40, 40) * b40); // x^(2^80-1)\n const b160 = modP(pow2(b80, 80) * b80); // x^(2^160-1)\n const b240 = modP(pow2(b160, 80) * b80); // x^(2^240-1)\n const b250 = modP(pow2(b240, 10) * b10); // x^(2^250-1)\n return modP(pow2(b250, 2) * x); // x^((p-5)/8), used by RFC8032 point decode\n};\nconst RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // 2^((p-1)/4) = sqrt(-1)\n// RFC8032 §5.1.3 square-root helper for point decompression. `value` is only meaningful when\n// `isValid` is true; callers are also expected to pass canonical field elements with non-zero `v`.\n// prettier-ignore\nconst uvRatio = (u, v) => {\n const v3 = modP(v * modP(v * v)); // v³\n const v7 = modP(modP(v3 * v3) * v); // v⁷\n const pow = pow_2_252_3(modP(u * v7)); // (uv⁷)^(p-5)/8\n let x = modP(u * modP(v3 * pow)); // (uv³)(uv⁷)^(p-5)/8\n const vx2 = modP(v * modP(x * x)); // vx²\n const root1 = x; // First root candidate\n const root2 = modP(x * RM1); // Second root candidate; RM1 is √-1\n const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root\n const useRoot2 = vx2 === mod(-u); // If vx² = -u, set x <-- x * 2^((p-1)/4)\n const noRoot = vx2 === mod(-u * RM1); // There is no valid root, vx² = -u√-1\n if (useRoot1)\n x = root1;\n if (useRoot2 || noRoot)\n x = root2; // We return root2 anyway, for const-time\n if ((mod(x) & 1n) === 1n)\n x = mod(-x); // edIsNegative\n return { isValid: useRoot1 || useRoot2, value: x };\n};\n// Reduce a little-endian byte string modulo the subgroup order `N` (RFC 8032's `L`); the `hash`\n// param name reflects the common caller shape, not an input restriction.\nconst modL_LE = (hash) => modN(bytesToNumberLE(hash));\n// RFC8032 5.1.5. Split the 64-byte hashed seed into the clamped scalar half and nonce prefix.\nconst hashedToExtK = (hashed) => {\n // slice creates a copy, unlike subarray\n const copy = snapshotBytes(hashed);\n const head = copy.slice(0, 32);\n head[0] &= 248; // Clamp bits: 0b1111_1000\n head[31] &= 127; // 0b0111_1111\n head[31] |= 64; // 0b0100_0000\n const prefix = copy.slice(32); // secret key \"prefix\"\n // RFC words this as `[s]B`; reducing the clamped little-endian scalar modulo `N` is equivalent\n // for base-point multiplication because `G` already has subgroup order `N`.\n const scalar = modL_LE(head);\n const point = G.multiply(scalar); // public key point\n const pointBytes = point.toBytes(); // point serialized to Uint8Array\n return { head, prefix, scalar, point, pointBytes };\n};\n// RFC8032 5.1.5; getPublicKey async, sync. Hash secret key and extract point.\nconst getExtendedPublicKeyAsync = (secretKey) => callHashAsync('sha512Async', abytes(secretKey, LEN, 'secretKey')).then(hashedToExtK);\nconst getExtendedPublicKey = (secretKey) => hashedToExtK(callHash('sha512', abytes(secretKey, LEN, 'secretKey')));\n/**\n * Creates a 32-byte Ed25519 public key from the RFC 8032 32-byte secret-key seed. Async.\n * @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.\n * @returns 32-byte public key.\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Derive the public key bytes for a newly generated signer secret.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const secretKey = ed.utils.randomSecretKey();\n * const publicKey = await ed.getPublicKeyAsync(secretKey);\n * ```\n */\nconst getPublicKeyAsync = (secretKey) => getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes);\n/**\n * Creates a 32-byte Ed25519 public key from the RFC 8032 32-byte secret-key seed.\n * To use, set `hashes.sha512` first.\n * @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.\n * @returns 32-byte public key.\n * @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Derive the public key entirely through the synchronous API.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const secretKey = ed.utils.randomSecretKey();\n * const publicKey = ed.getPublicKey(secretKey);\n * ```\n */\nconst getPublicKey = (secretKey) => getExtendedPublicKey(secretKey).pointBytes;\nconst hashFinishAsync = async (res) => res[1](await callHashAsync('sha512Async', res[0]));\nconst hashFinishSync = (res) => res[1](callHash('sha512', res[0]));\n// Code, shared between sync & async sign\nconst _sign = (e, rBytes, msg) => {\n const { pointBytes: A, scalar: s } = e;\n const r = modL_LE(rBytes); // r was created outside, reduce it modulo L\n // RFC 8032 5.1.6 allows r mod L = 0, and SUPERCOP ref10 accepts the resulting identity-point\n // signature.\n // We intentionally keep the safe multiply() rejection here so a miswired all-zero SHA-512 provider\n // fails loudly instead of silently producing a degenerate signature.\n const R = G.multiply(r).toBytes(); // R = [r]B\n const hashable = concatBytes(R, A, msg); // dom2(F, C) || R || A || PH(M)\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l\n return abytes(concatBytes(R, numTo32bLE(S)), 64); // 64-byte sig: 32-byte encoded R point || 32-byte LE(S)\n };\n return [hashable, finish];\n};\n/**\n * Signs message using secret key. Async.\n * Follows RFC8032 5.1.6.\n * @param message - Message bytes to sign.\n * @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.\n * @returns 64-byte Ed25519 signature.\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Sign an arbitrary message with a fresh Ed25519 secret key.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const secretKey = ed.utils.randomSecretKey();\n * const message = new Uint8Array([1, 2, 3]);\n * const signature = await ed.signAsync(message, secretKey);\n * ```\n */\nconst signAsync = async (message, secretKey) => {\n const m = snapshotBytes(message, 'message');\n const e = await getExtendedPublicKeyAsync(secretKey);\n // r = SHA512(dom2(F, C) || prefix || PH(M)); then generate R, k, S and the signature.\n return hashFinishAsync(_sign(e, await callHashAsync('sha512Async', e.prefix, m), m));\n};\n/**\n * Signs message using secret key. To use, set `hashes.sha512` first.\n * Follows RFC8032 5.1.6.\n * @param message - Message bytes to sign.\n * @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.\n * @returns 64-byte Ed25519 signature.\n * @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Use the sync API when you've wired a SHA-512 implementation yourself.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const secretKey = ed.utils.randomSecretKey();\n * const signature = ed.sign(new Uint8Array([1, 2, 3]), secretKey);\n * ```\n */\nconst sign = (message, secretKey) => {\n const m = snapshotBytes(message, 'message');\n const e = getExtendedPublicKey(secretKey);\n // r = SHA512(dom2(F, C) || prefix || PH(M)); then generate R, k, S and the signature.\n return hashFinishSync(_sign(e, callHash('sha512', e.prefix, m), m));\n};\n// Exported defaults favor ZIP-215 interoperability semantics; callers must opt into the stricter\n// branch with `{ zip215: false }`.\n// Preserves the exported ZIP-215 default for `{}` / `{ zip215: undefined }`, not just omitted opts.\nconst getZip215 = (options) => {\n if (options === null || typeof options !== 'object')\n throw new TypeError('expected valid options object');\n return options.zip215 ?? true;\n};\nconst _verify = (sig, msg, publicKey, options) => {\n sig = abytes(sig, 64, 'signature'); // Signature hex str/Bytes, must be 64 bytes\n msg = abytes(msg, undefined, 'message'); // Message hex str/Bytes\n publicKey = abytes(publicKey, LEN, 'publicKey');\n const zip215 = getZip215(options);\n // zip215=false keeps the library's stricter branch, which still canonicalizes `R` / `A` before\n // hashing and rejects small-order public keys earlier than pure RFC8032 text would require.\n const r = sig.subarray(0, LEN);\n const s = bytesToNumberLE(sig.subarray(LEN, 64)); // Decode second half as an integer S;\n let A, R, SB;\n let hashable = Uint8Array.of();\n let finished = false;\n try {\n // zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.\n // zip215=true: 0 <= y < MASK (2^256 for ed25519)\n // zip215=false: 0 <= y < P (2^255-19 for ed25519)\n A = Point.fromBytes(publicKey, zip215);\n R = Point.fromBytes(r, zip215);\n SB = G.multiply(s, false); // 0 <= s < l is done inside\n // ZIP-215 accepts noncanonical / unreduced point encodings, so the challenge hash must use the\n // exact signature/public-key bytes rather than canonicalized re-encodings of the decoded points.\n hashable = concatBytes(r, publicKey, msg); // dom2(F, C) || R || A || PH(M)\n finished = true;\n }\n catch (error) { }\n const finish = (hashed) => {\n if (!finished)\n return false;\n // Policy: strict mode intentionally rejects all small-order public keys, even though the raw RFC\n // equation text is looser here. This matches libsodium and avoids weak / ambiguous verification\n // outcomes where unusual low-order public keys can make distinct key/signature combinations verify.\n if (!zip215 && A.isSmallOrder())\n return false;\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n const k = modL_LE(hashed);\n const RkA = R.add(A.multiply(k, false));\n // Extended group equation\n // [8][S]B = [8]R + [8][k]A'\n return RkA.subtract(SB).clearCofactor().is0();\n };\n return [hashable, finish];\n};\n/**\n * Verifies a signature on message and public key. Async.\n * The implementation is based on RFC8032 5.1.7, but default opts use ZIP-215 semantics; pass\n * `{ zip215: false }` for the library's stricter branch.\n * @param signature - 64-byte signature.\n * @param message - Signed message bytes.\n * @param publicKey - 32-byte public key.\n * @param opts - Verification options. Defaults to ZIP-215 semantics. See {@link EdDSAVerifyOpts}.\n * @returns `true` when the signature is valid.\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Verify the signature against the same message and derived public key.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const secretKey = ed.utils.randomSecretKey();\n * const message = new Uint8Array([1, 2, 3]);\n * const publicKey = await ed.getPublicKeyAsync(secretKey);\n * const signature = await ed.signAsync(message, secretKey);\n * const isValid = await ed.verifyAsync(signature, message, publicKey);\n * ```\n */\nconst verifyAsync = async (signature, message, publicKey, opts = {}) => hashFinishAsync(_verify(signature, message, publicKey, opts));\n/**\n * Verifies a signature on message and public key using the synchronous hash path.\n * The implementation is based on RFC8032 5.1.7, but default opts use ZIP-215 semantics; pass\n * `{ zip215: false }` for the library's stricter branch.\n * @param signature - 64-byte signature.\n * @param message - Signed message bytes.\n * @param publicKey - 32-byte public key.\n * @param opts - Verification options. Defaults to ZIP-215 semantics. See {@link EdDSAVerifyOpts}.\n * @returns `true` when the signature is valid.\n * @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Verify a signature entirely through the synchronous API.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const secretKey = ed.utils.randomSecretKey();\n * const message = new Uint8Array([1, 2, 3]);\n * const publicKey = ed.getPublicKey(secretKey);\n * const signature = ed.sign(message, secretKey);\n * const isValid = ed.verify(signature, message, publicKey);\n * ```\n */\nconst verify = (signature, message, publicKey, opts = {}) => hashFinishSync(_verify(signature, message, publicKey, opts));\n/**\n * Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves.\n * Exposes the same low-level field-default `mod` reducer and non-CT `invert` helper used\n * internally.\n * @example\n * Convert bytes to a hex string with the low-level helper namespace.\n *\n * ```ts\n * const hex = etc.bytesToHex(new Uint8Array([1, 2, 3]));\n * ```\n */\nconst etc = /* @__PURE__ */ freeze({\n bytesToHex,\n hexToBytes,\n concatBytes,\n mod,\n invert,\n randomBytes,\n});\n/**\n * Hash implementations used by the synchronous API plus the default async WebCrypto provider.\n * Both slots are configurable API surface; wrapper helpers revalidate that providers still return\n * 64-byte SHA-512 digests.\n * @example\n * Provide a SHA-512 implementation before calling synchronous helpers.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const { publicKey } = ed.keygen();\n * ```\n */\nconst hashes = {\n sha512Async: async (message) => {\n const s = globalThis?.crypto?.subtle;\n if (!s)\n throw new Error('crypto.subtle must be defined, consider polyfill');\n return new Uint8Array(await s.digest('SHA-512', concatBytes(message)));\n },\n sha512: undefined,\n};\n// Returns the final 32-byte Ed25519 secret-key seed verbatim, generating fresh random bytes only\n// when omitted.\nconst randomSecretKey = (seed) => {\n return abytes(seed === undefined ? randomBytes() : seed, LEN, 'seed');\n};\n/**\n * Generates a secret/public keypair.\n * @param seed - Optional 32-byte Ed25519 secret-key seed, returned verbatim as `secretKey`.\n * @returns Keypair with `secretKey` and `publicKey`.\n * @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Generate a new keypair through the synchronous API after wiring SHA-512.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const { secretKey, publicKey } = ed.keygen();\n * ```\n */\nconst keygen = (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = getPublicKey(secretKey);\n return { secretKey, publicKey };\n};\n/**\n * Generates a secret/public keypair asynchronously.\n * @param seed - Optional 32-byte Ed25519 secret-key seed, returned verbatim as `secretKey`.\n * @returns Keypair with `secretKey` and `publicKey`.\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Generate a new keypair through the asynchronous WebCrypto-backed path.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const { secretKey, publicKey } = await ed.keygenAsync();\n * ```\n */\nconst keygenAsync = async (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = await getPublicKeyAsync(secretKey);\n return { secretKey, publicKey };\n};\n/**\n * Ed25519-specific key utilities.\n * `utils.getExtendedPublicKey*` expose secret-derived internals (`head`, `prefix`, `scalar`, and\n * point objects), not just public-key bytes.\n * @example\n * Generate a new Ed25519 secret key and derive the matching public key.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const secretKey = ed.utils.randomSecretKey();\n * const publicKey = await ed.getPublicKeyAsync(secretKey);\n * ```\n */\nconst utils = /* @__PURE__ */ freeze({\n getExtendedPublicKeyAsync,\n getExtendedPublicKey,\n randomSecretKey,\n});\n// ## Precomputes\n// --------------\n// Fixed W=8 window: 33 windows (ceil(256/8) + 1, NOT 32 - see wNAF loop), 128 points per window.\n// Layout is grouped by window: each block stores the positive multiples `1*base .. 128*base` for\n// that window, and the extra `+1` window absorbs carries from signed-digit recoding.\nconst precompute = () => {\n const points = [];\n let p = G;\n let b;\n for (let w = 0; w < 33; w++) {\n b = p;\n points.push(b);\n for (let i = 1; i < 128; i++) {\n b = b.add(p);\n points.push(b);\n } // i=1, bc we skip 0\n p = b.double();\n }\n return points;\n};\nlet Gpows = undefined; // shared process-wide cache of base-point precomputes\n// Branch-based negate helper used for JS/JIT mitigation symmetry, not a strict constant-time claim.\nconst ctneg = (cnd, p) => {\n const n = p.negate();\n return cnd ? n : p;\n};\n/**\n * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by\n * caching multiples of G (base point). Cache is stored in 32MB of RAM.\n * Any time `G.multiply` is done, precomputes are used.\n * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.\n *\n * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,\n * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.\n * Returns the real accumulator `p` plus a fake accumulator `f`; callers only care about `p`, while\n * `f` exists to keep similar work in zero-digit branches as a JS/JIT side-channel mitigation.\n *\n * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().\n */\nconst wNAF = (n) => {\n const comp = Gpows || (Gpows = precompute());\n let p = I;\n let f = G; // f must be G, or could become I in the end\n for (let w = 0; w < 33; w++) {\n let wbits = Number(n & 255n); // extract W=8 bits.\n n >>= 8n; // shift number by W=8 bits.\n // We use negative indexes to reduce size of precomputed table by 2x.\n // Instead of needing precomputes 0..256, we only calculate them for 0..128.\n // If an index > 128 is found, we do (256-index) - where 256 is next window.\n // Naive: index +127 => 127, +224 => 224\n // Optimized: index +127 => 127, +224 => 256-32\n if (wbits > 128) {\n wbits -= 256;\n n += 1n;\n }\n const off = w * 128; // offset of this window's block; also the fake-add index\n const offP = off + Math.abs(wbits) - 1; // real-add index; both offsets always evaluated\n const isOddW = w % 2 !== 0; // conditions, evaluate both; alternates fake-add sign per window\n const isNeg = wbits < 0;\n if (wbits === 0) {\n // wbits == 0 means the real index would be I: can't add it. Add window offset `off` instead.\n f = f.add(ctneg(isOddW, comp[off])); // bits are 0: add garbage to fake point\n }\n else {\n p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point\n }\n }\n if (n !== 0n)\n throw new Error('invalid wnaf');\n return { p, f }; // return both real and fake points for JIT/leakage-shape symmetry\n};\n// !! Remove the export to easily use in REPL / browser console\nexport { etc, getPublicKey, getPublicKeyAsync, hash, hashes, keygen, keygenAsync, Point, sign, signAsync, utils, verify, verifyAsync, };\n","/**\n * The public keys this build of the SDK will accept licence signatures from.\n *\n * **This file contains public keys only.** BroadPaper's private signing key\n * lives in the licence issuer's secret store and is never in this repository,\n * never in the npm package and never in a browser bundle. Publishing the\n * public half is the point: it is what lets a licence be checked with no\n * network call.\n *\n * Add a production key with:\n *\n * node scripts/licence-keys.mjs --production --key-id bp-1\n *\n * which prints the private key once, for the operator to paste into the\n * issuer's configuration, and writes the public half into this array.\n *\n * The list is an allowlist, so it is also the rotation mechanism: issue with a\n * new `keyId`, ship an SDK release trusting both, and drop the old entry once\n * every licence signed with it has expired. Licences carry their `keyId` inside\n * the signed payload, so an attacker cannot point one at a different key.\n *\n * It starts empty on purpose. A key here is trusted by every copy of the SDK in\n * the world, including production installs, which is exactly why a development\n * key must never be added to it — development keys are supplied at runtime\n * instead, through `configure({ trustedKeys })` or `BROADPAPER_TRUSTED_KEYS`,\n * so a licence signed in development cannot be honoured by a production build.\n */\nimport type { TrustedKey } from \"./types.js\";\n\nexport const TRUSTED_KEYS: readonly TrustedKey[] = [\n { keyId: \"bp-2026\", publicKey: \"woKmWyIazae7SpGhi4dwA7zNK1lWdboq88Rl5xscTs4\", note: \"production, generated 2026-09-08\" }\n];\n","/**\n * The licence certificate and the states it can be in.\n *\n * A BroadPaper licence is a signed certificate, not a secret. It says who\n * bought what and until when, BroadPaper signs it, and the SDK checks that\n * signature with a public key compiled into the package. Nothing here talks to\n * a network, reads a machine identifier or writes a file: a licence that is\n * valid on a laptop with no route to the internet is valid, full stop.\n */\n\n/**\n * Which licence was bought. Not a feature gate — both plans unlock exactly the\n * same software. The difference is who the resulting application may be put in\n * front of, which is a contractual matter and is presented as one in the\n * account area and the licence agreement.\n *\n * These are the `id`s in `shared/plans.json`, deliberately: that file is the\n * one machine-readable statement of the commercial model, and a certificate\n * that quotes a different vocabulary from the thing that priced it is a\n * certificate somebody eventually has to write a mapping table for.\n */\nexport type Plan = \"internal\" | \"saas\" | \"evaluation\";\n\n/**\n * The free, time-limited licence a developer gets from their account in\n * exchange for telling us who they are.\n *\n * It removes the mark while somebody evaluates, and nothing else: it permits no\n * production use, and it has no grace period — the day it ends, the mark comes\n * back. It is not in `shared/plans.json`, because nothing sells it.\n *\n * SDKs before 1.0 do not know the word and report such a licence as\n * `unsupported`, which keeps the mark and says to upgrade. That is the fail-safe\n * direction, and `tests/site/licence-format.test.ts` holds 0.4.1 to it.\n */\nexport const EVALUATION_PLAN = \"evaluation\" satisfies Plan;\n\n/**\n * How the licence is held.\n *\n * `subscription` is a term: the right to use the software ends with the term,\n * and so does the right to updates. It is the only thing sold today.\n *\n * `perpetual` is reserved. It would mean the right to use never ends, while\n * the right to updates still does — `validUntil` null, `updatesUntil` set. The\n * field exists now so that offering one later is a change to what the issuer\n * writes rather than a change to the certificate format, which would mean\n * reissuing every licence in the field. **This SDK does not honour one**: see\n * `readPayload` in `format.ts` for why refusing is the only safe answer.\n */\nexport type LicenseType = \"subscription\" | \"perpetual\";\n\n/** The product a licence is for. Present so one signing key can serve more later. */\nexport const PRODUCT = \"broadpaper-sdk\";\n\n/**\n * The signed payload.\n *\n * `organisationId` is the durable identifier of the buying organisation — a\n * Clerk organisation id — rather than an email address, because people change\n * addresses and organisations outlive their founders. It is *not* the Creem\n * customer id, which identifies the same buyer to the payment processor and is\n * a different string; the API keeps both, and naming this one for the\n * organisation is what stops the two being confused at a glance.\n *\n * Times are epoch **seconds**, not milliseconds and not ISO strings. The\n * certificate is written by `Utf8JsonWriter` in C# and read by `JSON.parse` in\n * TypeScript, and an integer cannot disagree about a timezone suffix or a\n * fractional second the way two date serialisers can — which matters more here\n * than anywhere, because the two halves only find out they disagree when a\n * customer's licence is rejected in the field.\n *\n * Field order is load-bearing on the issuing side only: `encodeSigningInput`\n * serialises this object, and `LicenceSigner.Payload` writes the same keys in\n * the same order so a certificate is byte-identical whichever issued it.\n * Verification never re-serialises — it checks the signature over the text as\n * received — so an unknown field from a later BroadPaper is carried through\n * rather than rejected.\n */\nexport interface LicensePayload {\n /**\n * Payload schema version. Bumped only when the meaning of a field changes,\n * never to add one: `readPayload` keeps fields it does not know about, so a\n * later BroadPaper can extend the certificate without older SDKs refusing it.\n */\n schemaVersion: 1;\n /** Which signing key signed this. Lets keys be rotated without reissuing everything. */\n keyId: string;\n /**\n * BroadPaper's own identifier for *this certificate*, `lic_…`.\n *\n * One per issuance, so a renewal or an upgrade carries a new one and the\n * document it produced can be dated from it. The buyer is identified by\n * `organisationId`, which does not change.\n */\n licenseId: string;\n /** The licensed organisation's durable id. A Clerk organisation id. */\n organisationId: string;\n /** The organisation's name, for display in warnings and PDF metadata. */\n organisationName: string;\n product: typeof PRODUCT;\n plan: Plan;\n licenseType: LicenseType;\n /** Epoch seconds. */\n issuedAt: number;\n /**\n * When the right to *use* the software ends, in epoch seconds.\n *\n * Null means never, which only a perpetual licence says. A subscription\n * always carries a date.\n */\n validUntil: number | null;\n /**\n * When the right to *updates* ends, in epoch seconds.\n *\n * For a subscription this equals `validUntil` and nothing reads it: the term\n * ends, and both rights end with it. It is separate from `validUntil` because\n * for a perpetual licence the two genuinely differ, and that is the whole\n * reason the field is here before anything consults it.\n */\n updatesUntil: number;\n}\n\n/**\n * Why a licence is not being honoured, or how it is being honoured.\n *\n * These are deliberately coarse. A developer needs to know whether their PDFs\n * will carry the evaluation mark and, if so, what to do about it; a taxonomy of\n * eleven parse failures helps nobody.\n */\nexport type LicenseState =\n /** No licence was configured. The SDK works; PDFs carry the evaluation mark. */\n | \"unlicensed\"\n /** A licence was configured but could not be read, or its signature is wrong. */\n | \"invalid\"\n /** Signed by a key this build of the SDK does not trust. */\n | \"untrusted\"\n /** For a different product, or a certificate this SDK is too old to honour. */\n | \"unsupported\"\n /** Valid, signed, and inside its term. */\n | \"active\"\n /** Past `validUntil` but inside the grace period: honoured, and warned about. */\n | \"grace\"\n /** Past `validUntil` and past the grace period. */\n | \"expired\";\n\n/** The outcome of checking a licence. Everything the SDK needs to decide. */\nexport interface LicenseStatus {\n state: LicenseState;\n /** True when PDFs render clean. `active` and `grace` only. */\n licensed: boolean;\n /** The payload, when one could be read and verified. */\n payload: LicensePayload | null;\n /** Which licence was bought, when it is being honoured. */\n plan: Plan | null;\n /** When the right to use ends, when known. Null for a licence with no end. */\n validUntil: Date | null;\n /** Days until `validUntil`; negative once expired. Null when there is no end date. */\n daysRemaining: number | null;\n /**\n * A developer-facing sentence. Always present for a state that is not\n * `active`, so callers can log it without composing their own prose.\n */\n message: string | null;\n /**\n * An informational line for a licence that *is* being honoured but is worth\n * knowing about — today, only an evaluation licence, which says when it ends.\n * Logged at info level, once. Optional so a status built by hand elsewhere\n * still type-checks.\n */\n notice?: string | null;\n}\n\n/** A public key this build of the SDK will accept signatures from. */\nexport interface TrustedKey {\n /** Matches `keyId` in the payload. */\n keyId: string;\n /** The raw 32-byte Ed25519 public key, base64url or base64. */\n publicKey: string;\n /** Free text for the key's provenance. Never displayed to end users. */\n note?: string;\n}\n","/**\n * Offline licence verification.\n *\n * Everything here is local: a signature check against a compiled-in public key\n * and a comparison against the clock. There is no activation call, no licence\n * server and nothing to be offline from. That is a deliberate product decision\n * as much as a technical one — a report renderer that stops working because a\n * key server is down is a report renderer nobody puts in a payroll run.\n *\n * The failure modes are all *soft*. An unreadable licence never throws out of a\n * render; it produces a status whose `message` says what is wrong, and the PDF\n * comes out carrying the evaluation mark.\n */\nimport { verifyAsync } from \"@noble/ed25519\";\nimport { base64UrlToBytes, utf8ToBytes } from \"./encoding.js\";\nimport { LicenseFormatError, parseLicense } from \"./format.js\";\nimport { TRUSTED_KEYS } from \"./trusted-keys.js\";\nimport { EVALUATION_PLAN, PRODUCT, type LicensePayload, type LicenseStatus, type TrustedKey } from \"./types.js\";\n\n/**\n * How long an expired licence keeps working.\n *\n * A renewal that is a week late is an accounts payable problem, not a reason to\n * stamp a customer's month-end reports. Thirty days is long enough to cover a\n * card expiring over a holiday and short enough that it is not a second licence\n * term.\n */\nexport const DEFAULT_GRACE_PERIOD_DAYS = 30;\n\n/** Where a developer gets a free evaluation key. Printed, never fetched. */\nexport const EVALUATION_KEY_URL = \"https://www.broadpaper.com/eval\";\n\nconst DAY_MS = 86_400_000;\n\nexport interface VerifyOptions {\n /** Fixed clock. Tests and deterministic renders pass one. */\n now?: Date;\n /** Extra keys to trust, on top of the ones built into this SDK. */\n trustedKeys?: readonly TrustedKey[];\n /**\n * Overrides {@link DEFAULT_GRACE_PERIOD_DAYS}. Never applies to an evaluation\n * licence, which has no grace period whatever a host configures.\n */\n gracePeriodDays?: number;\n}\n\n/** The status of a caller that supplied no licence at all. */\nexport function unlicensed(): LicenseStatus {\n return {\n state: \"unlicensed\",\n licensed: false,\n payload: null,\n plan: null,\n validUntil: null,\n daysRemaining: null,\n message: `BroadPaper is running in evaluation mode. Get a free evaluation key: ${EVALUATION_KEY_URL}`\n };\n}\n\nfunction failure(state: LicenseStatus[\"state\"], message: string, payload: LicensePayload | null = null): LicenseStatus {\n return {\n state,\n licensed: false,\n payload,\n plan: null,\n validUntil: payload?.validUntil != null ? new Date(payload.validUntil * 1000) : null,\n daysRemaining: null,\n message\n };\n}\n\n/**\n * Checks a licence string and reports what it entitles the caller to.\n *\n * Never throws for a bad licence: a malformed string, a forged signature and an\n * expired term are all ordinary answers, and a render is not the place to\n * discover that a config file has a typo in it.\n */\nexport async function verifyLicense(license: string | null | undefined, options: VerifyOptions = {}): Promise<LicenseStatus> {\n if (!license || !license.trim()) return unlicensed();\n\n let parsed;\n try {\n parsed = parseLicense(license);\n } catch (e) {\n if (e instanceof LicenseFormatError) {\n return failure(\n e.kind,\n e.kind === \"unsupported\"\n ? `This BroadPaper licence needs a newer version of the SDK (${e.message}). Update @broadpaper/* or the PDF will carry the evaluation watermark.`\n : `The BroadPaper licence could not be read (${e.message}), so PDFs carry the evaluation watermark.`\n );\n }\n /* c8 ignore next -- parseLicense only throws LicenseFormatError */\n throw e;\n }\n\n const { payload } = parsed;\n if (payload.product !== PRODUCT) {\n return failure(\n \"invalid\",\n `This licence is for ${JSON.stringify(payload.product)}, not the BroadPaper SDK, so PDFs carry the evaluation watermark.`,\n payload\n );\n }\n\n const key = findKey(payload.keyId, options.trustedKeys);\n if (!key) {\n return failure(\n \"untrusted\",\n `This BroadPaper licence was signed with key ${JSON.stringify(payload.keyId)}, which this build does not trust. ` +\n \"A licence issued for development is not honoured by a production build; check BROADPAPER_LICENSE points at the right one.\",\n payload\n );\n }\n\n let signatureOk = false;\n try {\n signatureOk = await verifyAsync(parsed.signature, utf8ToBytes(parsed.signedText), base64UrlToBytes(key.publicKey));\n } catch {\n // A malformed public key or a point that is not on the curve. Either way\n // this licence is not going to verify, and a render must not fail over it.\n signatureOk = false;\n }\n if (!signatureOk) {\n return failure(\"invalid\", \"This BroadPaper licence failed its signature check — it has been altered or truncated. PDFs carry the evaluation watermark.\", payload);\n }\n\n const now = options.now ?? new Date();\n\n // A licence with no end date never expires, so there is no clock to consult.\n // Nothing sold today issues one — `readPayload` refuses the only licence type\n // that would — but the field is nullable, and a null that fell through to the\n // arithmetic below would come out as 1970 and watermark a valid licence.\n if (payload.validUntil === null) {\n return { state: \"active\", licensed: true, payload, plan: payload.plan, validUntil: null, daysRemaining: null, message: null };\n }\n\n const validUntil = new Date(payload.validUntil * 1000);\n const evaluation = payload.plan === EVALUATION_PLAN;\n // An evaluation licence ends on its date. Paid licences get thirty days\n // because a late renewal is an accounts-payable problem; a free key has no\n // renewal to be late with, and the way to get more time is to ask for it.\n const graceDays = evaluation ? 0 : options.gracePeriodDays ?? DEFAULT_GRACE_PERIOD_DAYS;\n const day = validUntil.toISOString().slice(0, 10);\n const msRemaining = validUntil.getTime() - now.getTime();\n const daysRemaining = Math.floor(msRemaining / DAY_MS);\n\n if (msRemaining > 0) {\n return {\n state: \"active\",\n licensed: true,\n payload,\n plan: payload.plan,\n validUntil,\n daysRemaining,\n message: null,\n notice: evaluation\n ? `BroadPaper is running on an evaluation licence for ${payload.organisationName}, which ends on ${day}. ` +\n \"It is for evaluation and development, not production use.\"\n : null\n };\n }\n\n if (evaluation) {\n return failure(\n \"expired\",\n `The BroadPaper evaluation licence for ${payload.organisationName} ended on ${day}, so PDFs carry the evaluation watermark again. ` +\n \"Need longer? Reply to your licence email or write to hello@broadpaper.com.\",\n payload\n );\n }\n\n if (msRemaining > -graceDays * DAY_MS) {\n const daysOver = Math.max(1, Math.ceil(-msRemaining / DAY_MS));\n return {\n state: \"grace\",\n licensed: true,\n payload,\n plan: payload.plan,\n validUntil,\n daysRemaining,\n message:\n `The BroadPaper licence for ${payload.organisationName} expired ${daysOver} day${daysOver === 1 ? \"\" : \"s\"} ago and is inside its ${graceDays}-day grace period. ` +\n \"Renew it and copy the new licence from your account, or PDFs will start carrying the evaluation watermark.\"\n };\n }\n\n return failure(\n \"expired\",\n `The BroadPaper licence for ${payload.organisationName} expired on ${day} and its ${graceDays}-day grace period has passed, ` +\n \"so PDFs carry the evaluation watermark. Renewing issues a new licence in your BroadPaper account.\",\n payload\n );\n}\n\nfunction findKey(keyId: string, extra: readonly TrustedKey[] | undefined): TrustedKey | undefined {\n // Runtime keys are searched first so a development key can shadow a built-in\n // one of the same name without a rebuild.\n return extra?.find((k) => k.keyId === keyId) ?? TRUSTED_KEYS.find((k) => k.keyId === keyId);\n}\n","/**\n * Configuring BroadPaper once, for the life of the process.\n *\n * import { BroadPaper } from \"@broadpaper/forme\";\n * BroadPaper.configure({ license: process.env.BROADPAPER_LICENSE });\n *\n * The licence is not a credential, so this is not a secrets API: it is the same\n * shape of thing as setting a locale. A browser bundle that carries the licence\n * string in plain text is fine — the string is a signed certificate, and\n * possessing it grants nothing beyond what its payload already says.\n *\n * Configuration is deliberately process-global rather than an argument to every\n * render. Threading a licence through `renderPdf`, the render service, the\n * batch endpoint, the .NET client and every future export path is exactly the\n * kind of plumbing that ends with one path quietly forgetting it, and a\n * customer who has paid discovering a watermark in production.\n *\n * The store hangs off a `Symbol.for` key rather than a module-level variable so\n * that two copies of this package in one dependency tree — the usual result of\n * a mixed-version install — still agree about the licence.\n */\nimport { unlicensed, verifyLicense, type VerifyOptions } from \"./verify.js\";\nimport type { LicenseStatus, TrustedKey } from \"./types.js\";\n\nexport interface BroadPaperConfig {\n /**\n * The licence string, `BP1.…`. Read from `BROADPAPER_LICENSE` when this is\n * not set and the runtime has environment variables.\n */\n license?: string | null;\n /**\n * Public keys to trust in addition to the ones built into the SDK. This is\n * how a development licence is honoured on a developer's machine without a\n * development key ever being trusted by a production build.\n */\n trustedKeys?: readonly TrustedKey[];\n /** Overrides the 30-day post-expiry grace period. Mostly for tests. */\n gracePeriodDays?: number;\n /**\n * Where licence messages go. Defaults to `console.warn` for warnings and\n * `console.info` for information; `null` silences both. The level is a\n * second argument so a logger written for earlier versions still works.\n */\n logger?: ((message: string, level: LogLevel) => void) | null;\n}\n\n/** How loudly a licence message is said. */\nexport type LogLevel = \"info\" | \"warn\";\n\ninterface Store {\n config: BroadPaperConfig;\n /** Memoised by the licence string that produced it. */\n cache: { key: string; status: Promise<LicenseStatus> } | null;\n /** Messages already logged, so a hundred renders do not print a hundred lines. */\n logged: Set<string>;\n}\n\nconst STORE_KEY = Symbol.for(\"broadpaper.license.store\");\n\nfunction store(): Store {\n const g = globalThis as Record<symbol, unknown>;\n let s = g[STORE_KEY] as Store | undefined;\n if (!s) {\n s = { config: {}, cache: null, logged: new Set() };\n g[STORE_KEY] = s;\n }\n return s;\n}\n\n/**\n * Sets the licence and any other SDK-wide options. Call it once, at startup.\n *\n * Successive calls merge, so a host can set the licence in one place and the\n * grace period in another; passing `license: null` clears it.\n */\nexport function configure(config: BroadPaperConfig): void {\n const s = store();\n s.config = { ...s.config, ...config };\n s.cache = null;\n s.logged.clear();\n}\n\n/** What {@link configure} has been given, plus whatever the environment supplies. */\nexport function getConfig(): BroadPaperConfig {\n return { ...store().config };\n}\n\n/** Forgets the configuration entirely. Exists for tests. */\nexport function resetConfig(): void {\n const g = globalThis as Record<symbol, unknown>;\n delete g[STORE_KEY];\n}\n\n/**\n * `BroadPaper.configure({ … })`, for hosts that prefer a namespace to a bare\n * function. Both are the same store.\n */\nexport const BroadPaper = { configure, getConfig };\n\nfunction env(name: string): string | undefined {\n // Node, Deno and bundlers that inline `process.env` all satisfy this; a\n // browser without a shim simply has no environment, which is not an error.\n const p = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\n const value = p?.env?.[name];\n return value && value.trim() ? value : undefined;\n}\n\n/**\n * Keys trusted in addition to the built-in ones, from configuration and from\n * `BROADPAPER_TRUSTED_KEYS` — a JSON array of `{ keyId, publicKey }`.\n *\n * A syntax error there is reported rather than swallowed: someone setting that\n * variable is doing so on purpose, and silently ignoring it would present as\n * \"my development licence is not being honoured\" with nothing to go on.\n */\nfunction trustedKeysFromEnv(): readonly TrustedKey[] {\n const raw = env(\"BROADPAPER_TRUSTED_KEYS\");\n if (!raw) return [];\n try {\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) throw new Error(\"expected a JSON array\");\n return parsed.map((entry, i) => {\n const k = entry as Record<string, unknown>;\n if (typeof k?.keyId !== \"string\" || typeof k?.publicKey !== \"string\") throw new Error(`entry ${i} needs keyId and publicKey`);\n return { keyId: k.keyId, publicKey: k.publicKey };\n });\n } catch (e) {\n warn(`BROADPAPER_TRUSTED_KEYS could not be read (${(e as Error).message}); it is being ignored.`);\n return [];\n }\n}\n\n/** Logs a message once, whatever it takes to reach the developer. */\nexport function warn(message: string): void {\n log(message, \"warn\");\n}\n\n/** Logs an informational message once. */\nexport function info(message: string): void {\n log(message, \"info\");\n}\n\nfunction log(message: string, level: LogLevel): void {\n const s = store();\n if (s.logged.has(message)) return;\n s.logged.add(message);\n const logger = s.config.logger;\n if (logger === null) return;\n const line = `[BroadPaper] ${message}`;\n if (logger) logger(line, level);\n else if (level === \"info\") console.info(line);\n else console.warn(line);\n}\n\nfunction report(status: LicenseStatus): void {\n if (status.message) warn(status.message);\n if (status.notice) info(status.notice);\n}\n\nexport interface ResolveOptions extends VerifyOptions {\n /** A licence for this call only, overriding the configured one. */\n license?: string | null;\n}\n\n/**\n * The licence status for the current configuration.\n *\n * Memoised on the licence string, because every PDF asks and a signature check\n * per page of a five-hundred-page batch is waste. `configure` clears it, and a\n * per-call `license` bypasses it.\n *\n * Whatever the answer, any developer-facing message is logged once. That is the\n * only thing the SDK does that a caller did not ask for, and it is the\n * difference between a developer seeing \"your licence expired\" and a developer\n * seeing an unexplained watermark.\n */\nexport async function resolveLicenseStatus(options: ResolveOptions = {}): Promise<LicenseStatus> {\n const s = store();\n const config = s.config;\n const license = options.license !== undefined ? options.license : config.license ?? env(\"BROADPAPER_LICENSE\") ?? null;\n const trustedKeys = [...(options.trustedKeys ?? []), ...(config.trustedKeys ?? []), ...trustedKeysFromEnv()];\n const gracePeriodDays = options.gracePeriodDays ?? config.gracePeriodDays;\n\n if (!license) {\n const status = unlicensed();\n report(status);\n return status;\n }\n\n const verify = (): Promise<LicenseStatus> =>\n verifyLicense(license, { ...(options.now ? { now: options.now } : {}), trustedKeys, ...(gracePeriodDays !== undefined ? { gracePeriodDays } : {}) }).then((status) => {\n report(status);\n return status;\n });\n\n // A fixed clock is a test or a deterministic render; caching across different\n // clocks would make the grace-period boundary depend on call order.\n if (options.now || options.license !== undefined) return verify();\n\n const key = `${license}|${trustedKeys.map((k) => k.keyId).join(\",\")}|${gracePeriodDays ?? \"\"}`;\n if (s.cache?.key !== key) s.cache = { key, status: verify() };\n return s.cache.status;\n}\n","/**\n * The evaluation mark.\n *\n * This is the only thing an unlicensed BroadPaper does differently. Every\n * block, both PDF backends, the designer, data binding, pagination and the\n * render service behave identically with and without a licence; what changes is\n * that the file says, on every page, that it was produced with an evaluation\n * copy.\n *\n * It is drawn to be unmistakable in a document review and harmless to a\n * developer evaluating the product: a light diagonal line across the page,\n * behind nothing and over everything, at an opacity that leaves the report\n * entirely readable. Making the output illegible would only push people towards\n * evaluating something else.\n *\n * Each backend draws the spec with its own primitives — the Forme engine has a\n * page-native watermark node, Chromium gets a printed overlay — because a\n * single drawing implementation would mean one of them post-processing a file\n * the other had already finished, and a stamping pass that can be skipped is a\n * stamping pass that eventually is.\n */\nimport { resolveLicenseStatus, type ResolveOptions } from \"./config.js\";\nimport type { LicenseStatus } from \"./types.js\";\n\nexport interface WatermarkSpec {\n text: string;\n /** Points. The engines size the mark from this, not from the page. */\n fontSize: number;\n /** Degrees, anticlockwise from horizontal. */\n angle: number;\n /** Hex, without alpha. */\n color: string;\n /** 0–1. */\n opacity: number;\n /**\n * Where on the page it goes.\n *\n * `center` is the evaluation mark's diagonal stamp: sized from `fontSize`,\n * rotated by `angle`, across the middle of every page. It is the default and\n * the only thing `watermarkFor` ever asks for.\n *\n * `bottom` is a credit line along the foot of the page, in the bottom margin —\n * the shape a host's own commercial model usually wants. BroadPaper Cloud's\n * free plan started as a `center` mark at eight points, which is a small grey\n * sentence floating in the middle of an otherwise finished invoice: it reads\n * as a mistake rather than as a credit, and the whole point of that mark is\n * that a free user's document stays sendable.\n *\n * It is drawn in the margin rather than in the footer band deliberately, so it\n * costs no layout: a mark that changed the content height would make the\n * finished file paginate differently from the canvas the user approved.\n */\n placement?: \"center\" | \"bottom\";\n /**\n * A small mark drawn before the text, as an `image/svg+xml` data URI. `bottom`\n * only.\n *\n * Vector rather than a bitmap because it is drawn at about nine points and a\n * raster at that size is a smudge. Both backends parse the URI themselves —\n * the Forme engine's image decoder cannot read an SVG, so it is re-emitted as\n * the drawing it is.\n */\n mark?: string;\n /**\n * Where the text links to, making it a link in the file. `bottom` only, and\n * the Forme backend only — the Chromium backend stamps text into a finished\n * file and draws it unlinked.\n *\n * For a host's own credit line, whose job is to be followed: a free document a\n * business sends a client is the most-read advert the host will ever have, and\n * an address nobody can click is one hardly anybody types. The evaluation\n * stamp never has one, because it is there to be seen, not visited; its\n * footnote does, because saying where to get a key is the footnote's whole job.\n */\n href?: string;\n /**\n * A second mark drawn with this one: a `bottom` line under a `center` stamp.\n *\n * The evaluation mark carries one that says how to remove it. It is a field\n * of the spec rather than a second return value of `watermarkFor` so that\n * everything already passing one spec around — Cloud, a host's own extra mark,\n * both backends — carries it without learning a new shape. Backends reach it\n * through {@link expandWatermarks}.\n */\n footnote?: WatermarkSpec;\n}\n\n/**\n * The marks to draw, with each spec's `footnote` beside it and the empty\n * slots dropped. What every backend iterates.\n */\nexport function expandWatermarks(marks: ReadonlyArray<WatermarkSpec | null | undefined>): WatermarkSpec[] {\n const out: WatermarkSpec[] = [];\n for (const mark of marks) {\n if (!mark) continue;\n out.push(mark);\n if (mark.footnote) out.push(mark.footnote);\n }\n return out;\n}\n\n/**\n * The mark itself.\n *\n * No dashes or typographic punctuation: the standard PDF faces carry no em\n * dash, and a theme that names a font the engine does not have falls back to\n * them, which turned \"BroadPaper — Evaluation Copy\" into \"BroadPaper\n * Evaluation Copy\" in half the documents and a question mark in the rest.\n */\nexport const EVALUATION_WATERMARK: WatermarkSpec = {\n text: \"BroadPaper Evaluation Copy\",\n fontSize: 44,\n angle: -35,\n color: \"#c8102e\",\n opacity: 0.12,\n /*\n * The line that says what to do about the stamp. The stamp itself is never a\n * link — it is there to be seen. This line is the opposite: it exists to be\n * followed, so the Forme backend links it; Chromium stamps text into a finished\n * file and draws it unlinked. Darker than the stamp because at eight points\n * the stamp's opacity is unreadable, and still grey enough to leave the page\n * a page. A full stop rather than a dash, for the reason above.\n */\n footnote: {\n text: \"Evaluation copy. Remove this mark with a free key: broadpaper.com/eval\",\n fontSize: 8,\n angle: 0,\n color: \"#6b6b6b\",\n opacity: 0.9,\n placement: \"bottom\",\n href: \"https://www.broadpaper.com/eval\"\n }\n};\n\n/**\n * The mark a render should carry, or null when the licence says none.\n *\n * Backends call this rather than reading the licence status themselves, so\n * \"licensed\" and \"no watermark\" cannot drift apart.\n */\nexport async function resolveWatermark(options: ResolveOptions = {}): Promise<WatermarkSpec | null> {\n const status = await resolveLicenseStatus(options);\n return watermarkFor(status);\n}\n\n/** The pure half of {@link resolveWatermark}, for callers that already have a status. */\nexport function watermarkFor(status: LicenseStatus): WatermarkSpec | null {\n return status.licensed ? null : EVALUATION_WATERMARK;\n}\n\n/**\n * CSS that paints the mark on every `.bp-page` of a rendered document.\n *\n * Used by the Chromium backend and by the designer's print path — the two\n * places a PDF is produced by a browser rather than by the engine. `position:\n * fixed` would put it on the viewport rather than on each page, so it is an\n * absolutely positioned pseudo-element on the page box, which prints once per\n * sheet.\n *\n * `print-color-adjust` matters: without it Chromium drops the mark from the\n * printed file exactly as it drops any other background colour.\n */\nexport function watermarkCss(spec: WatermarkSpec = EVALUATION_WATERMARK): string {\n const note = spec.footnote;\n return [\n \".bp-page{position:relative;}\",\n \".bp-page::after{\",\n `content:\"${cssString(spec.text)}\";`,\n \"position:absolute;inset:0;\",\n \"display:flex;align-items:center;justify-content:center;\",\n \"pointer-events:none;z-index:2147483647;\",\n `transform:rotate(${spec.angle}deg);`,\n \"font-family:Helvetica,Arial,sans-serif;font-weight:700;letter-spacing:0.04em;white-space:nowrap;\",\n `font-size:${spec.fontSize}pt;color:${spec.color};opacity:${spec.opacity};`,\n \"-webkit-print-color-adjust:exact;print-color-adjust:exact;\",\n \"}\",\n // The footnote, along the foot of the same page box. Unlinked here: a\n // pseudo-element cannot be an anchor.\n ...(note\n ? [\n \".bp-page::before{\",\n `content:\"${cssString(note.text)}\";`,\n \"position:absolute;left:0;right:0;bottom:4pt;text-align:center;\",\n \"pointer-events:none;z-index:2147483647;\",\n \"font-family:Helvetica,Arial,sans-serif;white-space:nowrap;\",\n `font-size:${note.fontSize}pt;color:${note.color};opacity:${note.opacity};`,\n \"-webkit-print-color-adjust:exact;print-color-adjust:exact;\",\n \"}\"\n ]\n : [])\n ].join(\"\");\n}\n\nfunction cssString(text: string): string {\n return text.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n}\n\n/**\n * The PDF Producer string for a render.\n *\n * Licensed output records the licence id. It is not a secret — it identifies a\n * customer's licence, not their account — and having it in the file means a\n * document that turns up somewhere it should not can be traced back to the\n * licence that produced it without any of the tracking a phone-home would need.\n */\nexport function producerString(status: LicenseStatus): string {\n if (!status.licensed || !status.payload) return \"BroadPaper (evaluation)\";\n return `BroadPaper (${status.payload.licenseId})`;\n}\n","import { lookup } from \"node:dns/promises\";\nimport { isIP } from \"node:net\";\n\nexport interface NetworkPolicy {\n /**\n * Hostnames (or `*.example.com` wildcards, or `*`) the renderer may fetch\n * assets from. `data:` URLs are always allowed. Default: none.\n */\n allowedHosts?: string[];\n /** Block private / loopback / link-local address ranges even for allowed hosts. Default true. */\n blockPrivateNetworks?: boolean;\n /** Maximum number of network requests per render. Default 200. */\n maxRequests?: number;\n}\n\nconst PRIVATE_V4 = [\n [/^10\\./, \"10/8\"],\n [/^127\\./, \"loopback\"],\n [/^169\\.254\\./, \"link-local\"],\n [/^172\\.(1[6-9]|2\\d|3[01])\\./, \"172.16/12\"],\n [/^192\\.168\\./, \"192.168/16\"],\n [/^0\\./, \"0/8\"],\n [/^100\\.(6[4-9]|[7-9]\\d|1[01]\\d|12[0-7])\\./, \"CGNAT\"]\n] as const;\n\nexport function isPrivateAddress(ip: string): boolean {\n const kind = isIP(ip);\n if (kind === 4) return PRIVATE_V4.some(([re]) => re.test(ip));\n if (kind === 6) {\n const lower = ip.toLowerCase();\n if (lower === \"::1\" || lower === \"::\") return true;\n if (lower.startsWith(\"fe80:\") || lower.startsWith(\"fc\") || lower.startsWith(\"fd\")) return true;\n const mapped = /^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/.exec(lower);\n if (mapped) return isPrivateAddress(mapped[1]!);\n return false;\n }\n return false;\n}\n\nexport function hostAllowed(host: string, allowed: string[] | undefined): boolean {\n if (!allowed || allowed.length === 0) return false;\n const h = host.toLowerCase();\n return allowed.some((pattern) => {\n const p = pattern.toLowerCase();\n if (p === \"*\") return true;\n if (p.startsWith(\"*.\")) return h === p.slice(2) || h.endsWith(p.slice(1));\n return h === p;\n });\n}\n\nexport interface RequestDecision {\n allow: boolean;\n reason?: string;\n}\n\n/**\n * Decides whether the headless browser may perform a request. Resolves DNS so\n * that a public hostname pointing at a private address is still blocked.\n */\nexport async function decideRequest(url: string, policy: NetworkPolicy, counter: { count: number }): Promise<RequestDecision> {\n if (url.startsWith(\"data:\") || url === \"about:blank\") return { allow: true };\n let u: URL;\n try {\n u = new URL(url);\n } catch {\n return { allow: false, reason: \"invalid URL\" };\n }\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") return { allow: false, reason: `scheme ${u.protocol} not allowed` };\n if (++counter.count > (policy.maxRequests ?? 200)) return { allow: false, reason: \"request limit exceeded\" };\n if (!hostAllowed(u.hostname, policy.allowedHosts)) return { allow: false, reason: `host ${u.hostname} not in allow-list` };\n if (policy.blockPrivateNetworks !== false) {\n const host = u.hostname.replace(/^\\[|\\]$/g, \"\");\n if (host === \"localhost\" || host.endsWith(\".localhost\") || host.endsWith(\".internal\")) return { allow: false, reason: \"private host\" };\n if (isIP(host)) {\n if (isPrivateAddress(host)) return { allow: false, reason: \"private address\" };\n } else {\n try {\n const results = await lookup(host, { all: true });\n if (results.some((r) => isPrivateAddress(r.address))) return { allow: false, reason: \"resolves to a private address\" };\n } catch {\n return { allow: false, reason: \"DNS lookup failed\" };\n }\n }\n }\n return { allow: true };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport type { Browser, BrowserContext } from \"playwright-core\";\nimport type { DataSource, ReportData, ReportTemplate, Theme } from \"@broadpaper/core\";\nimport { expandWatermarks, producerString, resolveLicenseStatus, watermarkFor, type LicenseStatus, type WatermarkSpec } from \"@broadpaper/license\";\nimport { decideRequest, type NetworkPolicy } from \"./ssrf.js\";\nimport { stampWatermark } from \"./watermark.js\";\nimport type { RuntimeRenderOutput } from \"../runtime/index.js\";\n\nexport interface PdfMetadata {\n title?: string;\n author?: string;\n subject?: string;\n keywords?: string[];\n /** Creation date. Defaults to `now`. */\n creationDate?: Date;\n}\n\nexport interface RenderPdfOptions {\n template: ReportTemplate | { schemaVersion: number; [k: string]: unknown };\n data?: ReportData;\n theme?: Partial<Theme>;\n dataSources?: DataSource[];\n /** Fixed clock for deterministic output. */\n now?: Date;\n locale?: string;\n currency?: string;\n timeZone?: string;\n metadata?: PdfMetadata;\n /**\n * JavaScript source for a browser bundle that registers custom blocks:\n * it must call `BroadPaper.registerBlocks([...])`. Built by the host with its\n * own bundler from `@broadpaper/core` block definitions.\n */\n customBlocksScript?: string;\n network?: NetworkPolicy;\n /** Per-render timeout in ms. Default 60000. */\n timeoutMs?: number;\n /** Refuse documents longer than this. Default 500. */\n maxPages?: number;\n /** Chromium tagged (accessible) PDF. Default true. */\n tagged?: boolean;\n /** PDF/A-like outline generation from headings. Default true. */\n outline?: boolean;\n /** Attach the runtime from a custom path (testing). */\n runtimePath?: string;\n /**\n * An extra mark stamped on every page, on top of whatever the licence decides.\n *\n * Additive and never a replacement, exactly as in the browserless backend: the\n * licence mark is `watermarkFor`'s to decide and a caller cannot remove it.\n * Both backends take this so that switching backend cannot quietly drop a\n * host's own mark — which, for a free tier that depends on it, would be the\n * expensive kind of silence.\n */\n watermark?: WatermarkSpec | null;\n /**\n * A licence for this render only, overriding whatever `configure` was given.\n * A service rendering for one organisation should configure once at startup\n * instead; this is for a host that renders on behalf of several.\n */\n license?: string | null;\n}\n\nexport interface RenderPdfResult {\n pdf: Buffer;\n pages: number;\n warnings: RuntimeRenderOutput[\"warnings\"];\n /** Wall-clock render time in ms. */\n durationMs: number;\n}\n\nexport class PdfRenderError extends Error {\n constructor(\n message: string,\n public readonly code: \"TIMEOUT\" | \"TOO_MANY_PAGES\" | \"RUNTIME\" | \"BROWSER\"\n ) {\n super(message);\n this.name = \"PdfRenderError\";\n }\n}\n\nlet runtimeCache: string | null = null;\n\nasync function loadRuntime(path?: string): Promise<string> {\n if (path) return readFile(path, \"utf8\");\n if (runtimeCache) return runtimeCache;\n const here = dirname(fileURLToPath(import.meta.url));\n const candidates = [join(here, \"runtime.global.js\"), join(here, \"..\", \"dist\", \"runtime.global.js\")];\n for (const c of candidates) {\n try {\n runtimeCache = await readFile(c, \"utf8\");\n return runtimeCache;\n } catch {\n /* try next */\n }\n }\n throw new PdfRenderError(\"BroadPaper runtime bundle not found. Run `pnpm --filter @broadpaper/pdf build`.\", \"RUNTIME\");\n}\n\nconst BLANK_HTML = `<!doctype html><html><head><meta charset=\"utf-8\"><title>BroadPaper</title></head><body></body></html>`;\n\n/**\n * A reusable PDF renderer bound to a Playwright browser. Each render uses a\n * fresh, isolated browser context (no cookies, storage or cache shared between\n * documents) and a strict network policy.\n */\nexport class PdfRenderer {\n constructor(private readonly browser: Browser) {}\n\n async render(opts: RenderPdfOptions): Promise<RenderPdfResult> {\n const started = Date.now();\n const timeout = opts.timeoutMs ?? 60_000;\n const runtime = await loadRuntime(opts.runtimePath);\n let context: BrowserContext | null = null;\n try {\n 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 });\n context.setDefaultTimeout(timeout);\n const counter = { count: 0 };\n const policy: NetworkPolicy = { allowedHosts: [], blockPrivateNetworks: true, maxRequests: 200, ...(opts.network ?? {}) };\n await context.route(\"**/*\", async (route) => {\n const url = route.request().url();\n const decision = await decideRequest(url, policy, counter);\n if (decision.allow) await route.continue();\n else await route.abort(\"blockedbyclient\");\n });\n\n const page = await context.newPage();\n const errors: string[] = [];\n page.on(\"pageerror\", (e) => errors.push(String(e)));\n await page.setContent(BLANK_HTML, { waitUntil: \"load\" });\n await page.addScriptTag({ content: runtime });\n if (opts.customBlocksScript) await page.addScriptTag({ content: opts.customBlocksScript });\n\n const input = {\n template: opts.template,\n data: opts.data ?? {},\n theme: opts.theme,\n dataSources: opts.dataSources ?? [],\n now: (opts.now ?? new Date()).toISOString(),\n locale: opts.locale,\n currency: opts.currency,\n timeZone: opts.timeZone,\n mode: \"preview\" as const\n };\n\n const result = (await Promise.race([\n page.evaluate(async (i) => window.BroadPaper.render(i as never), input),\n new Promise<never>((_, reject) => setTimeout(() => reject(new PdfRenderError(`Render timed out after ${timeout}ms`, \"TIMEOUT\")), timeout))\n ])) as RuntimeRenderOutput;\n\n if (errors.length) throw new PdfRenderError(`Runtime error: ${errors[0]}`, \"RUNTIME\");\n const maxPages = opts.maxPages ?? 500;\n if (result.pages > maxPages) throw new PdfRenderError(`Document has ${result.pages} pages, more than the limit of ${maxPages}`, \"TOO_MANY_PAGES\");\n\n await page.emulateMedia({ media: \"print\" });\n const pdf = await page.pdf({\n width: `${result.width}px`,\n height: `${result.height}px`,\n printBackground: true,\n preferCSSPageSize: true,\n margin: { top: 0, right: 0, bottom: 0, left: 0 },\n displayHeaderFooter: false,\n tagged: opts.tagged ?? true,\n outline: opts.outline ?? true\n });\n\n // The licence is checked here, on the way out, rather than inside the\n // page: nothing a host injects into the browser — a custom-blocks bundle,\n // its own runtime, its own CSS — sits between this and the file.\n const license = await resolveLicenseStatus(opts.license !== undefined ? { license: opts.license } : {});\n const finished = await applyMetadata(pdf, opts.metadata, opts.now, license, opts.watermark);\n return { pdf: finished, pages: result.pages, warnings: result.warnings, durationMs: Date.now() - started };\n } catch (e) {\n if (e instanceof PdfRenderError) throw e;\n throw new PdfRenderError(`Browser failure: ${(e as Error).message}`, \"BROWSER\");\n } finally {\n await context?.close().catch(() => undefined);\n }\n }\n}\n\n/**\n * Writes document metadata (Title, Author, Subject, Keywords, Producer, dates)\n * into the PDF using pdf-lib, and stamps the evaluation mark when the licence\n * calls for one. With a fixed `now` the output is byte-stable.\n *\n * The two jobs are together because this is the last time the file is open:\n * every Chromium render ends here, so a PDF that leaves this function clean was\n * produced under a licence that says it may be.\n *\n * `license` is resolved from the configured licence when it is not supplied,\n * which keeps the guarantee for a caller reaching this function directly.\n */\nexport async function applyMetadata(pdf: Buffer, meta: PdfMetadata | undefined, now?: Date, license?: LicenseStatus, extraWatermark?: WatermarkSpec | null): Promise<Buffer> {\n const { PDFDocument } = await import(\"pdf-lib\");\n const status = license ?? (await resolveLicenseStatus());\n const doc = await PDFDocument.load(pdf, { updateMetadata: false });\n const when = meta?.creationDate ?? now ?? new Date();\n // The licence mark first, then the caller's. Both are stamped; neither\n // cancels the other.\n for (const mark of expandWatermarks([watermarkFor(status), extraWatermark])) await stampWatermark(doc, mark);\n doc.setProducer(producerString(status));\n doc.setCreator(\"BroadPaper\");\n doc.setCreationDate(when);\n doc.setModificationDate(when);\n if (meta?.title) doc.setTitle(meta.title, { showInWindowTitleBar: true });\n if (meta?.author) doc.setAuthor(meta.author);\n if (meta?.subject) doc.setSubject(meta.subject);\n if (meta?.keywords?.length) doc.setKeywords(meta.keywords);\n const bytes = await doc.save({ useObjectStreams: true, addDefaultPage: false });\n return Buffer.from(bytes);\n}\n\nexport interface BrowserFactory {\n launch(): Promise<Browser>;\n}\n\n/**\n * Convenience: renders one PDF with a temporary browser. For servers use\n * `PdfRenderer` with a long-lived browser instead.\n */\nexport async function renderPdf(opts: RenderPdfOptions & { browser?: Browser; launch?: () => Promise<Browser> }): Promise<RenderPdfResult> {\n let browser = opts.browser;\n let own = false;\n if (!browser) {\n const launch = opts.launch ?? defaultLaunch;\n browser = await launch();\n own = true;\n }\n try {\n return await new PdfRenderer(browser).render(opts);\n } finally {\n if (own) await browser.close().catch(() => undefined);\n }\n}\n\nexport async function defaultLaunch(): Promise<Browser> {\n // Playwright is an optional peer dependency: this package is the fidelity\n // reference rather than the recommended backend, and most hosts render with\n // Forme and never launch a browser at all. Neither driver being installed is\n // therefore an ordinary configuration and not a broken install, so it has to\n // say so — the bare module resolution error names a package the host never\n // knowingly asked for.\n let mod: typeof import(\"playwright-core\");\n try {\n mod = (await import(\"playwright\").catch(() => import(\"playwright-core\"))) as typeof import(\"playwright-core\");\n } catch {\n throw new PdfRenderError(\n \"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.\",\n \"BROWSER\"\n );\n }\n return mod.chromium.launch({ headless: true, args: [\"--disable-gpu\", \"--font-render-hinting=none\", \"--disable-dev-shm-usage\"] });\n}\n","/**\n * The evaluation mark, drawn into a finished PDF.\n *\n * The browserless backend hands the engine a watermark node and lets it draw;\n * Chromium has no such notion, so the mark goes on afterwards, into the file.\n * That is deliberately the *last* thing that happens to a PDF here rather than\n * a stylesheet injected into the page: a host supplying its own custom-blocks\n * bundle, its own CSS or its own runtime can change what the page looks like,\n * and none of it can change what comes out of this function.\n *\n * One line per page, centred, rotated, at the same colour and opacity the\n * engine uses, so an evaluation PDF looks the same whichever backend produced\n * it.\n */\nimport type { PDFDocument } from \"pdf-lib\";\nimport type { WatermarkSpec } from \"@broadpaper/license\";\n\nexport async function stampWatermark(doc: PDFDocument, spec: WatermarkSpec): Promise<void> {\n const { StandardFonts, degrees, rgb } = await import(\"pdf-lib\");\n // Helvetica-Bold is one of the fourteen faces every PDF reader has, so the\n // mark needs no embedded font and adds nothing to the file size.\n const font = await doc.embedFont((spec.placement ?? \"center\") === \"bottom\" ? StandardFonts.Helvetica : StandardFonts.HelveticaBold);\n const color = hexToRgb(spec.color);\n const radians = (spec.angle * Math.PI) / 180;\n const width = font.widthOfTextAtSize(spec.text, spec.fontSize);\n const height = font.heightAtSize(spec.fontSize);\n\n /*\n * A credit line along the foot of the page.\n *\n * Centred horizontally, sitting a little above the page edge, unrotated\n * whatever `angle` says — a rotated line at eight points is a smudge, and this\n * placement exists precisely so a host's own mark can leave a document\n * sendable. The other backend draws it in the bottom margin for the same\n * reason; neither of them touches the content height.\n *\n * The mark itself is not drawn here. It is vector artwork and this is a\n * post-processing pass over a finished file with no layout to hang it off; the\n * Forme backend — the one Cloud renders on — draws both. Chromium is the\n * fidelity reference and an escalation path, and a credit line without its\n * glyph is a great deal better than a grey box where the glyph should be.\n */\n if ((spec.placement ?? \"center\") === \"bottom\") {\n for (const page of doc.getPages()) {\n const { width: pw } = page.getSize();\n page.drawText(spec.text, {\n x: (pw - width) / 2,\n y: spec.fontSize * 1.2,\n size: spec.fontSize,\n font,\n color: rgb(color.r, color.g, color.b),\n opacity: spec.opacity\n });\n }\n return;\n }\n\n for (const page of doc.getPages()) {\n const { width: pw, height: ph } = page.getSize();\n // drawText places the baseline at (x, y) and then rotates about that point,\n // so the centring has to be done in the rotated frame: walk back along the\n // text's own axis by half its length, and off it by half its height.\n const x = pw / 2 - (Math.cos(radians) * width) / 2 + (Math.sin(radians) * height) / 2;\n const y = ph / 2 - (Math.sin(radians) * width) / 2 - (Math.cos(radians) * height) / 2;\n page.drawText(spec.text, {\n x,\n y,\n size: spec.fontSize,\n font,\n color: rgb(color.r, color.g, color.b),\n opacity: spec.opacity,\n rotate: degrees(spec.angle)\n });\n }\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());\n /* c8 ignore next -- the spec's colour is a constant; this guards a host that edited it */\n if (!m) return { r: 0.78, g: 0.06, b: 0.18 };\n const n = parseInt(m[1]!, 16);\n return { r: ((n >> 16) & 255) / 255, g: ((n >> 8) & 255) / 255, b: (n & 255) / 255 };\n}\n","import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { Browser } from \"playwright-core\";\nimport { PdfRenderer, PdfRenderError, defaultLaunch, type RenderPdfOptions } from \"./render-pdf.js\";\nimport type { NetworkPolicy } from \"./ssrf.js\";\n\nexport interface PdfServerOptions {\n port?: number;\n host?: string;\n /** Shared-secret bearer token. Strongly recommended outside of local development. */\n token?: string;\n /** Maximum request body size in bytes. Default 25 MB. */\n maxBodyBytes?: number;\n /** Concurrent renders. Default 4. */\n concurrency?: number;\n /** Default network policy (request body may narrow but never widen it). */\n network?: NetworkPolicy;\n /** Custom blocks bundle (JS source) injected into every render. */\n customBlocksScript?: string;\n launch?: () => Promise<Browser>;\n timeoutMs?: number;\n maxPages?: number;\n log?: (msg: string) => void;\n}\n\nexport interface PdfServer {\n server: Server;\n port: number;\n close(): Promise<void>;\n}\n\ninterface RenderRequestBody extends Omit<RenderPdfOptions, \"now\" | \"network\" | \"customBlocksScript\" | \"runtimePath\" | \"metadata\"> {\n now?: string;\n network?: { allowedHosts?: string[] };\n metadata?: { title?: string; author?: string; subject?: string; keywords?: string[] };\n /** \"pdf\" (default) returns application/pdf; \"json\" returns { pdfBase64, pages, warnings }. */\n format?: \"pdf\" | \"json\";\n}\n\nfunction readJson(req: IncomingMessage, limit: number): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n req.on(\"data\", (c: Buffer) => {\n size += c.length;\n if (size > limit) {\n reject(new Error(\"Request body too large\"));\n req.destroy();\n return;\n }\n chunks.push(c);\n });\n req.on(\"end\", () => {\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString(\"utf8\")));\n } catch {\n reject(new Error(\"Invalid JSON\"));\n }\n });\n req.on(\"error\", reject);\n });\n}\n\nfunction send(res: ServerResponse, status: number, body: unknown, headers: Record<string, string> = {}) {\n const json = JSON.stringify(body);\n res.writeHead(status, { \"content-type\": \"application/json; charset=utf-8\", \"content-length\": Buffer.byteLength(json), ...headers });\n res.end(json);\n}\n\n/**\n * Starts a small, dependency-free HTTP service:\n * POST /render → PDF bytes (or JSON with format: \"json\")\n * GET /health → { ok, browser }\n *\n * Deploy it next to your application. Report data never leaves your network.\n */\nexport async function createPdfServer(opts: PdfServerOptions = {}): Promise<PdfServer> {\n const log = opts.log ?? (() => undefined);\n const browser = await (opts.launch ?? defaultLaunch)();\n const renderer = new PdfRenderer(browser);\n const concurrency = opts.concurrency ?? 4;\n let active = 0;\n const queue: Array<() => void> = [];\n const acquire = () =>\n new Promise<void>((resolve) => {\n if (active < concurrency) {\n active++;\n resolve();\n } else queue.push(resolve);\n });\n const release = () => {\n active--;\n const next = queue.shift();\n if (next) {\n active++;\n next();\n }\n };\n\n const server = createServer(async (req, res) => {\n const url = new URL(req.url ?? \"/\", \"http://localhost\");\n res.setHeader(\"x-content-type-options\", \"nosniff\");\n if (req.method === \"GET\" && url.pathname === \"/health\") return send(res, 200, { ok: true, browser: browser.isConnected(), active, queued: queue.length });\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, { \"access-control-allow-origin\": \"*\", \"access-control-allow-headers\": \"authorization, content-type\", \"access-control-allow-methods\": \"POST, GET, OPTIONS\" });\n return res.end();\n }\n if (req.method !== \"POST\" || url.pathname !== \"/render\") return send(res, 404, { error: \"Not found\" });\n if (opts.token) {\n const auth = req.headers.authorization ?? \"\";\n if (auth !== `Bearer ${opts.token}`) return send(res, 401, { error: \"Unauthorised\" });\n }\n let body: RenderRequestBody;\n try {\n body = (await readJson(req, opts.maxBodyBytes ?? 25 * 1024 * 1024)) as RenderRequestBody;\n } catch (e) {\n return send(res, 400, { error: (e as Error).message });\n }\n if (!body || typeof body !== \"object\" || !body.template) return send(res, 400, { error: \"Missing template\" });\n\n // Narrow the network policy: request may only restrict, never widen.\n const serverHosts = opts.network?.allowedHosts ?? [];\n const requested = body.network?.allowedHosts;\n const allowedHosts = requested ? requested.filter((h) => serverHosts.includes(\"*\") || serverHosts.includes(h)) : serverHosts;\n\n await acquire();\n const started = Date.now();\n try {\n const result = await renderer.render({\n template: body.template,\n data: body.data,\n theme: body.theme,\n dataSources: body.dataSources,\n now: body.now ? new Date(body.now) : undefined,\n locale: body.locale,\n currency: body.currency,\n timeZone: body.timeZone,\n metadata: body.metadata,\n network: { ...(opts.network ?? {}), allowedHosts },\n customBlocksScript: opts.customBlocksScript,\n timeoutMs: opts.timeoutMs,\n maxPages: opts.maxPages\n });\n log(`render ok pages=${result.pages} ms=${result.durationMs}`);\n res.setHeader(\"access-control-allow-origin\", \"*\");\n if (body.format === \"json\") return send(res, 200, { pdfBase64: result.pdf.toString(\"base64\"), pages: result.pages, warnings: result.warnings, durationMs: result.durationMs });\n 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\"` });\n res.end(result.pdf);\n } catch (e) {\n const err = e as PdfRenderError;\n log(`render failed ${err.code ?? \"\"} ${err.message} ms=${Date.now() - started}`);\n const status = err instanceof PdfRenderError ? (err.code === \"TIMEOUT\" ? 504 : err.code === \"TOO_MANY_PAGES\" ? 413 : 500) : 500;\n res.setHeader(\"access-control-allow-origin\", \"*\");\n send(res, status, { error: err.message, code: err.code ?? \"UNKNOWN\" });\n } finally {\n release();\n }\n });\n\n const port = opts.port ?? 4780;\n await new Promise<void>((resolve) => server.listen(port, opts.host ?? \"0.0.0.0\", resolve));\n const address = server.address();\n const actualPort = typeof address === \"object\" && address ? address.port : port;\n log(`BroadPaper PDF service listening on http://${opts.host ?? \"0.0.0.0\"}:${actualPort}`);\n return {\n server,\n port: actualPort,\n close: async () => {\n await new Promise<void>((resolve) => server.close(() => resolve()));\n await browser.close().catch(() => undefined);\n }\n };\n}\n"],"mappings":"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","names":["i","G","mod","log"]}
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createPdfServer
4
- } from "./chunk-OHMUXC7H.js";
4
+ } from "./chunk-H5HVLT2H.js";
5
5
 
6
6
  // src/cli.ts
7
7
  var env = process.env;
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  renderPdf,
14
14
  resolveLicenseStatus,
15
15
  verifyLicense
16
- } from "./chunk-OHMUXC7H.js";
16
+ } from "./chunk-H5HVLT2H.js";
17
17
  export {
18
18
  BroadPaper,
19
19
  PdfRenderError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@broadpaper/pdf",
3
- "version": "0.4.1",
3
+ "version": "1.0.0",
4
4
  "description": "BroadPaper PDF renderer: headless Chromium printing of the paged document, with an HTTP server, SSRF guard and a browser print fallback.",
5
5
  "keywords": [
6
6
  "pdf",
@@ -48,10 +48,10 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "pdf-lib": "^1.17.1",
51
- "@broadpaper/blocks": "0.4.1",
52
- "@broadpaper/core": "0.4.1",
53
- "@broadpaper/renderer": "0.4.1",
54
- "@broadpaper/license": "0.4.1"
51
+ "@broadpaper/blocks": "1.0.0",
52
+ "@broadpaper/core": "1.0.0",
53
+ "@broadpaper/renderer": "1.0.0",
54
+ "@broadpaper/license": "1.0.0"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "playwright": ">=1.40",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../license/src/encoding.ts","../../license/src/format.ts","../../../node_modules/.pnpm/@noble+ed25519@3.2.0/node_modules/@noble/ed25519/index.js","../../license/src/trusted-keys.ts","../../license/src/types.ts","../../license/src/verify.ts","../../license/src/config.ts","../../license/src/watermark.ts","../src/server/ssrf.ts","../src/server/render-pdf.ts","../src/server/watermark.ts","../src/server/http.ts"],"sourcesContent":["/**\n * base64url and UTF-8, without depending on Node or on the DOM.\n *\n * The SDK runs in Node, in edge runtimes, in a worker and in a browser, and the\n * licence string has to decode identically in all four. `atob`/`btoa` exist\n * everywhere modern but are byte-oriented and mangle anything above U+00FF, so\n * text goes through `TextEncoder`/`TextDecoder` first and only bytes are\n * base64'd. The tables below are the whole implementation, which is smaller\n * than the runtime detection needed to use `Buffer` where it happens to exist.\n */\n\nconst ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\nconst LOOKUP = /* @__PURE__ */ (() => {\n const t = new Int8Array(128).fill(-1);\n for (let i = 0; i < ALPHABET.length; i++) t[ALPHABET.charCodeAt(i)] = i;\n // Accept standard base64 as well, so a licence that survived a round trip\n // through a system that rewrote the alphabet still reads.\n t[\"+\".charCodeAt(0)] = 62;\n t[\"/\".charCodeAt(0)] = 63;\n return t;\n})();\n\nexport function bytesToBase64Url(bytes: Uint8Array): string {\n let out = \"\";\n let i = 0;\n for (; i + 2 < bytes.length; i += 3) {\n const n = (bytes[i]! << 16) | (bytes[i + 1]! << 8) | bytes[i + 2]!;\n out += ALPHABET[(n >>> 18) & 63]! + ALPHABET[(n >>> 12) & 63]! + ALPHABET[(n >>> 6) & 63]! + ALPHABET[n & 63]!;\n }\n const rest = bytes.length - i;\n if (rest === 1) {\n const n = bytes[i]! << 16;\n out += ALPHABET[(n >>> 18) & 63]! + ALPHABET[(n >>> 12) & 63]!;\n } else if (rest === 2) {\n const n = (bytes[i]! << 16) | (bytes[i + 1]! << 8);\n out += ALPHABET[(n >>> 18) & 63]! + ALPHABET[(n >>> 12) & 63]! + ALPHABET[(n >>> 6) & 63]!;\n }\n return out;\n}\n\n/** Throws on anything that is not base64/base64url. Padding is optional. */\nexport function base64UrlToBytes(text: string): Uint8Array {\n let end = text.length;\n while (end > 0 && text[end - 1] === \"=\") end--;\n const chars: number[] = [];\n for (let i = 0; i < end; i++) {\n const code = text.charCodeAt(i);\n const value = code < 128 ? LOOKUP[code]! : -1;\n if (value < 0) throw new Error(`not base64: ${JSON.stringify(text[i])} at ${i}`);\n chars.push(value);\n }\n // 4 base64 characters carry 3 bytes; a group of 1 is never valid.\n if (chars.length % 4 === 1) throw new Error(\"not base64: truncated\");\n const out = new Uint8Array(Math.floor((chars.length * 3) / 4));\n let o = 0;\n let i = 0;\n for (; i + 3 < chars.length; i += 4) {\n const n = (chars[i]! << 18) | (chars[i + 1]! << 12) | (chars[i + 2]! << 6) | chars[i + 3]!;\n out[o++] = (n >>> 16) & 255;\n out[o++] = (n >>> 8) & 255;\n out[o++] = n & 255;\n }\n const rest = chars.length - i;\n if (rest === 2) {\n out[o++] = ((chars[i]! << 18) | (chars[i + 1]! << 12)) >>> 16;\n } else if (rest === 3) {\n const n = (chars[i]! << 18) | (chars[i + 1]! << 12) | (chars[i + 2]! << 6);\n out[o++] = (n >>> 16) & 255;\n out[o++] = (n >>> 8) & 255;\n }\n return out;\n}\n\nconst encoder = /* @__PURE__ */ new TextEncoder();\nconst decoder = /* @__PURE__ */ new TextDecoder(\"utf-8\", { fatal: true });\n\nexport const utf8ToBytes = (text: string): Uint8Array => encoder.encode(text);\nexport const bytesToUtf8 = (bytes: Uint8Array): string => decoder.decode(bytes);\n","/**\n * The licence string.\n *\n * BP1.<base64url payload>.<base64url signature>\n *\n * Three parts, dot-separated, safe in an environment variable, a YAML file, a\n * URL and a shell argument without quoting. The leading `BP1` is the *string\n * format* version and `payload.version` is the *payload schema* version; they\n * move independently, and both are checked, so a licence issued for a later\n * format is reported as unsupported rather than as corrupt.\n *\n * What is signed is the bytes of `BP1.<payload>` — prefix included. Signing the\n * encoded text rather than the decoded object means verification never depends\n * on two JSON serialisers agreeing about key order or number formatting, and\n * covering the prefix stops a payload being lifted into a future format that\n * might read a field differently.\n */\nimport { base64UrlToBytes, bytesToBase64Url, bytesToUtf8, utf8ToBytes } from \"./encoding.js\";\nimport { PRODUCT, type LicensePayload, type LicenseType, type Plan } from \"./types.js\";\n\n/** The only string format this SDK can read. */\nexport const FORMAT_PREFIX = \"BP1\";\n\n/** A licence string split into its parts, before any signature check. */\nexport interface ParsedLicense {\n prefix: string;\n /** The exact text that was signed. */\n signedText: string;\n encodedPayload: string;\n signature: Uint8Array;\n payload: LicensePayload;\n}\n\nexport class LicenseFormatError extends Error {\n constructor(\n message: string,\n /** `unsupported` when the licence is well-formed but newer than this SDK. */\n readonly kind: \"invalid\" | \"unsupported\" = \"invalid\"\n ) {\n super(message);\n this.name = \"LicenseFormatError\";\n }\n}\n\nconst PLANS: readonly Plan[] = [\"internal\", \"saas\"];\n\n/**\n * The licence types this SDK can actually honour.\n *\n * Only `subscription`. A perpetual licence's whole meaning is that the right to\n * use outlives the right to updates, which needs the running build's release\n * date to enforce — a fact a certificate cannot carry, because it is issued\n * before the versions it covers exist. A build with no such date could only\n * honour a perpetual licence by honouring *every* future version forever, which\n * is not what was sold. So it is refused, and refused as `unsupported` rather\n * than `invalid`: the fix is to upgrade, and saying so is more use than calling\n * a valid certificate corrupt.\n */\nconst LICENSE_TYPES: readonly LicenseType[] = [\"subscription\"];\n\n/** Whitespace is stripped: licences get pasted, wrapped and indented. */\nexport function normalizeLicense(license: string): string {\n return license.replace(/\\s+/g, \"\");\n}\n\n/**\n * Reads a licence string without verifying it.\n *\n * Nothing here decides whether a licence is *honoured* — that needs the\n * signature — but a structurally broken string can be rejected before any\n * cryptography happens, and the account UI can display a licence's contents\n * without holding a public key.\n */\nexport function parseLicense(license: string): ParsedLicense {\n const text = normalizeLicense(license);\n if (!text) throw new LicenseFormatError(\"the licence string is empty\");\n\n const parts = text.split(\".\");\n if (parts.length !== 3) throw new LicenseFormatError(`expected three dot-separated parts, found ${parts.length}`);\n const [prefix, encodedPayload, encodedSignature] = parts as [string, string, string];\n\n if (prefix !== FORMAT_PREFIX) {\n // A licence issued in a format this SDK predates is a version problem, not\n // a corrupt string, and the fix is to upgrade rather than to re-copy it.\n const known = /^BP\\d+$/.test(prefix);\n throw new LicenseFormatError(\n known\n ? `licence format ${prefix} is newer than this version of BroadPaper, which reads ${FORMAT_PREFIX}`\n : `unrecognised licence prefix ${JSON.stringify(prefix)}`,\n known ? \"unsupported\" : \"invalid\"\n );\n }\n if (!encodedPayload || !encodedSignature) throw new LicenseFormatError(\"the licence string has an empty part\");\n\n let json: string;\n let signature: Uint8Array;\n try {\n json = bytesToUtf8(base64UrlToBytes(encodedPayload));\n signature = base64UrlToBytes(encodedSignature);\n } catch (e) {\n throw new LicenseFormatError(`the licence string is not valid base64 (${(e as Error).message})`);\n }\n if (signature.length !== 64) throw new LicenseFormatError(`an Ed25519 signature is 64 bytes, this one is ${signature.length}`);\n\n let raw: unknown;\n try {\n raw = JSON.parse(json);\n } catch {\n throw new LicenseFormatError(\"the licence payload is not valid JSON\");\n }\n\n return {\n prefix,\n signedText: `${prefix}.${encodedPayload}`,\n encodedPayload,\n signature,\n payload: readPayload(raw)\n };\n}\n\n/**\n * Validates the payload's shape.\n *\n * Unknown properties are kept, not rejected: they are inside the signature, so\n * a licence issued by a later BroadPaper carrying a field this SDK has never\n * heard of is still a licence this SDK can honour.\n */\nfunction readPayload(raw: unknown): LicensePayload {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) throw new LicenseFormatError(\"the licence payload is not an object\");\n const o = raw as Record<string, unknown>;\n\n const schemaVersion = o.schemaVersion;\n if (schemaVersion !== 1) {\n const numeric = typeof schemaVersion === \"number\" && Number.isInteger(schemaVersion) && schemaVersion > 1;\n throw new LicenseFormatError(\n numeric\n ? `licence payload schema version ${schemaVersion} is newer than this version of BroadPaper, which reads version 1`\n : \"the licence payload has no usable schemaVersion\",\n numeric ? \"unsupported\" : \"invalid\"\n );\n }\n\n const text = (key: string): string => {\n const value = o[key];\n if (typeof value !== \"string\" || value === \"\") throw new LicenseFormatError(`the licence payload is missing ${key}`);\n return value;\n };\n const seconds = (key: string): number => {\n const value = o[key];\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new LicenseFormatError(`the licence payload is missing ${key}`);\n return value;\n };\n // `null` is the honest encoding of \"no end date\" — a sentinel year 9999 would\n // be a date somebody eventually compares against. Absent is still an error;\n // only an explicit null means never.\n const secondsOrNever = (key: string): number | null => {\n const value = o[key];\n if (value === null) return null;\n return seconds(key);\n };\n\n const plan = text(\"plan\");\n if (!PLANS.includes(plan as Plan)) {\n // A plan this SDK does not know is a newer commercial model, and refusing\n // to honour a licence we cannot classify would punish the customer for\n // buying something new. It is reported as unsupported so the developer is\n // told to upgrade.\n throw new LicenseFormatError(`this version of BroadPaper does not know the plan ${JSON.stringify(plan)}`, \"unsupported\");\n }\n\n const licenseType = text(\"licenseType\");\n if (!LICENSE_TYPES.includes(licenseType as LicenseType)) {\n throw new LicenseFormatError(`this version of BroadPaper cannot honour a ${JSON.stringify(licenseType)} licence`, \"unsupported\");\n }\n\n return {\n ...o,\n schemaVersion: 1,\n keyId: text(\"keyId\"),\n licenseId: text(\"licenseId\"),\n organisationId: text(\"organisationId\"),\n organisationName: text(\"organisationName\"),\n product: text(\"product\") as typeof PRODUCT,\n plan: plan as Plan,\n licenseType: licenseType as LicenseType,\n issuedAt: seconds(\"issuedAt\"),\n validUntil: secondsOrNever(\"validUntil\"),\n updatesUntil: seconds(\"updatesUntil\")\n };\n}\n\n/**\n * Encodes a payload into the text that gets signed.\n *\n * Exported because BroadPaper's own licence issuer must produce byte-identical\n * input to what the SDK verifies, and the only way to guarantee that is for\n * both to call this function.\n */\nexport function encodeSigningInput(payload: LicensePayload): { signedText: string; encodedPayload: string } {\n const encodedPayload = bytesToBase64Url(utf8ToBytes(JSON.stringify(payload)));\n return { encodedPayload, signedText: `${FORMAT_PREFIX}.${encodedPayload}` };\n}\n\n/** Assembles the final licence string from a payload and its signature. */\nexport function formatLicense(payload: LicensePayload, signature: Uint8Array): string {\n if (signature.length !== 64) throw new LicenseFormatError(`an Ed25519 signature is 64 bytes, this one is ${signature.length}`);\n const { encodedPayload } = encodeSigningInput(payload);\n return `${FORMAT_PREFIX}.${encodedPayload}.${bytesToBase64Url(signature)}`;\n}\n","/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */\n/**\n * 5KB JS implementation of ed25519 EdDSA signatures.\n * Targets RFC8032, FIPS 186-5, and ZIP215 behavior.\n * @module\n * @example\n * ```js\nimport * as ed from '@noble/ed25519';\n(async () => {\n const secretKey = ed.utils.randomSecretKey();\n const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);\n const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present\n const signature = await ed.signAsync(message, secretKey);\n const isValid = await ed.verifyAsync(signature, message, pubKey);\n})();\n```\n */\n/**\n * Curve params. edwards25519 uses the RFC equation `-x² + y² = 1 + dx²y²`.\n * The stored `a` literal below is `p - 1`, i.e. the field-element encoding of RFC `a = -1`.\n * * P = `2n**255n - 19n` // field over which calculations are done\n * * N = `2n**252n + 27742317777372353535851937790883648493n` // prime-order subgroup order\n * * h = 8 // cofactor\n * * a = `Fp.create(BigInt(-1))` // equation param, stored here as `p - 1`\n * * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param\n * * Gx, Gy are coordinates of Generator / base point\n *\n * Mirror noble-curves: Point.CURVE() exposes shared params, but callers must not be able to mutate\n * that shared view and desynchronize it from the arithmetic constants captured below.\n */\nconst freeze = Object.freeze;\nconst P = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn;\nconst N = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn;\nconst _d = 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n;\nconst Gx = 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an;\nconst Gy = 0x6666666666666666666666666666666666666666666666666666666666666658n;\nconst _a = P - 1n; // field-element encoding of RFC `a = -1`\nconst ed25519_CURVE = freeze({\n p: P,\n n: N,\n h: 8n,\n a: _a,\n d: _d,\n Gx,\n Gy,\n});\n// Shared 32-byte encoded width for Ed25519 points, scalars, signatures/2, and keys. Named LEN\n// rather than RFC 8032's `L`, which names the group order (stored here as `N`).\nconst LEN = 32;\n// Helpers and Precomputes sections are reused between libraries\n// ## Helpers\n// ----------\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nconst isBytes = (a) => {\n // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases.\n // The fallback still requires a real ArrayBuffer view, so plain\n // JSON-deserialized `{ constructor: ... }` spoofing is rejected, and\n // `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.\n return (a instanceof Uint8Array ||\n (ArrayBuffer.isView(a) &&\n a.constructor.name === 'Uint8Array' &&\n a.BYTES_PER_ELEMENT === 1));\n};\n/** Asserts something is Bytes. */\nconst abytes = (value, length, title = '') => {\n // Success path first: this runs at the start of every update() / digestInto(), and the\n // common `abytes(data)` form must not pay for length handling it does not use.\n if (isBytes(value) && (length === undefined || value.length === length))\n return value;\n // Error path: recompute freely to build the exact message.\n const bytes = isBytes(value);\n const ofLen = length !== undefined ? ` of length ${length}` : '';\n const got = bytes ? `length=${value.length}` : `type=${typeof value}`;\n const message = (title ? `\"${title}\" ` : '') + 'expected Uint8Array' + ofLen + ', got ' + got;\n if (!bytes)\n throw new TypeError(message);\n throw new RangeError(message);\n};\n// Validate, then take one owned copy, so later caller mutation cannot be observed — e.g. cannot\n// make sign()'s nonce derivation and challenge derivation see different messages.\nconst snapshotBytes = (value, title = '', length) => Uint8Array.from(abytes(value, length, title));\n// Callers keep values non-negative and within the requested width; padStart() won't truncate over-wide inputs.\nconst padh = (n, pad) => n.toString(16).padStart(pad, '0');\n/** Convert byte array to hex string. */\nconst bytesToHex = (bytes) => {\n let hex = '';\n for (const byte of abytes(bytes))\n hex += padh(byte, 2);\n return hex;\n};\n/** Convert hex string to byte array. */\nconst hexToBytes = (hex) => {\n const e = 'hex invalid'; // Strict ASCII hex only, with one generic error for parse failures.\n if (typeof hex !== 'string')\n throw new TypeError(e);\n if (hex.length % 2 || !/^[\\da-f]*$/i.test(hex))\n throw new RangeError(e);\n const array = new Uint8Array(hex.length / 2);\n for (let ai = 0, hi = 0; ai < array.length; ai++, hi += 2) {\n const n1 = hex.charCodeAt(hi);\n const n2 = hex.charCodeAt(hi + 1);\n // Regex guarantees ASCII. For 0..9/A..F/a..f, this maps char codes to 0..15.\n array[ai] = ((n1 & 15) + (n1 >> 6) * 9) * 16 + (n2 & 15) + (n2 >> 6) * 9;\n }\n return array;\n};\n// WebCrypto is available in all modern environments\n/** Copies several Uint8Arrays into one. */\nconst concatBytes = (...arrays) => {\n let sum = 0;\n for (const a of arrays)\n sum += abytes(a).length;\n const res = new Uint8Array(sum);\n let pad = 0;\n for (const a of arrays) {\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n};\n/**\n * WebCrypto OS-level CSPRNG (random number generator).\n * Will throw when not available; large-request ceilings are delegated to getRandomValues().\n */\nconst randomBytes = (len = LEN) => {\n const c = globalThis?.crypto;\n if (typeof c?.getRandomValues !== 'function')\n throw new Error('crypto.getRandomValues must be defined, consider polyfill');\n return c.getRandomValues(new Uint8Array(len));\n};\n/** Inclusive-lower, exclusive-upper bigint range assertion. */\nconst arange = (n, min, max, msg = 'bad number: out of range') => {\n if (typeof n !== 'bigint')\n throw new TypeError(msg);\n if (min <= n && n < max)\n return n;\n throw new RangeError(msg);\n};\n/** Canonical modular reduction. Callers must provide a positive modulus. */\nconst mod = (a, b = P) => ((a %= b) >= 0n ? a : b + a);\n// Low-255-bit mask used by the `2^255 - 19` fast reduction in `modP(...)`.\nconst P_MASK = (1n << 255n) - 1n;\n// Fast reduction for the special prime `2^255 - 19`. This path assumes nonnegative inputs; the\n// generic fallback would simply be `mod(num, P)`.\nconst modP = (num) => {\n if (num < 0n)\n throw new RangeError('negative coordinate');\n let r = (num >> 255n) * 19n + (num & P_MASK);\n r = (r >> 255n) * 19n + (r & P_MASK);\n return r % P;\n};\n// Reduce modulo the subgroup order stored in implementation constant `N` (RFC 8032's `L`).\nconst modN = (a) => mod(a, N);\n/** Modular inversion using extended euclidean GCD. Variable-time (non-CT). */\nconst invert = (number, modulo) => {\n if (number === 0n)\n throw new Error('invert: expected non-zero number');\n // modulo = 1 is the zero ring: gcd(x, 1) = 1 makes the loop below \"succeed\" and return the\n // useless inverse 0. Reject it like pow() and invertCt() do.\n if (modulo <= 1n)\n throw new Error('invert: expected modulus > 1, got ' + modulo);\n // This is variable-time: the loop count depends on `number`.\n let a = mod(number, modulo);\n let b = modulo;\n // Only the Bézout coefficient of `number` (x/u chain) is tracked; the coefficient of `modulo`\n // never affects the output, so it is not computed.\n // prettier-ignore\n let x = 0n, u = 1n;\n while (a !== 0n) {\n const q = b / a;\n const r = b - a * q;\n const m = x - u * q;\n // prettier-ignore\n b = a, a = r, x = u, u = m;\n }\n const gcd = b;\n if (gcd !== 1n)\n throw new Error('invert: does not exist');\n return mod(x, modulo);\n};\n// Dynamic lookup keeps sync/async hash providers configurable at runtime. Both exported slots are\n// caller-owned and may be unset; wrapper helpers use this lookup first and then enforce the digest\n// contract instead of trusting provider output.\nconst _hash = (name) => {\n // @ts-ignore\n const fn = hashes[name];\n if (typeof fn !== 'function')\n throw new Error('hashes.' + name + ' not set');\n return fn;\n};\n// All exported provider slots are caller-configurable and may be unset or return arbitrary values,\n// so wrapper helpers must enforce the exact 64-byte SHA-512 digest contract instead of trusting providers.\nconst callHash = (name, ...m) => abytes(_hash(name)(concatBytes(...m)), 64, 'digest');\nconst callHashAsync = async (name, ...m) => abytes(await _hash(name)(concatBytes(...m)), 64, 'digest');\n/**\n * SHA-512 helper used by the synchronous API.\n * @param msg - Message bytes to hash.\n * @returns 64-byte SHA-512 digest.\n * @example\n * Hash message bytes after wiring the synchronous SHA-512 implementation.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const digest = ed.hash(new Uint8Array([1, 2, 3]));\n * ```\n */\n// Public helper validates the message boundary explicitly; the configured provider is still looked\n// up dynamically and its output is checked with `callHash(...)`.\nconst hash = (msg) => callHash('sha512', abytes(msg, undefined, 'message'));\n// Runtime class guard: this is `instanceof Point`, so cross-realm / duplicate-bundle Point objects\n// are rejected even if they are structurally identical.\nconst apoint = (p) => {\n if (p instanceof Point)\n return p;\n throw new TypeError('Point expected');\n};\n// ## End of Helpers\n// -----------------\n// Exclusive upper bound `2^256` used by 32-byte decode/serialization range checks.\nconst B256 = 2n ** 256n;\n/**\n * Point in XYZT extended coordinates.\n * @param X - X coordinate.\n * @param Y - Y coordinate.\n * @param Z - Projective Z coordinate.\n * @param T - Cached cross-product term.\n * @example\n * Do point arithmetic with the built-in base point and encode the result as hex.\n *\n * ```ts\n * const hex = Point.BASE.double().toHex();\n * ```\n */\nclass Point {\n static BASE;\n static ZERO;\n X;\n Y;\n Z;\n T;\n // Constructor only bounds-checks and freezes XYZT coordinates; it does not prove the point is\n // on-curve or that T matches X*Y/Z.\n constructor(X, Y, Z, T) {\n const max = B256;\n this.X = arange(X, 0n, max);\n this.Y = arange(Y, 0n, max);\n this.Z = arange(Z, 1n, max);\n this.T = arange(T, 0n, max);\n freeze(this);\n }\n static CURVE() {\n return ed25519_CURVE;\n }\n static fromAffine(p) {\n return new Point(p.x, p.y, 1n, modP(p.x * p.y));\n }\n /** RFC8032 5.1.3: Uint8Array to Point. */\n static fromBytes(bytes, zip215 = false) {\n const normed = snapshotBytes(bytes, 'point', LEN); // owned copy: sign-bit mask below mutates it\n // adjust first LE byte = last BE byte\n const lastByte = normed[31];\n normed[31] = lastByte & ~0x80;\n const y = bytesToNumberLE(normed);\n // After clearing the sign bit, parsed `y` is always < 2^255. ZIP-215 still accepts the full\n // post-mask range here, while strict RFC8032 decoding further requires `y < p`.\n if (!zip215)\n arange(y, 0n, P);\n const y2 = modP(y * y); // y²\n const u = mod(y2 - 1n); // u=y²-1\n const v = modP(_d * y2 + 1n); // v=dy²+1\n let { isValid, value: x } = uvRatio(u, v); // (uv³)(uv⁷)^(p-5)/8; square root\n if (!isValid)\n throw new Error('bad point: y not sqrt'); // not square root: bad point\n const isLastByteOdd = !!(lastByte & 0x80); // x_0, last bit\n // ZIP-215-compatible decoding keeps the x=0 / sign-bit=1 encoding accepted; strict RFC 8032\n // rejects it, but the vendored ZIP-215 compliance vectors include this form in A/R bytes.\n if (!zip215 && x === 0n && isLastByteOdd)\n throw new Error('bad point: x==0, isLastByteOdd'); // x=0, x_0=1\n if (isLastByteOdd !== !!(x & 1n))\n x = mod(-x); // adjust sign of x coordinate\n return new Point(x, y, 1n, modP(x * y)); // Z=1, T=xy\n }\n static fromHex(hex, zip215) {\n return Point.fromBytes(hexToBytes(hex), zip215);\n }\n get x() {\n return this.toAffine().x;\n }\n get y() {\n return this.toAffine().y;\n }\n /** Checks if the point is valid and on-curve. */\n assertValidity() {\n const a = _a;\n const d = _d;\n const p = this;\n // Intentional stricter-than-on-curve policy: reject ZERO by default because many protocols\n // require a non-zero point, and silently accepting identity points is a common caller mistake.\n if (p.is0())\n throw new Error('bad point: ZERO');\n // Equation in affine coordinates: ax² + y² = 1 + dx²y²\n // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²\n const { X, Y, Z, T } = p;\n const X2 = modP(X * X); // X²\n const Y2 = modP(Y * Y); // Y²\n const Z2 = modP(Z * Z); // Z²\n const Z4 = modP(Z2 * Z2); // Z⁴\n const aX2 = modP(X2 * a); // aX²\n const left = modP(Z2 * (aX2 + Y2)); // (aX² + Y²)Z²\n const right = mod(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²\n if (left !== right)\n throw new Error('bad point: equation left != right (1)');\n // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T\n const XY = modP(X * Y);\n const ZT = modP(Z * T);\n if (XY !== ZT)\n throw new Error('bad point: equation left != right (2)');\n return this;\n }\n /** Equality check: compare points P&Q. */\n equals(other) {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality\n return modP(X1 * Z2) === modP(X2 * Z1) && modP(Y1 * Z2) === modP(Y2 * Z1);\n }\n is0() {\n return this.equals(I);\n }\n /** Flip point over y coordinate. */\n negate() {\n return new Point(mod(-this.X), this.Y, this.Z, mod(-this.T));\n }\n /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */\n double() {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const a = _a;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd\n const A = modP(X1 * X1);\n const B = modP(Y1 * Y1);\n const C = modP(2n * Z1 * Z1);\n const D = modP(a * A);\n const x1y1 = mod(X1 + Y1);\n const E = mod(modP(x1y1 * x1y1) - A - B);\n const G = mod(D + B);\n const F = mod(G - C);\n const H = mod(D - B);\n const X3 = modP(E * F);\n const Y3 = modP(G * H);\n const T3 = modP(E * H);\n const Z3 = modP(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n /** Point addition. Complete formula. Cost: `9M + 1*a + 1*d + 7add`. */\n add(other) {\n const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;\n const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); // doesn't check if other on-curve\n const a = _a;\n const d = _d;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd\n const A = modP(X1 * X2);\n const B = modP(Y1 * Y2);\n const C = modP(modP(T1 * d) * T2);\n const D = modP(Z1 * Z2);\n const E = mod(modP(mod(X1 + Y1) * mod(X2 + Y2)) - A - B);\n const F = mod(D - C);\n const G = mod(D + C);\n const H = mod(B - modP(a * A));\n const X3 = modP(E * F);\n const Y3 = modP(G * H);\n const T3 = modP(E * H);\n const Z3 = modP(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n subtract(other) {\n return this.add(apoint(other).negate());\n }\n /**\n * Point-by-scalar multiplication. Safe mode requires `1 <= n < CURVE.n`.\n * Unsafe mode additionally permits `n = 0` and returns the identity point for that case.\n * Uses {@link wNAF} for base point.\n * Uses fake point to mitigate side-channel leakage.\n * @param n - scalar by which point is multiplied\n * @param safe - safe mode guards against timing attacks; unsafe mode is faster\n */\n multiply(n, safe = true) {\n // Mirror noble-curves: unsafe mode still validates scalar range first, but intentionally keeps\n // `n = 0` as the one extra accepted case used by verification-style callers.\n if (!safe && n === 0n)\n return I;\n arange(n, 1n, N);\n if (!safe && this.is0())\n return I;\n if (n === 1n)\n return this;\n if (this.equals(G))\n return wNAF(n).p;\n // init result point & fake point\n let p = I;\n let f = G;\n let d = this;\n // Safe mode always runs 256 iterations so ladder length can't leak the scalar's\n // leading zero bits; unsafe mode stops at the top set bit for speed.\n for (let i = 0; safe ? i < 256 : n > 0n; i++) {\n // if bit is present, add to point\n // if not present, add to fake, for timing safety\n if (n & 1n)\n p = p.add(d);\n else if (safe)\n f = f.add(d);\n d = d.double();\n n >>= 1n;\n }\n return p;\n }\n multiplyUnsafe(scalar) {\n return this.multiply(scalar, false);\n }\n /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */\n toAffine() {\n const { X, Y, Z } = this;\n // Fast-path only for the identity point; all other inputs still go through inversion.\n if (this.equals(I))\n return { x: 0n, y: 1n };\n const iz = invert(Z, P);\n // (Z * Z^-1) must be 1, otherwise bad math\n if (modP(Z * iz) !== 1n)\n throw new Error('invalid inverse');\n // x = X*Z^-1; y = Y*Z^-1\n return { x: modP(X * iz), y: modP(Y * iz) };\n }\n toBytes() {\n const { x, y } = this.toAffine();\n const b = numTo32bLE(y);\n // store sign in first LE byte\n b[31] |= x & 1n ? 0x80 : 0;\n return b;\n }\n toHex() {\n return bytesToHex(this.toBytes());\n }\n clearCofactor() {\n return this.multiply(8n, false); // h = 8\n }\n isSmallOrder() {\n return this.clearCofactor().is0();\n }\n isTorsionFree() {\n // Multiply by big number N. We can't `mul(N)` because of checks. Instead, we `mul(N/2)*2+1`;\n // N is odd, so N/2 truncates and the final `add(this)` is always needed.\n return this.multiply(N / 2n, false)\n .double()\n .add(this)\n .is0();\n }\n}\n/** Generator / base point */\nconst G = new Point(Gx, Gy, 1n, mod(Gx * Gy));\n/** Identity / zero point */\nconst I = new Point(0n, 1n, 1n, 0n);\n// Static aliases\nPoint.BASE = G;\nPoint.ZERO = I;\nconst numTo32bLE = (num) => hexToBytes(padh(arange(num, 0n, B256), 64)).reverse();\n// Caller-enforced width: some sites require 32-byte RFC encodings, while others intentionally feed\n// wider SHA-512 output chunks through the same little-endian parser.\nconst bytesToNumberLE = (b) => BigInt('0x' + bytesToHex(Uint8Array.from(abytes(b)).reverse()));\nconst pow2 = (x, power) => {\n // pow2(x, 4) == x^(2^4)\n // Negative `power` values are not rejected here and currently leave `x` unchanged.\n let r = x;\n while (power-- > 0) {\n r = modP(r * r);\n }\n return r;\n};\n// prettier-ignore\nconst pow_2_252_3 = (x) => {\n const x2 = modP(x * x); // x^2, bits 1\n const b2 = modP(x2 * x); // x^3, bits 11\n const b4 = modP(pow2(b2, 2) * b2); // x^(2^4-1), bits 1111\n const b5 = modP(pow2(b4, 1) * x); // x^(2^5-1), bits 11111\n const b10 = modP(pow2(b5, 5) * b5); // x^(2^10-1)\n const b20 = modP(pow2(b10, 10) * b10); // x^(2^20-1)\n const b40 = modP(pow2(b20, 20) * b20); // x^(2^40-1)\n const b80 = modP(pow2(b40, 40) * b40); // x^(2^80-1)\n const b160 = modP(pow2(b80, 80) * b80); // x^(2^160-1)\n const b240 = modP(pow2(b160, 80) * b80); // x^(2^240-1)\n const b250 = modP(pow2(b240, 10) * b10); // x^(2^250-1)\n return modP(pow2(b250, 2) * x); // x^((p-5)/8), used by RFC8032 point decode\n};\nconst RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // 2^((p-1)/4) = sqrt(-1)\n// RFC8032 §5.1.3 square-root helper for point decompression. `value` is only meaningful when\n// `isValid` is true; callers are also expected to pass canonical field elements with non-zero `v`.\n// prettier-ignore\nconst uvRatio = (u, v) => {\n const v3 = modP(v * modP(v * v)); // v³\n const v7 = modP(modP(v3 * v3) * v); // v⁷\n const pow = pow_2_252_3(modP(u * v7)); // (uv⁷)^(p-5)/8\n let x = modP(u * modP(v3 * pow)); // (uv³)(uv⁷)^(p-5)/8\n const vx2 = modP(v * modP(x * x)); // vx²\n const root1 = x; // First root candidate\n const root2 = modP(x * RM1); // Second root candidate; RM1 is √-1\n const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root\n const useRoot2 = vx2 === mod(-u); // If vx² = -u, set x <-- x * 2^((p-1)/4)\n const noRoot = vx2 === mod(-u * RM1); // There is no valid root, vx² = -u√-1\n if (useRoot1)\n x = root1;\n if (useRoot2 || noRoot)\n x = root2; // We return root2 anyway, for const-time\n if ((mod(x) & 1n) === 1n)\n x = mod(-x); // edIsNegative\n return { isValid: useRoot1 || useRoot2, value: x };\n};\n// Reduce a little-endian byte string modulo the subgroup order `N` (RFC 8032's `L`); the `hash`\n// param name reflects the common caller shape, not an input restriction.\nconst modL_LE = (hash) => modN(bytesToNumberLE(hash));\n// RFC8032 5.1.5. Split the 64-byte hashed seed into the clamped scalar half and nonce prefix.\nconst hashedToExtK = (hashed) => {\n // slice creates a copy, unlike subarray\n const copy = snapshotBytes(hashed);\n const head = copy.slice(0, 32);\n head[0] &= 248; // Clamp bits: 0b1111_1000\n head[31] &= 127; // 0b0111_1111\n head[31] |= 64; // 0b0100_0000\n const prefix = copy.slice(32); // secret key \"prefix\"\n // RFC words this as `[s]B`; reducing the clamped little-endian scalar modulo `N` is equivalent\n // for base-point multiplication because `G` already has subgroup order `N`.\n const scalar = modL_LE(head);\n const point = G.multiply(scalar); // public key point\n const pointBytes = point.toBytes(); // point serialized to Uint8Array\n return { head, prefix, scalar, point, pointBytes };\n};\n// RFC8032 5.1.5; getPublicKey async, sync. Hash secret key and extract point.\nconst getExtendedPublicKeyAsync = (secretKey) => callHashAsync('sha512Async', abytes(secretKey, LEN, 'secretKey')).then(hashedToExtK);\nconst getExtendedPublicKey = (secretKey) => hashedToExtK(callHash('sha512', abytes(secretKey, LEN, 'secretKey')));\n/**\n * Creates a 32-byte Ed25519 public key from the RFC 8032 32-byte secret-key seed. Async.\n * @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.\n * @returns 32-byte public key.\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Derive the public key bytes for a newly generated signer secret.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const secretKey = ed.utils.randomSecretKey();\n * const publicKey = await ed.getPublicKeyAsync(secretKey);\n * ```\n */\nconst getPublicKeyAsync = (secretKey) => getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes);\n/**\n * Creates a 32-byte Ed25519 public key from the RFC 8032 32-byte secret-key seed.\n * To use, set `hashes.sha512` first.\n * @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.\n * @returns 32-byte public key.\n * @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Derive the public key entirely through the synchronous API.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const secretKey = ed.utils.randomSecretKey();\n * const publicKey = ed.getPublicKey(secretKey);\n * ```\n */\nconst getPublicKey = (secretKey) => getExtendedPublicKey(secretKey).pointBytes;\nconst hashFinishAsync = async (res) => res[1](await callHashAsync('sha512Async', res[0]));\nconst hashFinishSync = (res) => res[1](callHash('sha512', res[0]));\n// Code, shared between sync & async sign\nconst _sign = (e, rBytes, msg) => {\n const { pointBytes: A, scalar: s } = e;\n const r = modL_LE(rBytes); // r was created outside, reduce it modulo L\n // RFC 8032 5.1.6 allows r mod L = 0, and SUPERCOP ref10 accepts the resulting identity-point\n // signature.\n // We intentionally keep the safe multiply() rejection here so a miswired all-zero SHA-512 provider\n // fails loudly instead of silently producing a degenerate signature.\n const R = G.multiply(r).toBytes(); // R = [r]B\n const hashable = concatBytes(R, A, msg); // dom2(F, C) || R || A || PH(M)\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l\n return abytes(concatBytes(R, numTo32bLE(S)), 64); // 64-byte sig: 32-byte encoded R point || 32-byte LE(S)\n };\n return [hashable, finish];\n};\n/**\n * Signs message using secret key. Async.\n * Follows RFC8032 5.1.6.\n * @param message - Message bytes to sign.\n * @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.\n * @returns 64-byte Ed25519 signature.\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Sign an arbitrary message with a fresh Ed25519 secret key.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const secretKey = ed.utils.randomSecretKey();\n * const message = new Uint8Array([1, 2, 3]);\n * const signature = await ed.signAsync(message, secretKey);\n * ```\n */\nconst signAsync = async (message, secretKey) => {\n const m = snapshotBytes(message, 'message');\n const e = await getExtendedPublicKeyAsync(secretKey);\n // r = SHA512(dom2(F, C) || prefix || PH(M)); then generate R, k, S and the signature.\n return hashFinishAsync(_sign(e, await callHashAsync('sha512Async', e.prefix, m), m));\n};\n/**\n * Signs message using secret key. To use, set `hashes.sha512` first.\n * Follows RFC8032 5.1.6.\n * @param message - Message bytes to sign.\n * @param secretKey - 32-byte RFC 8032 secret-key seed, not a 64-byte expanded secret key.\n * @returns 64-byte Ed25519 signature.\n * @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Use the sync API when you've wired a SHA-512 implementation yourself.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const secretKey = ed.utils.randomSecretKey();\n * const signature = ed.sign(new Uint8Array([1, 2, 3]), secretKey);\n * ```\n */\nconst sign = (message, secretKey) => {\n const m = snapshotBytes(message, 'message');\n const e = getExtendedPublicKey(secretKey);\n // r = SHA512(dom2(F, C) || prefix || PH(M)); then generate R, k, S and the signature.\n return hashFinishSync(_sign(e, callHash('sha512', e.prefix, m), m));\n};\n// Exported defaults favor ZIP-215 interoperability semantics; callers must opt into the stricter\n// branch with `{ zip215: false }`.\n// Preserves the exported ZIP-215 default for `{}` / `{ zip215: undefined }`, not just omitted opts.\nconst getZip215 = (options) => {\n if (options === null || typeof options !== 'object')\n throw new TypeError('expected valid options object');\n return options.zip215 ?? true;\n};\nconst _verify = (sig, msg, publicKey, options) => {\n sig = abytes(sig, 64, 'signature'); // Signature hex str/Bytes, must be 64 bytes\n msg = abytes(msg, undefined, 'message'); // Message hex str/Bytes\n publicKey = abytes(publicKey, LEN, 'publicKey');\n const zip215 = getZip215(options);\n // zip215=false keeps the library's stricter branch, which still canonicalizes `R` / `A` before\n // hashing and rejects small-order public keys earlier than pure RFC8032 text would require.\n const r = sig.subarray(0, LEN);\n const s = bytesToNumberLE(sig.subarray(LEN, 64)); // Decode second half as an integer S;\n let A, R, SB;\n let hashable = Uint8Array.of();\n let finished = false;\n try {\n // zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.\n // zip215=true: 0 <= y < MASK (2^256 for ed25519)\n // zip215=false: 0 <= y < P (2^255-19 for ed25519)\n A = Point.fromBytes(publicKey, zip215);\n R = Point.fromBytes(r, zip215);\n SB = G.multiply(s, false); // 0 <= s < l is done inside\n // ZIP-215 accepts noncanonical / unreduced point encodings, so the challenge hash must use the\n // exact signature/public-key bytes rather than canonicalized re-encodings of the decoded points.\n hashable = concatBytes(r, publicKey, msg); // dom2(F, C) || R || A || PH(M)\n finished = true;\n }\n catch (error) { }\n const finish = (hashed) => {\n if (!finished)\n return false;\n // Policy: strict mode intentionally rejects all small-order public keys, even though the raw RFC\n // equation text is looser here. This matches libsodium and avoids weak / ambiguous verification\n // outcomes where unusual low-order public keys can make distinct key/signature combinations verify.\n if (!zip215 && A.isSmallOrder())\n return false;\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n const k = modL_LE(hashed);\n const RkA = R.add(A.multiply(k, false));\n // Extended group equation\n // [8][S]B = [8]R + [8][k]A'\n return RkA.subtract(SB).clearCofactor().is0();\n };\n return [hashable, finish];\n};\n/**\n * Verifies a signature on message and public key. Async.\n * The implementation is based on RFC8032 5.1.7, but default opts use ZIP-215 semantics; pass\n * `{ zip215: false }` for the library's stricter branch.\n * @param signature - 64-byte signature.\n * @param message - Signed message bytes.\n * @param publicKey - 32-byte public key.\n * @param opts - Verification options. Defaults to ZIP-215 semantics. See {@link EdDSAVerifyOpts}.\n * @returns `true` when the signature is valid.\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Verify the signature against the same message and derived public key.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const secretKey = ed.utils.randomSecretKey();\n * const message = new Uint8Array([1, 2, 3]);\n * const publicKey = await ed.getPublicKeyAsync(secretKey);\n * const signature = await ed.signAsync(message, secretKey);\n * const isValid = await ed.verifyAsync(signature, message, publicKey);\n * ```\n */\nconst verifyAsync = async (signature, message, publicKey, opts = {}) => hashFinishAsync(_verify(signature, message, publicKey, opts));\n/**\n * Verifies a signature on message and public key using the synchronous hash path.\n * The implementation is based on RFC8032 5.1.7, but default opts use ZIP-215 semantics; pass\n * `{ zip215: false }` for the library's stricter branch.\n * @param signature - 64-byte signature.\n * @param message - Signed message bytes.\n * @param publicKey - 32-byte public key.\n * @param opts - Verification options. Defaults to ZIP-215 semantics. See {@link EdDSAVerifyOpts}.\n * @returns `true` when the signature is valid.\n * @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Verify a signature entirely through the synchronous API.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const secretKey = ed.utils.randomSecretKey();\n * const message = new Uint8Array([1, 2, 3]);\n * const publicKey = ed.getPublicKey(secretKey);\n * const signature = ed.sign(message, secretKey);\n * const isValid = ed.verify(signature, message, publicKey);\n * ```\n */\nconst verify = (signature, message, publicKey, opts = {}) => hashFinishSync(_verify(signature, message, publicKey, opts));\n/**\n * Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves.\n * Exposes the same low-level field-default `mod` reducer and non-CT `invert` helper used\n * internally.\n * @example\n * Convert bytes to a hex string with the low-level helper namespace.\n *\n * ```ts\n * const hex = etc.bytesToHex(new Uint8Array([1, 2, 3]));\n * ```\n */\nconst etc = /* @__PURE__ */ freeze({\n bytesToHex,\n hexToBytes,\n concatBytes,\n mod,\n invert,\n randomBytes,\n});\n/**\n * Hash implementations used by the synchronous API plus the default async WebCrypto provider.\n * Both slots are configurable API surface; wrapper helpers revalidate that providers still return\n * 64-byte SHA-512 digests.\n * @example\n * Provide a SHA-512 implementation before calling synchronous helpers.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const { publicKey } = ed.keygen();\n * ```\n */\nconst hashes = {\n sha512Async: async (message) => {\n const s = globalThis?.crypto?.subtle;\n if (!s)\n throw new Error('crypto.subtle must be defined, consider polyfill');\n return new Uint8Array(await s.digest('SHA-512', concatBytes(message)));\n },\n sha512: undefined,\n};\n// Returns the final 32-byte Ed25519 secret-key seed verbatim, generating fresh random bytes only\n// when omitted.\nconst randomSecretKey = (seed) => {\n return abytes(seed === undefined ? randomBytes() : seed, LEN, 'seed');\n};\n/**\n * Generates a secret/public keypair.\n * @param seed - Optional 32-byte Ed25519 secret-key seed, returned verbatim as `secretKey`.\n * @returns Keypair with `secretKey` and `publicKey`.\n * @throws If synchronous SHA-512 has not been configured in `hashes`. {@link Error}\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Generate a new keypair through the synchronous API after wiring SHA-512.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n * import { sha512 } from '@noble/hashes/sha2.js';\n *\n * ed.hashes.sha512 = sha512;\n * const { secretKey, publicKey } = ed.keygen();\n * ```\n */\nconst keygen = (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = getPublicKey(secretKey);\n return { secretKey, publicKey };\n};\n/**\n * Generates a secret/public keypair asynchronously.\n * @param seed - Optional 32-byte Ed25519 secret-key seed, returned verbatim as `secretKey`.\n * @returns Keypair with `secretKey` and `publicKey`.\n * @throws On wrong argument types. {@link TypeError}\n * @throws On wrong argument ranges or values. {@link RangeError}\n * @example\n * Generate a new keypair through the asynchronous WebCrypto-backed path.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const { secretKey, publicKey } = await ed.keygenAsync();\n * ```\n */\nconst keygenAsync = async (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = await getPublicKeyAsync(secretKey);\n return { secretKey, publicKey };\n};\n/**\n * Ed25519-specific key utilities.\n * `utils.getExtendedPublicKey*` expose secret-derived internals (`head`, `prefix`, `scalar`, and\n * point objects), not just public-key bytes.\n * @example\n * Generate a new Ed25519 secret key and derive the matching public key.\n *\n * ```ts\n * import * as ed from '@noble/ed25519';\n *\n * const secretKey = ed.utils.randomSecretKey();\n * const publicKey = await ed.getPublicKeyAsync(secretKey);\n * ```\n */\nconst utils = /* @__PURE__ */ freeze({\n getExtendedPublicKeyAsync,\n getExtendedPublicKey,\n randomSecretKey,\n});\n// ## Precomputes\n// --------------\n// Fixed W=8 window: 33 windows (ceil(256/8) + 1, NOT 32 - see wNAF loop), 128 points per window.\n// Layout is grouped by window: each block stores the positive multiples `1*base .. 128*base` for\n// that window, and the extra `+1` window absorbs carries from signed-digit recoding.\nconst precompute = () => {\n const points = [];\n let p = G;\n let b;\n for (let w = 0; w < 33; w++) {\n b = p;\n points.push(b);\n for (let i = 1; i < 128; i++) {\n b = b.add(p);\n points.push(b);\n } // i=1, bc we skip 0\n p = b.double();\n }\n return points;\n};\nlet Gpows = undefined; // shared process-wide cache of base-point precomputes\n// Branch-based negate helper used for JS/JIT mitigation symmetry, not a strict constant-time claim.\nconst ctneg = (cnd, p) => {\n const n = p.negate();\n return cnd ? n : p;\n};\n/**\n * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by\n * caching multiples of G (base point). Cache is stored in 32MB of RAM.\n * Any time `G.multiply` is done, precomputes are used.\n * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.\n *\n * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,\n * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.\n * Returns the real accumulator `p` plus a fake accumulator `f`; callers only care about `p`, while\n * `f` exists to keep similar work in zero-digit branches as a JS/JIT side-channel mitigation.\n *\n * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().\n */\nconst wNAF = (n) => {\n const comp = Gpows || (Gpows = precompute());\n let p = I;\n let f = G; // f must be G, or could become I in the end\n for (let w = 0; w < 33; w++) {\n let wbits = Number(n & 255n); // extract W=8 bits.\n n >>= 8n; // shift number by W=8 bits.\n // We use negative indexes to reduce size of precomputed table by 2x.\n // Instead of needing precomputes 0..256, we only calculate them for 0..128.\n // If an index > 128 is found, we do (256-index) - where 256 is next window.\n // Naive: index +127 => 127, +224 => 224\n // Optimized: index +127 => 127, +224 => 256-32\n if (wbits > 128) {\n wbits -= 256;\n n += 1n;\n }\n const off = w * 128; // offset of this window's block; also the fake-add index\n const offP = off + Math.abs(wbits) - 1; // real-add index; both offsets always evaluated\n const isOddW = w % 2 !== 0; // conditions, evaluate both; alternates fake-add sign per window\n const isNeg = wbits < 0;\n if (wbits === 0) {\n // wbits == 0 means the real index would be I: can't add it. Add window offset `off` instead.\n f = f.add(ctneg(isOddW, comp[off])); // bits are 0: add garbage to fake point\n }\n else {\n p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point\n }\n }\n if (n !== 0n)\n throw new Error('invalid wnaf');\n return { p, f }; // return both real and fake points for JIT/leakage-shape symmetry\n};\n// !! Remove the export to easily use in REPL / browser console\nexport { etc, getPublicKey, getPublicKeyAsync, hash, hashes, keygen, keygenAsync, Point, sign, signAsync, utils, verify, verifyAsync, };\n","/**\n * The public keys this build of the SDK will accept licence signatures from.\n *\n * **This file contains public keys only.** BroadPaper's private signing key\n * lives in the licence issuer's secret store and is never in this repository,\n * never in the npm package and never in a browser bundle. Publishing the\n * public half is the point: it is what lets a licence be checked with no\n * network call.\n *\n * Add a production key with:\n *\n * node scripts/licence-keys.mjs --production --key-id bp-1\n *\n * which prints the private key once, for the operator to paste into the\n * issuer's configuration, and writes the public half into this array.\n *\n * The list is an allowlist, so it is also the rotation mechanism: issue with a\n * new `keyId`, ship an SDK release trusting both, and drop the old entry once\n * every licence signed with it has expired. Licences carry their `keyId` inside\n * the signed payload, so an attacker cannot point one at a different key.\n *\n * It starts empty on purpose. A key here is trusted by every copy of the SDK in\n * the world, including production installs, which is exactly why a development\n * key must never be added to it — development keys are supplied at runtime\n * instead, through `configure({ trustedKeys })` or `BROADPAPER_TRUSTED_KEYS`,\n * so a licence signed in development cannot be honoured by a production build.\n */\nimport type { TrustedKey } from \"./types.js\";\n\nexport const TRUSTED_KEYS: readonly TrustedKey[] = [\n { keyId: \"bp-2026\", publicKey: \"woKmWyIazae7SpGhi4dwA7zNK1lWdboq88Rl5xscTs4\", note: \"production, generated 2026-09-08\" }\n];\n","/**\n * The licence certificate and the states it can be in.\n *\n * A BroadPaper licence is a signed certificate, not a secret. It says who\n * bought what and until when, BroadPaper signs it, and the SDK checks that\n * signature with a public key compiled into the package. Nothing here talks to\n * a network, reads a machine identifier or writes a file: a licence that is\n * valid on a laptop with no route to the internet is valid, full stop.\n */\n\n/**\n * Which licence was bought. Not a feature gate — both plans unlock exactly the\n * same software. The difference is who the resulting application may be put in\n * front of, which is a contractual matter and is presented as one in the\n * account area and the licence agreement.\n *\n * These are the `id`s in `shared/plans.json`, deliberately: that file is the\n * one machine-readable statement of the commercial model, and a certificate\n * that quotes a different vocabulary from the thing that priced it is a\n * certificate somebody eventually has to write a mapping table for.\n */\nexport type Plan = \"internal\" | \"saas\";\n\n/**\n * How the licence is held.\n *\n * `subscription` is a term: the right to use the software ends with the term,\n * and so does the right to updates. It is the only thing sold today.\n *\n * `perpetual` is reserved. It would mean the right to use never ends, while\n * the right to updates still does — `validUntil` null, `updatesUntil` set. The\n * field exists now so that offering one later is a change to what the issuer\n * writes rather than a change to the certificate format, which would mean\n * reissuing every licence in the field. **This SDK does not honour one**: see\n * `readPayload` in `format.ts` for why refusing is the only safe answer.\n */\nexport type LicenseType = \"subscription\" | \"perpetual\";\n\n/** The product a licence is for. Present so one signing key can serve more later. */\nexport const PRODUCT = \"broadpaper-sdk\";\n\n/**\n * The signed payload.\n *\n * `organisationId` is the durable identifier of the buying organisation — a\n * Clerk organisation id — rather than an email address, because people change\n * addresses and organisations outlive their founders. It is *not* the Creem\n * customer id, which identifies the same buyer to the payment processor and is\n * a different string; the API keeps both, and naming this one for the\n * organisation is what stops the two being confused at a glance.\n *\n * Times are epoch **seconds**, not milliseconds and not ISO strings. The\n * certificate is written by `Utf8JsonWriter` in C# and read by `JSON.parse` in\n * TypeScript, and an integer cannot disagree about a timezone suffix or a\n * fractional second the way two date serialisers can — which matters more here\n * than anywhere, because the two halves only find out they disagree when a\n * customer's licence is rejected in the field.\n *\n * Field order is load-bearing on the issuing side only: `encodeSigningInput`\n * serialises this object, and `LicenceSigner.Payload` writes the same keys in\n * the same order so a certificate is byte-identical whichever issued it.\n * Verification never re-serialises — it checks the signature over the text as\n * received — so an unknown field from a later BroadPaper is carried through\n * rather than rejected.\n */\nexport interface LicensePayload {\n /**\n * Payload schema version. Bumped only when the meaning of a field changes,\n * never to add one: `readPayload` keeps fields it does not know about, so a\n * later BroadPaper can extend the certificate without older SDKs refusing it.\n */\n schemaVersion: 1;\n /** Which signing key signed this. Lets keys be rotated without reissuing everything. */\n keyId: string;\n /**\n * BroadPaper's own identifier for *this certificate*, `lic_…`.\n *\n * One per issuance, so a renewal or an upgrade carries a new one and the\n * document it produced can be dated from it. The buyer is identified by\n * `organisationId`, which does not change.\n */\n licenseId: string;\n /** The licensed organisation's durable id. A Clerk organisation id. */\n organisationId: string;\n /** The organisation's name, for display in warnings and PDF metadata. */\n organisationName: string;\n product: typeof PRODUCT;\n plan: Plan;\n licenseType: LicenseType;\n /** Epoch seconds. */\n issuedAt: number;\n /**\n * When the right to *use* the software ends, in epoch seconds.\n *\n * Null means never, which only a perpetual licence says. A subscription\n * always carries a date.\n */\n validUntil: number | null;\n /**\n * When the right to *updates* ends, in epoch seconds.\n *\n * For a subscription this equals `validUntil` and nothing reads it: the term\n * ends, and both rights end with it. It is separate from `validUntil` because\n * for a perpetual licence the two genuinely differ, and that is the whole\n * reason the field is here before anything consults it.\n */\n updatesUntil: number;\n}\n\n/**\n * Why a licence is not being honoured, or how it is being honoured.\n *\n * These are deliberately coarse. A developer needs to know whether their PDFs\n * will carry the evaluation mark and, if so, what to do about it; a taxonomy of\n * eleven parse failures helps nobody.\n */\nexport type LicenseState =\n /** No licence was configured. The SDK works; PDFs carry the evaluation mark. */\n | \"unlicensed\"\n /** A licence was configured but could not be read, or its signature is wrong. */\n | \"invalid\"\n /** Signed by a key this build of the SDK does not trust. */\n | \"untrusted\"\n /** For a different product, or a certificate this SDK is too old to honour. */\n | \"unsupported\"\n /** Valid, signed, and inside its term. */\n | \"active\"\n /** Past `validUntil` but inside the grace period: honoured, and warned about. */\n | \"grace\"\n /** Past `validUntil` and past the grace period. */\n | \"expired\";\n\n/** The outcome of checking a licence. Everything the SDK needs to decide. */\nexport interface LicenseStatus {\n state: LicenseState;\n /** True when PDFs render clean. `active` and `grace` only. */\n licensed: boolean;\n /** The payload, when one could be read and verified. */\n payload: LicensePayload | null;\n /** Which licence was bought, when it is being honoured. */\n plan: Plan | null;\n /** When the right to use ends, when known. Null for a licence with no end. */\n validUntil: Date | null;\n /** Days until `validUntil`; negative once expired. Null when there is no end date. */\n daysRemaining: number | null;\n /**\n * A developer-facing sentence. Always present for a state that is not\n * `active`, so callers can log it without composing their own prose.\n */\n message: string | null;\n}\n\n/** A public key this build of the SDK will accept signatures from. */\nexport interface TrustedKey {\n /** Matches `keyId` in the payload. */\n keyId: string;\n /** The raw 32-byte Ed25519 public key, base64url or base64. */\n publicKey: string;\n /** Free text for the key's provenance. Never displayed to end users. */\n note?: string;\n}\n","/**\n * Offline licence verification.\n *\n * Everything here is local: a signature check against a compiled-in public key\n * and a comparison against the clock. There is no activation call, no licence\n * server and nothing to be offline from. That is a deliberate product decision\n * as much as a technical one — a report renderer that stops working because a\n * key server is down is a report renderer nobody puts in a payroll run.\n *\n * The failure modes are all *soft*. An unreadable licence never throws out of a\n * render; it produces a status whose `message` says what is wrong, and the PDF\n * comes out carrying the evaluation mark.\n */\nimport { verifyAsync } from \"@noble/ed25519\";\nimport { base64UrlToBytes, utf8ToBytes } from \"./encoding.js\";\nimport { LicenseFormatError, parseLicense } from \"./format.js\";\nimport { TRUSTED_KEYS } from \"./trusted-keys.js\";\nimport { PRODUCT, type LicensePayload, type LicenseStatus, type TrustedKey } from \"./types.js\";\n\n/**\n * How long an expired licence keeps working.\n *\n * A renewal that is a week late is an accounts payable problem, not a reason to\n * stamp a customer's month-end reports. Thirty days is long enough to cover a\n * card expiring over a holiday and short enough that it is not a second licence\n * term.\n */\nexport const DEFAULT_GRACE_PERIOD_DAYS = 30;\n\nconst DAY_MS = 86_400_000;\n\nexport interface VerifyOptions {\n /** Fixed clock. Tests and deterministic renders pass one. */\n now?: Date;\n /** Extra keys to trust, on top of the ones built into this SDK. */\n trustedKeys?: readonly TrustedKey[];\n /** Overrides {@link DEFAULT_GRACE_PERIOD_DAYS}. */\n gracePeriodDays?: number;\n}\n\n/** The status of a caller that supplied no licence at all. */\nexport function unlicensed(): LicenseStatus {\n return {\n state: \"unlicensed\",\n licensed: false,\n payload: null,\n plan: null,\n validUntil: null,\n daysRemaining: null,\n message:\n \"No BroadPaper licence is configured, so PDFs carry the evaluation watermark. Everything else works; see https://www.broadpaper.com/docs/guide/licensing.\"\n };\n}\n\nfunction failure(state: LicenseStatus[\"state\"], message: string, payload: LicensePayload | null = null): LicenseStatus {\n return {\n state,\n licensed: false,\n payload,\n plan: null,\n validUntil: payload?.validUntil != null ? new Date(payload.validUntil * 1000) : null,\n daysRemaining: null,\n message\n };\n}\n\n/**\n * Checks a licence string and reports what it entitles the caller to.\n *\n * Never throws for a bad licence: a malformed string, a forged signature and an\n * expired term are all ordinary answers, and a render is not the place to\n * discover that a config file has a typo in it.\n */\nexport async function verifyLicense(license: string | null | undefined, options: VerifyOptions = {}): Promise<LicenseStatus> {\n if (!license || !license.trim()) return unlicensed();\n\n let parsed;\n try {\n parsed = parseLicense(license);\n } catch (e) {\n if (e instanceof LicenseFormatError) {\n return failure(\n e.kind,\n e.kind === \"unsupported\"\n ? `This BroadPaper licence needs a newer version of the SDK (${e.message}). Update @broadpaper/* or the PDF will carry the evaluation watermark.`\n : `The BroadPaper licence could not be read (${e.message}), so PDFs carry the evaluation watermark.`\n );\n }\n /* c8 ignore next -- parseLicense only throws LicenseFormatError */\n throw e;\n }\n\n const { payload } = parsed;\n if (payload.product !== PRODUCT) {\n return failure(\n \"invalid\",\n `This licence is for ${JSON.stringify(payload.product)}, not the BroadPaper SDK, so PDFs carry the evaluation watermark.`,\n payload\n );\n }\n\n const key = findKey(payload.keyId, options.trustedKeys);\n if (!key) {\n return failure(\n \"untrusted\",\n `This BroadPaper licence was signed with key ${JSON.stringify(payload.keyId)}, which this build does not trust. ` +\n \"A licence issued for development is not honoured by a production build; check BROADPAPER_LICENSE points at the right one.\",\n payload\n );\n }\n\n let signatureOk = false;\n try {\n signatureOk = await verifyAsync(parsed.signature, utf8ToBytes(parsed.signedText), base64UrlToBytes(key.publicKey));\n } catch {\n // A malformed public key or a point that is not on the curve. Either way\n // this licence is not going to verify, and a render must not fail over it.\n signatureOk = false;\n }\n if (!signatureOk) {\n return failure(\"invalid\", \"This BroadPaper licence failed its signature check — it has been altered or truncated. PDFs carry the evaluation watermark.\", payload);\n }\n\n const now = options.now ?? new Date();\n\n // A licence with no end date never expires, so there is no clock to consult.\n // Nothing sold today issues one — `readPayload` refuses the only licence type\n // that would — but the field is nullable, and a null that fell through to the\n // arithmetic below would come out as 1970 and watermark a valid licence.\n if (payload.validUntil === null) {\n return { state: \"active\", licensed: true, payload, plan: payload.plan, validUntil: null, daysRemaining: null, message: null };\n }\n\n const validUntil = new Date(payload.validUntil * 1000);\n const graceDays = options.gracePeriodDays ?? DEFAULT_GRACE_PERIOD_DAYS;\n const msRemaining = validUntil.getTime() - now.getTime();\n const daysRemaining = Math.floor(msRemaining / DAY_MS);\n\n if (msRemaining > 0) {\n return {\n state: \"active\",\n licensed: true,\n payload,\n plan: payload.plan,\n validUntil,\n daysRemaining,\n message: null\n };\n }\n\n if (msRemaining > -graceDays * DAY_MS) {\n const daysOver = Math.max(1, Math.ceil(-msRemaining / DAY_MS));\n return {\n state: \"grace\",\n licensed: true,\n payload,\n plan: payload.plan,\n validUntil,\n daysRemaining,\n message:\n `The BroadPaper licence for ${payload.organisationName} expired ${daysOver} day${daysOver === 1 ? \"\" : \"s\"} ago and is inside its ${graceDays}-day grace period. ` +\n \"Renew it and copy the new licence from your account, or PDFs will start carrying the evaluation watermark.\"\n };\n }\n\n return failure(\n \"expired\",\n `The BroadPaper licence for ${payload.organisationName} expired on ${validUntil.toISOString().slice(0, 10)} and its ${graceDays}-day grace period has passed, ` +\n \"so PDFs carry the evaluation watermark. Renewing issues a new licence in your BroadPaper account.\",\n payload\n );\n}\n\nfunction findKey(keyId: string, extra: readonly TrustedKey[] | undefined): TrustedKey | undefined {\n // Runtime keys are searched first so a development key can shadow a built-in\n // one of the same name without a rebuild.\n return extra?.find((k) => k.keyId === keyId) ?? TRUSTED_KEYS.find((k) => k.keyId === keyId);\n}\n","/**\n * Configuring BroadPaper once, for the life of the process.\n *\n * import { BroadPaper } from \"@broadpaper/forme\";\n * BroadPaper.configure({ license: process.env.BROADPAPER_LICENSE });\n *\n * The licence is not a credential, so this is not a secrets API: it is the same\n * shape of thing as setting a locale. A browser bundle that carries the licence\n * string in plain text is fine — the string is a signed certificate, and\n * possessing it grants nothing beyond what its payload already says.\n *\n * Configuration is deliberately process-global rather than an argument to every\n * render. Threading a licence through `renderPdf`, the render service, the\n * batch endpoint, the .NET client and every future export path is exactly the\n * kind of plumbing that ends with one path quietly forgetting it, and a\n * customer who has paid discovering a watermark in production.\n *\n * The store hangs off a `Symbol.for` key rather than a module-level variable so\n * that two copies of this package in one dependency tree — the usual result of\n * a mixed-version install — still agree about the licence.\n */\nimport { unlicensed, verifyLicense, type VerifyOptions } from \"./verify.js\";\nimport type { LicenseStatus, TrustedKey } from \"./types.js\";\n\nexport interface BroadPaperConfig {\n /**\n * The licence string, `BP1.…`. Read from `BROADPAPER_LICENSE` when this is\n * not set and the runtime has environment variables.\n */\n license?: string | null;\n /**\n * Public keys to trust in addition to the ones built into the SDK. This is\n * how a development licence is honoured on a developer's machine without a\n * development key ever being trusted by a production build.\n */\n trustedKeys?: readonly TrustedKey[];\n /** Overrides the 30-day post-expiry grace period. Mostly for tests. */\n gracePeriodDays?: number;\n /** Where licence warnings go. Defaults to `console.warn`. */\n logger?: ((message: string) => void) | null;\n}\n\ninterface Store {\n config: BroadPaperConfig;\n /** Memoised by the licence string that produced it. */\n cache: { key: string; status: Promise<LicenseStatus> } | null;\n /** Messages already logged, so a hundred renders do not print a hundred lines. */\n logged: Set<string>;\n}\n\nconst STORE_KEY = Symbol.for(\"broadpaper.license.store\");\n\nfunction store(): Store {\n const g = globalThis as Record<symbol, unknown>;\n let s = g[STORE_KEY] as Store | undefined;\n if (!s) {\n s = { config: {}, cache: null, logged: new Set() };\n g[STORE_KEY] = s;\n }\n return s;\n}\n\n/**\n * Sets the licence and any other SDK-wide options. Call it once, at startup.\n *\n * Successive calls merge, so a host can set the licence in one place and the\n * grace period in another; passing `license: null` clears it.\n */\nexport function configure(config: BroadPaperConfig): void {\n const s = store();\n s.config = { ...s.config, ...config };\n s.cache = null;\n s.logged.clear();\n}\n\n/** What {@link configure} has been given, plus whatever the environment supplies. */\nexport function getConfig(): BroadPaperConfig {\n return { ...store().config };\n}\n\n/** Forgets the configuration entirely. Exists for tests. */\nexport function resetConfig(): void {\n const g = globalThis as Record<symbol, unknown>;\n delete g[STORE_KEY];\n}\n\n/**\n * `BroadPaper.configure({ … })`, for hosts that prefer a namespace to a bare\n * function. Both are the same store.\n */\nexport const BroadPaper = { configure, getConfig };\n\nfunction env(name: string): string | undefined {\n // Node, Deno and bundlers that inline `process.env` all satisfy this; a\n // browser without a shim simply has no environment, which is not an error.\n const p = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\n const value = p?.env?.[name];\n return value && value.trim() ? value : undefined;\n}\n\n/**\n * Keys trusted in addition to the built-in ones, from configuration and from\n * `BROADPAPER_TRUSTED_KEYS` — a JSON array of `{ keyId, publicKey }`.\n *\n * A syntax error there is reported rather than swallowed: someone setting that\n * variable is doing so on purpose, and silently ignoring it would present as\n * \"my development licence is not being honoured\" with nothing to go on.\n */\nfunction trustedKeysFromEnv(): readonly TrustedKey[] {\n const raw = env(\"BROADPAPER_TRUSTED_KEYS\");\n if (!raw) return [];\n try {\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) throw new Error(\"expected a JSON array\");\n return parsed.map((entry, i) => {\n const k = entry as Record<string, unknown>;\n if (typeof k?.keyId !== \"string\" || typeof k?.publicKey !== \"string\") throw new Error(`entry ${i} needs keyId and publicKey`);\n return { keyId: k.keyId, publicKey: k.publicKey };\n });\n } catch (e) {\n warn(`BROADPAPER_TRUSTED_KEYS could not be read (${(e as Error).message}); it is being ignored.`);\n return [];\n }\n}\n\n/** Logs a message once, whatever it takes to reach the developer. */\nexport function warn(message: string): void {\n const s = store();\n if (s.logged.has(message)) return;\n s.logged.add(message);\n const logger = s.config.logger;\n if (logger === null) return;\n const line = `[BroadPaper] ${message}`;\n if (logger) logger(line);\n else console.warn(line);\n}\n\nexport interface ResolveOptions extends VerifyOptions {\n /** A licence for this call only, overriding the configured one. */\n license?: string | null;\n}\n\n/**\n * The licence status for the current configuration.\n *\n * Memoised on the licence string, because every PDF asks and a signature check\n * per page of a five-hundred-page batch is waste. `configure` clears it, and a\n * per-call `license` bypasses it.\n *\n * Whatever the answer, any developer-facing message is logged once. That is the\n * only thing the SDK does that a caller did not ask for, and it is the\n * difference between a developer seeing \"your licence expired\" and a developer\n * seeing an unexplained watermark.\n */\nexport async function resolveLicenseStatus(options: ResolveOptions = {}): Promise<LicenseStatus> {\n const s = store();\n const config = s.config;\n const license = options.license !== undefined ? options.license : config.license ?? env(\"BROADPAPER_LICENSE\") ?? null;\n const trustedKeys = [...(options.trustedKeys ?? []), ...(config.trustedKeys ?? []), ...trustedKeysFromEnv()];\n const gracePeriodDays = options.gracePeriodDays ?? config.gracePeriodDays;\n\n if (!license) {\n const status = unlicensed();\n if (status.message) warn(status.message);\n return status;\n }\n\n const verify = (): Promise<LicenseStatus> =>\n verifyLicense(license, { ...(options.now ? { now: options.now } : {}), trustedKeys, ...(gracePeriodDays !== undefined ? { gracePeriodDays } : {}) }).then((status) => {\n if (status.message) warn(status.message);\n return status;\n });\n\n // A fixed clock is a test or a deterministic render; caching across different\n // clocks would make the grace-period boundary depend on call order.\n if (options.now || options.license !== undefined) return verify();\n\n const key = `${license}|${trustedKeys.map((k) => k.keyId).join(\",\")}|${gracePeriodDays ?? \"\"}`;\n if (s.cache?.key !== key) s.cache = { key, status: verify() };\n return s.cache.status;\n}\n","/**\n * The evaluation mark.\n *\n * This is the only thing an unlicensed BroadPaper does differently. Every\n * block, both PDF backends, the designer, data binding, pagination and the\n * render service behave identically with and without a licence; what changes is\n * that the file says, on every page, that it was produced with an evaluation\n * copy.\n *\n * It is drawn to be unmistakable in a document review and harmless to a\n * developer evaluating the product: a light diagonal line across the page,\n * behind nothing and over everything, at an opacity that leaves the report\n * entirely readable. Making the output illegible would only push people towards\n * evaluating something else.\n *\n * Each backend draws the spec with its own primitives — the Forme engine has a\n * page-native watermark node, Chromium gets a printed overlay — because a\n * single drawing implementation would mean one of them post-processing a file\n * the other had already finished, and a stamping pass that can be skipped is a\n * stamping pass that eventually is.\n */\nimport { resolveLicenseStatus, type ResolveOptions } from \"./config.js\";\nimport type { LicenseStatus } from \"./types.js\";\n\nexport interface WatermarkSpec {\n text: string;\n /** Points. The engines size the mark from this, not from the page. */\n fontSize: number;\n /** Degrees, anticlockwise from horizontal. */\n angle: number;\n /** Hex, without alpha. */\n color: string;\n /** 0–1. */\n opacity: number;\n /**\n * Where on the page it goes.\n *\n * `center` is the evaluation mark's diagonal stamp: sized from `fontSize`,\n * rotated by `angle`, across the middle of every page. It is the default and\n * the only thing `watermarkFor` ever asks for.\n *\n * `bottom` is a credit line along the foot of the page, in the bottom margin —\n * the shape a host's own commercial model usually wants. BroadPaper Cloud's\n * free plan started as a `center` mark at eight points, which is a small grey\n * sentence floating in the middle of an otherwise finished invoice: it reads\n * as a mistake rather than as a credit, and the whole point of that mark is\n * that a free user's document stays sendable.\n *\n * It is drawn in the margin rather than in the footer band deliberately, so it\n * costs no layout: a mark that changed the content height would make the\n * finished file paginate differently from the canvas the user approved.\n */\n placement?: \"center\" | \"bottom\";\n /**\n * A small mark drawn before the text, as an `image/svg+xml` data URI. `bottom`\n * only.\n *\n * Vector rather than a bitmap because it is drawn at about nine points and a\n * raster at that size is a smudge. Both backends parse the URI themselves —\n * the Forme engine's image decoder cannot read an SVG, so it is re-emitted as\n * the drawing it is.\n */\n mark?: string;\n /**\n * Where the text links to, making it a link in the file. `bottom` only, and\n * the Forme backend only — the Chromium backend stamps text into a finished\n * file and draws it unlinked.\n *\n * For a host's own credit line, whose job is to be followed: a free document a\n * business sends a client is the most-read advert the host will ever have, and\n * an address nobody can click is one hardly anybody types. The evaluation mark\n * never has one — `watermarkFor` does not set it — because that mark is there to\n * be seen, not visited.\n */\n href?: string;\n}\n\n/**\n * The mark itself.\n *\n * No dashes or typographic punctuation: the standard PDF faces carry no em\n * dash, and a theme that names a font the engine does not have falls back to\n * them, which turned \"BroadPaper — Evaluation Copy\" into \"BroadPaper\n * Evaluation Copy\" in half the documents and a question mark in the rest.\n */\nexport const EVALUATION_WATERMARK: WatermarkSpec = {\n text: \"BroadPaper Evaluation Copy\",\n fontSize: 44,\n angle: -35,\n color: \"#c8102e\",\n opacity: 0.12\n};\n\n/**\n * The mark a render should carry, or null when the licence says none.\n *\n * Backends call this rather than reading the licence status themselves, so\n * \"licensed\" and \"no watermark\" cannot drift apart.\n */\nexport async function resolveWatermark(options: ResolveOptions = {}): Promise<WatermarkSpec | null> {\n const status = await resolveLicenseStatus(options);\n return watermarkFor(status);\n}\n\n/** The pure half of {@link resolveWatermark}, for callers that already have a status. */\nexport function watermarkFor(status: LicenseStatus): WatermarkSpec | null {\n return status.licensed ? null : EVALUATION_WATERMARK;\n}\n\n/**\n * CSS that paints the mark on every `.bp-page` of a rendered document.\n *\n * Used by the Chromium backend and by the designer's print path — the two\n * places a PDF is produced by a browser rather than by the engine. `position:\n * fixed` would put it on the viewport rather than on each page, so it is an\n * absolutely positioned pseudo-element on the page box, which prints once per\n * sheet.\n *\n * `print-color-adjust` matters: without it Chromium drops the mark from the\n * printed file exactly as it drops any other background colour.\n */\nexport function watermarkCss(spec: WatermarkSpec = EVALUATION_WATERMARK): string {\n const text = spec.text.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n return [\n \".bp-page{position:relative;}\",\n \".bp-page::after{\",\n `content:\"${text}\";`,\n \"position:absolute;inset:0;\",\n \"display:flex;align-items:center;justify-content:center;\",\n \"pointer-events:none;z-index:2147483647;\",\n `transform:rotate(${spec.angle}deg);`,\n \"font-family:Helvetica,Arial,sans-serif;font-weight:700;letter-spacing:0.04em;white-space:nowrap;\",\n `font-size:${spec.fontSize}pt;color:${spec.color};opacity:${spec.opacity};`,\n \"-webkit-print-color-adjust:exact;print-color-adjust:exact;\",\n \"}\"\n ].join(\"\");\n}\n\n/**\n * The PDF Producer string for a render.\n *\n * Licensed output records the licence id. It is not a secret — it identifies a\n * customer's licence, not their account — and having it in the file means a\n * document that turns up somewhere it should not can be traced back to the\n * licence that produced it without any of the tracking a phone-home would need.\n */\nexport function producerString(status: LicenseStatus): string {\n if (!status.licensed || !status.payload) return \"BroadPaper (evaluation)\";\n return `BroadPaper (${status.payload.licenseId})`;\n}\n","import { lookup } from \"node:dns/promises\";\nimport { isIP } from \"node:net\";\n\nexport interface NetworkPolicy {\n /**\n * Hostnames (or `*.example.com` wildcards, or `*`) the renderer may fetch\n * assets from. `data:` URLs are always allowed. Default: none.\n */\n allowedHosts?: string[];\n /** Block private / loopback / link-local address ranges even for allowed hosts. Default true. */\n blockPrivateNetworks?: boolean;\n /** Maximum number of network requests per render. Default 200. */\n maxRequests?: number;\n}\n\nconst PRIVATE_V4 = [\n [/^10\\./, \"10/8\"],\n [/^127\\./, \"loopback\"],\n [/^169\\.254\\./, \"link-local\"],\n [/^172\\.(1[6-9]|2\\d|3[01])\\./, \"172.16/12\"],\n [/^192\\.168\\./, \"192.168/16\"],\n [/^0\\./, \"0/8\"],\n [/^100\\.(6[4-9]|[7-9]\\d|1[01]\\d|12[0-7])\\./, \"CGNAT\"]\n] as const;\n\nexport function isPrivateAddress(ip: string): boolean {\n const kind = isIP(ip);\n if (kind === 4) return PRIVATE_V4.some(([re]) => re.test(ip));\n if (kind === 6) {\n const lower = ip.toLowerCase();\n if (lower === \"::1\" || lower === \"::\") return true;\n if (lower.startsWith(\"fe80:\") || lower.startsWith(\"fc\") || lower.startsWith(\"fd\")) return true;\n const mapped = /^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/.exec(lower);\n if (mapped) return isPrivateAddress(mapped[1]!);\n return false;\n }\n return false;\n}\n\nexport function hostAllowed(host: string, allowed: string[] | undefined): boolean {\n if (!allowed || allowed.length === 0) return false;\n const h = host.toLowerCase();\n return allowed.some((pattern) => {\n const p = pattern.toLowerCase();\n if (p === \"*\") return true;\n if (p.startsWith(\"*.\")) return h === p.slice(2) || h.endsWith(p.slice(1));\n return h === p;\n });\n}\n\nexport interface RequestDecision {\n allow: boolean;\n reason?: string;\n}\n\n/**\n * Decides whether the headless browser may perform a request. Resolves DNS so\n * that a public hostname pointing at a private address is still blocked.\n */\nexport async function decideRequest(url: string, policy: NetworkPolicy, counter: { count: number }): Promise<RequestDecision> {\n if (url.startsWith(\"data:\") || url === \"about:blank\") return { allow: true };\n let u: URL;\n try {\n u = new URL(url);\n } catch {\n return { allow: false, reason: \"invalid URL\" };\n }\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") return { allow: false, reason: `scheme ${u.protocol} not allowed` };\n if (++counter.count > (policy.maxRequests ?? 200)) return { allow: false, reason: \"request limit exceeded\" };\n if (!hostAllowed(u.hostname, policy.allowedHosts)) return { allow: false, reason: `host ${u.hostname} not in allow-list` };\n if (policy.blockPrivateNetworks !== false) {\n const host = u.hostname.replace(/^\\[|\\]$/g, \"\");\n if (host === \"localhost\" || host.endsWith(\".localhost\") || host.endsWith(\".internal\")) return { allow: false, reason: \"private host\" };\n if (isIP(host)) {\n if (isPrivateAddress(host)) return { allow: false, reason: \"private address\" };\n } else {\n try {\n const results = await lookup(host, { all: true });\n if (results.some((r) => isPrivateAddress(r.address))) return { allow: false, reason: \"resolves to a private address\" };\n } catch {\n return { allow: false, reason: \"DNS lookup failed\" };\n }\n }\n }\n return { allow: true };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport type { Browser, BrowserContext } from \"playwright-core\";\nimport type { DataSource, ReportData, ReportTemplate, Theme } from \"@broadpaper/core\";\nimport { producerString, resolveLicenseStatus, watermarkFor, type LicenseStatus, type WatermarkSpec } from \"@broadpaper/license\";\nimport { decideRequest, type NetworkPolicy } from \"./ssrf.js\";\nimport { stampWatermark } from \"./watermark.js\";\nimport type { RuntimeRenderOutput } from \"../runtime/index.js\";\n\nexport interface PdfMetadata {\n title?: string;\n author?: string;\n subject?: string;\n keywords?: string[];\n /** Creation date. Defaults to `now`. */\n creationDate?: Date;\n}\n\nexport interface RenderPdfOptions {\n template: ReportTemplate | { schemaVersion: number; [k: string]: unknown };\n data?: ReportData;\n theme?: Partial<Theme>;\n dataSources?: DataSource[];\n /** Fixed clock for deterministic output. */\n now?: Date;\n locale?: string;\n currency?: string;\n timeZone?: string;\n metadata?: PdfMetadata;\n /**\n * JavaScript source for a browser bundle that registers custom blocks:\n * it must call `BroadPaper.registerBlocks([...])`. Built by the host with its\n * own bundler from `@broadpaper/core` block definitions.\n */\n customBlocksScript?: string;\n network?: NetworkPolicy;\n /** Per-render timeout in ms. Default 60000. */\n timeoutMs?: number;\n /** Refuse documents longer than this. Default 500. */\n maxPages?: number;\n /** Chromium tagged (accessible) PDF. Default true. */\n tagged?: boolean;\n /** PDF/A-like outline generation from headings. Default true. */\n outline?: boolean;\n /** Attach the runtime from a custom path (testing). */\n runtimePath?: string;\n /**\n * An extra mark stamped on every page, on top of whatever the licence decides.\n *\n * Additive and never a replacement, exactly as in the browserless backend: the\n * licence mark is `watermarkFor`'s to decide and a caller cannot remove it.\n * Both backends take this so that switching backend cannot quietly drop a\n * host's own mark — which, for a free tier that depends on it, would be the\n * expensive kind of silence.\n */\n watermark?: WatermarkSpec | null;\n /**\n * A licence for this render only, overriding whatever `configure` was given.\n * A service rendering for one organisation should configure once at startup\n * instead; this is for a host that renders on behalf of several.\n */\n license?: string | null;\n}\n\nexport interface RenderPdfResult {\n pdf: Buffer;\n pages: number;\n warnings: RuntimeRenderOutput[\"warnings\"];\n /** Wall-clock render time in ms. */\n durationMs: number;\n}\n\nexport class PdfRenderError extends Error {\n constructor(\n message: string,\n public readonly code: \"TIMEOUT\" | \"TOO_MANY_PAGES\" | \"RUNTIME\" | \"BROWSER\"\n ) {\n super(message);\n this.name = \"PdfRenderError\";\n }\n}\n\nlet runtimeCache: string | null = null;\n\nasync function loadRuntime(path?: string): Promise<string> {\n if (path) return readFile(path, \"utf8\");\n if (runtimeCache) return runtimeCache;\n const here = dirname(fileURLToPath(import.meta.url));\n const candidates = [join(here, \"runtime.global.js\"), join(here, \"..\", \"dist\", \"runtime.global.js\")];\n for (const c of candidates) {\n try {\n runtimeCache = await readFile(c, \"utf8\");\n return runtimeCache;\n } catch {\n /* try next */\n }\n }\n throw new PdfRenderError(\"BroadPaper runtime bundle not found. Run `pnpm --filter @broadpaper/pdf build`.\", \"RUNTIME\");\n}\n\nconst BLANK_HTML = `<!doctype html><html><head><meta charset=\"utf-8\"><title>BroadPaper</title></head><body></body></html>`;\n\n/**\n * A reusable PDF renderer bound to a Playwright browser. Each render uses a\n * fresh, isolated browser context (no cookies, storage or cache shared between\n * documents) and a strict network policy.\n */\nexport class PdfRenderer {\n constructor(private readonly browser: Browser) {}\n\n async render(opts: RenderPdfOptions): Promise<RenderPdfResult> {\n const started = Date.now();\n const timeout = opts.timeoutMs ?? 60_000;\n const runtime = await loadRuntime(opts.runtimePath);\n let context: BrowserContext | null = null;\n try {\n 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 });\n context.setDefaultTimeout(timeout);\n const counter = { count: 0 };\n const policy: NetworkPolicy = { allowedHosts: [], blockPrivateNetworks: true, maxRequests: 200, ...(opts.network ?? {}) };\n await context.route(\"**/*\", async (route) => {\n const url = route.request().url();\n const decision = await decideRequest(url, policy, counter);\n if (decision.allow) await route.continue();\n else await route.abort(\"blockedbyclient\");\n });\n\n const page = await context.newPage();\n const errors: string[] = [];\n page.on(\"pageerror\", (e) => errors.push(String(e)));\n await page.setContent(BLANK_HTML, { waitUntil: \"load\" });\n await page.addScriptTag({ content: runtime });\n if (opts.customBlocksScript) await page.addScriptTag({ content: opts.customBlocksScript });\n\n const input = {\n template: opts.template,\n data: opts.data ?? {},\n theme: opts.theme,\n dataSources: opts.dataSources ?? [],\n now: (opts.now ?? new Date()).toISOString(),\n locale: opts.locale,\n currency: opts.currency,\n timeZone: opts.timeZone,\n mode: \"preview\" as const\n };\n\n const result = (await Promise.race([\n page.evaluate(async (i) => window.BroadPaper.render(i as never), input),\n new Promise<never>((_, reject) => setTimeout(() => reject(new PdfRenderError(`Render timed out after ${timeout}ms`, \"TIMEOUT\")), timeout))\n ])) as RuntimeRenderOutput;\n\n if (errors.length) throw new PdfRenderError(`Runtime error: ${errors[0]}`, \"RUNTIME\");\n const maxPages = opts.maxPages ?? 500;\n if (result.pages > maxPages) throw new PdfRenderError(`Document has ${result.pages} pages, more than the limit of ${maxPages}`, \"TOO_MANY_PAGES\");\n\n await page.emulateMedia({ media: \"print\" });\n const pdf = await page.pdf({\n width: `${result.width}px`,\n height: `${result.height}px`,\n printBackground: true,\n preferCSSPageSize: true,\n margin: { top: 0, right: 0, bottom: 0, left: 0 },\n displayHeaderFooter: false,\n tagged: opts.tagged ?? true,\n outline: opts.outline ?? true\n });\n\n // The licence is checked here, on the way out, rather than inside the\n // page: nothing a host injects into the browser — a custom-blocks bundle,\n // its own runtime, its own CSS — sits between this and the file.\n const license = await resolveLicenseStatus(opts.license !== undefined ? { license: opts.license } : {});\n const finished = await applyMetadata(pdf, opts.metadata, opts.now, license, opts.watermark);\n return { pdf: finished, pages: result.pages, warnings: result.warnings, durationMs: Date.now() - started };\n } catch (e) {\n if (e instanceof PdfRenderError) throw e;\n throw new PdfRenderError(`Browser failure: ${(e as Error).message}`, \"BROWSER\");\n } finally {\n await context?.close().catch(() => undefined);\n }\n }\n}\n\n/**\n * Writes document metadata (Title, Author, Subject, Keywords, Producer, dates)\n * into the PDF using pdf-lib, and stamps the evaluation mark when the licence\n * calls for one. With a fixed `now` the output is byte-stable.\n *\n * The two jobs are together because this is the last time the file is open:\n * every Chromium render ends here, so a PDF that leaves this function clean was\n * produced under a licence that says it may be.\n *\n * `license` is resolved from the configured licence when it is not supplied,\n * which keeps the guarantee for a caller reaching this function directly.\n */\nexport async function applyMetadata(pdf: Buffer, meta: PdfMetadata | undefined, now?: Date, license?: LicenseStatus, extraWatermark?: WatermarkSpec | null): Promise<Buffer> {\n const { PDFDocument } = await import(\"pdf-lib\");\n const status = license ?? (await resolveLicenseStatus());\n const doc = await PDFDocument.load(pdf, { updateMetadata: false });\n const when = meta?.creationDate ?? now ?? new Date();\n // The licence mark first, then the caller's. Both are stamped; neither\n // cancels the other.\n for (const mark of [watermarkFor(status), extraWatermark]) if (mark) await stampWatermark(doc, mark);\n doc.setProducer(producerString(status));\n doc.setCreator(\"BroadPaper\");\n doc.setCreationDate(when);\n doc.setModificationDate(when);\n if (meta?.title) doc.setTitle(meta.title, { showInWindowTitleBar: true });\n if (meta?.author) doc.setAuthor(meta.author);\n if (meta?.subject) doc.setSubject(meta.subject);\n if (meta?.keywords?.length) doc.setKeywords(meta.keywords);\n const bytes = await doc.save({ useObjectStreams: true, addDefaultPage: false });\n return Buffer.from(bytes);\n}\n\nexport interface BrowserFactory {\n launch(): Promise<Browser>;\n}\n\n/**\n * Convenience: renders one PDF with a temporary browser. For servers use\n * `PdfRenderer` with a long-lived browser instead.\n */\nexport async function renderPdf(opts: RenderPdfOptions & { browser?: Browser; launch?: () => Promise<Browser> }): Promise<RenderPdfResult> {\n let browser = opts.browser;\n let own = false;\n if (!browser) {\n const launch = opts.launch ?? defaultLaunch;\n browser = await launch();\n own = true;\n }\n try {\n return await new PdfRenderer(browser).render(opts);\n } finally {\n if (own) await browser.close().catch(() => undefined);\n }\n}\n\nexport async function defaultLaunch(): Promise<Browser> {\n // Playwright is an optional peer dependency: this package is the fidelity\n // reference rather than the recommended backend, and most hosts render with\n // Forme and never launch a browser at all. Neither driver being installed is\n // therefore an ordinary configuration and not a broken install, so it has to\n // say so — the bare module resolution error names a package the host never\n // knowingly asked for.\n let mod: typeof import(\"playwright-core\");\n try {\n mod = (await import(\"playwright\").catch(() => import(\"playwright-core\"))) as typeof import(\"playwright-core\");\n } catch {\n throw new PdfRenderError(\n \"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.\",\n \"BROWSER\"\n );\n }\n return mod.chromium.launch({ headless: true, args: [\"--disable-gpu\", \"--font-render-hinting=none\", \"--disable-dev-shm-usage\"] });\n}\n","/**\n * The evaluation mark, drawn into a finished PDF.\n *\n * The browserless backend hands the engine a watermark node and lets it draw;\n * Chromium has no such notion, so the mark goes on afterwards, into the file.\n * That is deliberately the *last* thing that happens to a PDF here rather than\n * a stylesheet injected into the page: a host supplying its own custom-blocks\n * bundle, its own CSS or its own runtime can change what the page looks like,\n * and none of it can change what comes out of this function.\n *\n * One line per page, centred, rotated, at the same colour and opacity the\n * engine uses, so an evaluation PDF looks the same whichever backend produced\n * it.\n */\nimport type { PDFDocument } from \"pdf-lib\";\nimport type { WatermarkSpec } from \"@broadpaper/license\";\n\nexport async function stampWatermark(doc: PDFDocument, spec: WatermarkSpec): Promise<void> {\n const { StandardFonts, degrees, rgb } = await import(\"pdf-lib\");\n // Helvetica-Bold is one of the fourteen faces every PDF reader has, so the\n // mark needs no embedded font and adds nothing to the file size.\n const font = await doc.embedFont((spec.placement ?? \"center\") === \"bottom\" ? StandardFonts.Helvetica : StandardFonts.HelveticaBold);\n const color = hexToRgb(spec.color);\n const radians = (spec.angle * Math.PI) / 180;\n const width = font.widthOfTextAtSize(spec.text, spec.fontSize);\n const height = font.heightAtSize(spec.fontSize);\n\n /*\n * A credit line along the foot of the page.\n *\n * Centred horizontally, sitting a little above the page edge, unrotated\n * whatever `angle` says — a rotated line at eight points is a smudge, and this\n * placement exists precisely so a host's own mark can leave a document\n * sendable. The other backend draws it in the bottom margin for the same\n * reason; neither of them touches the content height.\n *\n * The mark itself is not drawn here. It is vector artwork and this is a\n * post-processing pass over a finished file with no layout to hang it off; the\n * Forme backend — the one Cloud renders on — draws both. Chromium is the\n * fidelity reference and an escalation path, and a credit line without its\n * glyph is a great deal better than a grey box where the glyph should be.\n */\n if ((spec.placement ?? \"center\") === \"bottom\") {\n for (const page of doc.getPages()) {\n const { width: pw } = page.getSize();\n page.drawText(spec.text, {\n x: (pw - width) / 2,\n y: spec.fontSize * 1.2,\n size: spec.fontSize,\n font,\n color: rgb(color.r, color.g, color.b),\n opacity: spec.opacity\n });\n }\n return;\n }\n\n for (const page of doc.getPages()) {\n const { width: pw, height: ph } = page.getSize();\n // drawText places the baseline at (x, y) and then rotates about that point,\n // so the centring has to be done in the rotated frame: walk back along the\n // text's own axis by half its length, and off it by half its height.\n const x = pw / 2 - (Math.cos(radians) * width) / 2 + (Math.sin(radians) * height) / 2;\n const y = ph / 2 - (Math.sin(radians) * width) / 2 - (Math.cos(radians) * height) / 2;\n page.drawText(spec.text, {\n x,\n y,\n size: spec.fontSize,\n font,\n color: rgb(color.r, color.g, color.b),\n opacity: spec.opacity,\n rotate: degrees(spec.angle)\n });\n }\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());\n /* c8 ignore next -- the spec's colour is a constant; this guards a host that edited it */\n if (!m) return { r: 0.78, g: 0.06, b: 0.18 };\n const n = parseInt(m[1]!, 16);\n return { r: ((n >> 16) & 255) / 255, g: ((n >> 8) & 255) / 255, b: (n & 255) / 255 };\n}\n","import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { Browser } from \"playwright-core\";\nimport { PdfRenderer, PdfRenderError, defaultLaunch, type RenderPdfOptions } from \"./render-pdf.js\";\nimport type { NetworkPolicy } from \"./ssrf.js\";\n\nexport interface PdfServerOptions {\n port?: number;\n host?: string;\n /** Shared-secret bearer token. Strongly recommended outside of local development. */\n token?: string;\n /** Maximum request body size in bytes. Default 25 MB. */\n maxBodyBytes?: number;\n /** Concurrent renders. Default 4. */\n concurrency?: number;\n /** Default network policy (request body may narrow but never widen it). */\n network?: NetworkPolicy;\n /** Custom blocks bundle (JS source) injected into every render. */\n customBlocksScript?: string;\n launch?: () => Promise<Browser>;\n timeoutMs?: number;\n maxPages?: number;\n log?: (msg: string) => void;\n}\n\nexport interface PdfServer {\n server: Server;\n port: number;\n close(): Promise<void>;\n}\n\ninterface RenderRequestBody extends Omit<RenderPdfOptions, \"now\" | \"network\" | \"customBlocksScript\" | \"runtimePath\" | \"metadata\"> {\n now?: string;\n network?: { allowedHosts?: string[] };\n metadata?: { title?: string; author?: string; subject?: string; keywords?: string[] };\n /** \"pdf\" (default) returns application/pdf; \"json\" returns { pdfBase64, pages, warnings }. */\n format?: \"pdf\" | \"json\";\n}\n\nfunction readJson(req: IncomingMessage, limit: number): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n req.on(\"data\", (c: Buffer) => {\n size += c.length;\n if (size > limit) {\n reject(new Error(\"Request body too large\"));\n req.destroy();\n return;\n }\n chunks.push(c);\n });\n req.on(\"end\", () => {\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString(\"utf8\")));\n } catch {\n reject(new Error(\"Invalid JSON\"));\n }\n });\n req.on(\"error\", reject);\n });\n}\n\nfunction send(res: ServerResponse, status: number, body: unknown, headers: Record<string, string> = {}) {\n const json = JSON.stringify(body);\n res.writeHead(status, { \"content-type\": \"application/json; charset=utf-8\", \"content-length\": Buffer.byteLength(json), ...headers });\n res.end(json);\n}\n\n/**\n * Starts a small, dependency-free HTTP service:\n * POST /render → PDF bytes (or JSON with format: \"json\")\n * GET /health → { ok, browser }\n *\n * Deploy it next to your application. Report data never leaves your network.\n */\nexport async function createPdfServer(opts: PdfServerOptions = {}): Promise<PdfServer> {\n const log = opts.log ?? (() => undefined);\n const browser = await (opts.launch ?? defaultLaunch)();\n const renderer = new PdfRenderer(browser);\n const concurrency = opts.concurrency ?? 4;\n let active = 0;\n const queue: Array<() => void> = [];\n const acquire = () =>\n new Promise<void>((resolve) => {\n if (active < concurrency) {\n active++;\n resolve();\n } else queue.push(resolve);\n });\n const release = () => {\n active--;\n const next = queue.shift();\n if (next) {\n active++;\n next();\n }\n };\n\n const server = createServer(async (req, res) => {\n const url = new URL(req.url ?? \"/\", \"http://localhost\");\n res.setHeader(\"x-content-type-options\", \"nosniff\");\n if (req.method === \"GET\" && url.pathname === \"/health\") return send(res, 200, { ok: true, browser: browser.isConnected(), active, queued: queue.length });\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, { \"access-control-allow-origin\": \"*\", \"access-control-allow-headers\": \"authorization, content-type\", \"access-control-allow-methods\": \"POST, GET, OPTIONS\" });\n return res.end();\n }\n if (req.method !== \"POST\" || url.pathname !== \"/render\") return send(res, 404, { error: \"Not found\" });\n if (opts.token) {\n const auth = req.headers.authorization ?? \"\";\n if (auth !== `Bearer ${opts.token}`) return send(res, 401, { error: \"Unauthorised\" });\n }\n let body: RenderRequestBody;\n try {\n body = (await readJson(req, opts.maxBodyBytes ?? 25 * 1024 * 1024)) as RenderRequestBody;\n } catch (e) {\n return send(res, 400, { error: (e as Error).message });\n }\n if (!body || typeof body !== \"object\" || !body.template) return send(res, 400, { error: \"Missing template\" });\n\n // Narrow the network policy: request may only restrict, never widen.\n const serverHosts = opts.network?.allowedHosts ?? [];\n const requested = body.network?.allowedHosts;\n const allowedHosts = requested ? requested.filter((h) => serverHosts.includes(\"*\") || serverHosts.includes(h)) : serverHosts;\n\n await acquire();\n const started = Date.now();\n try {\n const result = await renderer.render({\n template: body.template,\n data: body.data,\n theme: body.theme,\n dataSources: body.dataSources,\n now: body.now ? new Date(body.now) : undefined,\n locale: body.locale,\n currency: body.currency,\n timeZone: body.timeZone,\n metadata: body.metadata,\n network: { ...(opts.network ?? {}), allowedHosts },\n customBlocksScript: opts.customBlocksScript,\n timeoutMs: opts.timeoutMs,\n maxPages: opts.maxPages\n });\n log(`render ok pages=${result.pages} ms=${result.durationMs}`);\n res.setHeader(\"access-control-allow-origin\", \"*\");\n if (body.format === \"json\") return send(res, 200, { pdfBase64: result.pdf.toString(\"base64\"), pages: result.pages, warnings: result.warnings, durationMs: result.durationMs });\n 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\"` });\n res.end(result.pdf);\n } catch (e) {\n const err = e as PdfRenderError;\n log(`render failed ${err.code ?? \"\"} ${err.message} ms=${Date.now() - started}`);\n const status = err instanceof PdfRenderError ? (err.code === \"TIMEOUT\" ? 504 : err.code === \"TOO_MANY_PAGES\" ? 413 : 500) : 500;\n res.setHeader(\"access-control-allow-origin\", \"*\");\n send(res, status, { error: err.message, code: err.code ?? \"UNKNOWN\" });\n } finally {\n release();\n }\n });\n\n const port = opts.port ?? 4780;\n await new Promise<void>((resolve) => server.listen(port, opts.host ?? \"0.0.0.0\", resolve));\n const address = server.address();\n const actualPort = typeof address === \"object\" && address ? address.port : port;\n log(`BroadPaper PDF service listening on http://${opts.host ?? \"0.0.0.0\"}:${actualPort}`);\n return {\n server,\n port: actualPort,\n close: async () => {\n await new Promise<void>((resolve) => server.close(() => resolve()));\n await browser.close().catch(() => undefined);\n }\n };\n}\n"],"mappings":"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","names":["i","G","mod"]}