@lpdfio/lpdf 0.5.0 → 0.7.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
@@ -1,6 +1,7 @@
1
1
  # Lpdf License
2
2
 
3
3
  Copyright © 2026 Codesense LLC
4
+
4
5
  License inquiries: license@lpdf.io
5
6
 
6
7
  ---
@@ -39,13 +40,11 @@ Companies and organizations whose total annual gross revenue exceeded **1,000,00
39
40
 
40
41
  "Production environment" means any environment in which the Software processes real user data or supports live business operations, including staging environments accessible by end users.
41
42
 
42
- Organizations whose revenue crosses the 1,000,000 USD threshold have a **90-day grace period** following the close of their fiscal year to obtain a Professional or Enterprise license. During this grace period, continued use is permitted.
43
-
44
43
  ### Larger Businesses
45
44
 
46
45
  Companies and organizations whose total annual gross revenue exceeded **10,000,000 USD** in the most recent 12-month fiscal year must obtain an Enterprise License to use Lpdf in production environments.
47
46
 
48
- Organizations whose revenue crosses the 10,000,000 USD threshold have a **90-day grace period** following the close of their fiscal year to obtain an Enterprise license. During this grace period, continued use under a Professional License is permitted.
47
+ Organizations whose revenue crosses the 10,000,000 USD threshold have a **90-day grace period** following the close of their fiscal year to obtain an Enterprise license. During this grace period, continued use under a Professional License is permitted. The licensee remains subject to the terms of their existing Professional License and does not gain Enterprise rights until an Enterprise License is obtained.
49
48
 
50
49
  ### Supporting Lpdf
51
50
 
@@ -57,17 +56,21 @@ Paid licenses directly fund the continued development, maintenance, and improvem
57
56
 
58
57
  *Applies to: individuals, open-source projects, non-profit organizations, and companies with annual gross revenue under 1,000,000 USD.*
59
58
 
60
- Permission is hereby granted, free of charge, to any person or qualifying organization obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
59
+ Permission is hereby granted, free of charge, to any person or qualifying organization obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
61
60
 
62
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
61
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any redistribution of the Software must be made under the terms of this Community License and may not be sublicensed under different terms.
63
62
 
64
63
  All modifications to the Software made by the licensee remain the intellectual property of the licensee. Codesense LLC claims no ownership over modifications unless they are voluntarily submitted as contributions to the Lpdf project under a separate Contributor License Agreement.
65
64
 
66
65
  If your organization's annual gross revenue exceeds 1,000,000 USD, your rights under this Community License are automatically terminated upon expiration of the 90-day grace period described above, and you must obtain a Professional or Enterprise license before continuing to use Lpdf in production.
67
66
 
67
+ ### Governing Law
68
+
69
+ This license is governed by and construed in accordance with the laws of the State of Texas, United States, without regard to its conflict of law provisions.
70
+
68
71
  ### Disclaimer of Warranty
69
72
 
70
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL CODESENSE LLC OR ITS CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. IN NO EVENT SHALL CODESENSE LLC'S TOTAL CUMULATIVE LIABILITY TO ANY PARTY EXCEED THE GREATER OF (A) THE FEES PAID BY THAT PARTY TO CODESENSE LLC IN THE TWELVE MONTHS PRECEDING THE CLAIM, OR (B) ONE HUNDRED US DOLLARS (USD 100).
73
+ THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL CODESENSE LLC OR ITS CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. IN NO EVENT SHALL CODESENSE LLC'S TOTAL CUMULATIVE LIABILITY TO ANY PARTY EXCEED THE GREATER OF (A) THE FEES PAID BY THAT PARTY TO CODESENSE LLC IN THE TWELVE MONTHS PRECEDING THE CLAIM, OR (B) ONE HUNDRED US DOLLARS (USD 100).
71
74
 
72
75
  ---
73
76
 
@@ -97,7 +100,11 @@ Upon payment, the licensee receives a perpetual license for the version of Lpdf
97
100
 
98
101
  ### Support
99
102
 
100
- Professional License holders receive email support from Codesense LLC.
103
+ Professional License holders receive email support from Codesense LLC with a target response time of 3 business days for standard inquiries. Support terms are further detailed at lpdf.io/support.
104
+
105
+ ### Audit
106
+
107
+ Codesense LLC may, upon 30 days' written notice and no more than once per calendar year, request a written certification from the licensee confirming their applicable license tier and annual gross revenue for the most recent fiscal year. The licensee agrees to provide such certification within 15 business days of the request.
101
108
 
102
109
  ### Ownership and Modifications
103
110
 
@@ -123,9 +130,9 @@ THIS SOFTWARE IS PROVIDED "AS IS," WITHOUT A WARRANTY OF ANY KIND, EXPRESS OR IM
123
130
 
124
131
  ### Governing Law and Dispute Resolution
125
132
 
126
- This license is governed by and construed in accordance with the laws of the State of Delaware, United States, without regard to its conflict of law provisions.
133
+ This license is governed by and construed in accordance with the laws of the State of Texas, United States, without regard to its conflict of law provisions.
127
134
 
128
- Any dispute arising out of or relating to this license or the Software shall be resolved by binding arbitration administered by the American Arbitration Association under its Commercial Arbitration Rules. The arbitration shall take place in **Plano, Texas**. Judgment on the award rendered by the arbitrator may be entered in any court of competent jurisdiction.
135
+ Any dispute arising out of or relating to this license or the Software shall be resolved by binding arbitration administered by the American Arbitration Association under its Commercial Arbitration Rules. The arbitration shall take place in Plano, Texas. Judgment on the award rendered by the arbitrator may be entered in any court of competent jurisdiction.
129
136
 
130
137
  Notwithstanding the foregoing, either party may seek injunctive or other equitable relief in any court of competent jurisdiction to prevent the actual or threatened infringement, misappropriation, or violation of a party's intellectual property rights.
131
138
 
@@ -139,16 +146,16 @@ Notwithstanding the foregoing, either party may seek injunctive or other equitab
139
146
 
140
147
  Licensees agree not to make false statements of fact about Lpdf, Codesense LLC, or its contributors that are intended to cause material harm to the reputation of the project or the company. This clause does not restrict good-faith criticism, bug reports, public discussion of software deficiencies, or reviews based on the licensee's genuine experience.
141
148
 
142
- License rights may not be rented, leased, or transferred to any third party.
149
+ License rights may not be rented, leased, or transferred to any third party, except as expressly permitted under the subsidiary grant below.
143
150
 
144
151
  ### License Grant
145
152
 
146
- Subject to payment of the applicable license fee, Codesense LLC grants the licensee a non-exclusive, worldwide, royalty-free license to:
153
+ Subject to payment of the applicable license fee, Codesense LLC grants the licensee a non-exclusive, worldwide, royalty-free license for an unlimited number of developers within the licensee's organization to:
147
154
 
148
155
  - Use, copy, modify, and integrate the Software into unlimited applications and projects
149
156
  - Distribute the Software as part of compiled or packaged commercial products
150
157
  - Deploy the Software across unlimited servers, environments, and infrastructure
151
- - Issue license keys to wholly owned subsidiaries and controlled entities
158
+ - Extend license rights to wholly owned subsidiaries and entities in which the licensee holds more than 50% ownership or voting control ("Controlled Entities"), provided such Controlled Entities are identified to Codesense LLC upon request and remain subject to the terms of this license
152
159
 
153
160
  ### License Fees and Evaluation
154
161
 
@@ -158,11 +165,15 @@ Upon payment, the licensee receives a perpetual license for the version of Lpdf
158
165
 
159
166
  ### Support
160
167
 
161
- Enterprise License holders receive priority support with a defined SLA from Codesense LLC.
168
+ Enterprise License holders receive priority support from Codesense LLC. Supported response times and escalation procedures are defined in the Enterprise Support Policy at lpdf.io/support/enterprise. Custom SLA terms may be negotiated as part of a Master Service Agreement.
162
169
 
163
170
  ### Contract
164
171
 
165
- Enterprise licensees may request a Master Service Agreement (MSA) in place of the standard Terms of Service. Invoice billing is available upon request.
172
+ Enterprise licensees may request a Master Service Agreement (MSA) in place of the standard Terms of Service available at lpdf.io/terms. To initiate an MSA request, contact license@lpdf.io. The standard terms govern until a fully executed MSA is in place. Invoice billing is available upon request.
173
+
174
+ ### Audit
175
+
176
+ Codesense LLC may, upon 30 days' written notice and no more than once per calendar year, request a written certification from the licensee confirming their applicable license tier and annual gross revenue for the most recent fiscal year, and may request a list of Controlled Entities covered under the subsidiary grant. The licensee agrees to provide such certification within 15 business days of the request. For Enterprise licensees under an MSA, audit rights may be further defined therein.
166
177
 
167
178
  ### Ownership and Modifications
168
179
 
@@ -188,8 +199,14 @@ THIS SOFTWARE IS PROVIDED "AS IS," WITHOUT A WARRANTY OF ANY KIND, EXPRESS OR IM
188
199
 
189
200
  ### Governing Law and Dispute Resolution
190
201
 
191
- This license is governed by and construed in accordance with the laws of the State of Delaware, United States, without regard to its conflict of law provisions.
202
+ This license is governed by and construed in accordance with the laws of the State of Texas, United States, without regard to its conflict of law provisions.
192
203
 
193
- Any dispute arising out of or relating to this license or the Software shall be resolved by binding arbitration administered by the American Arbitration Association under its Commercial Arbitration Rules. The arbitration shall take place in **Plano, Texas**. Judgment on the award rendered by the arbitrator may be entered in any court of competent jurisdiction.
204
+ Any dispute arising out of or relating to this license or the Software shall be resolved by binding arbitration administered by the American Arbitration Association under its Commercial Arbitration Rules. The arbitration shall take place in Plano, Texas. Judgment on the award rendered by the arbitrator may be entered in any court of competent jurisdiction.
194
205
 
195
206
  Notwithstanding the foregoing, either party may seek injunctive or other equitable relief in any court of competent jurisdiction to prevent the actual or threatened infringement, misappropriation, or violation of a party's intellectual property rights.
207
+
208
+ ---
209
+
210
+ For license purchases and inquiries: license@lpdf.io
211
+
212
+ Privacy Policy: lpdf.io/privacy | Terms of Service: lpdf.io/terms | Support: lpdf.io/support
package/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  # @lpdfio/lpdf
4
4
 
5
- Node.js adapter for [Lpdf](https://lpdf.io) — an accurate, efficient, and cross-platform PDF engine.
5
+ **Node.js SDK for [Lpdf](https://lpdf.io) — PDF as Code on every platform**
6
+
7
+ You describe a document as code or XML. Lpdf renders a compact, pixel-perfect PDF — identical across platforms.
6
8
 
7
9
  ## Installation
8
10
 
@@ -13,48 +15,41 @@ npm install @lpdfio/lpdf
13
15
  ## Usage — Node.js
14
16
 
15
17
  ```ts
16
- import { LpdfEngine } from '@lpdfio/lpdf';
17
- import { readFileSync, writeFileSync } from 'node:fs';
18
-
19
- const engine = new LpdfEngine('');
20
-
21
- engine.loadFont('montserrat', readFileSync('fonts/Montserrat-Regular.ttf'));
22
- engine.loadImage('logo', readFileSync('images/logo.png'));
23
-
24
- const xml = readFileSync('document.xml', 'utf8');
25
- const pdf = await engine.renderPdf(xml);
26
-
27
- writeFileSync('output.pdf', pdf);
18
+ import { L, NoAttr } from 'lpdf'
19
+
20
+ const engine = L.engine()
21
+
22
+ const doc = L.document({ size: 'letter', margin: '48pt' }, [
23
+ L.section(NoAttr, [
24
+ L.layout(NoAttr, [
25
+ L.stack({ gap: '24pt' }, [
26
+ L.split(NoAttr, [
27
+ L.text({ fontSize: '8pt', color: '#888888' }, ['ACME CORP']),
28
+ L.text({ fontSize: '22pt', bold: 'true' }, ['Project Proposal']),
29
+ ]),
30
+ L.divider({ thickness: 'xs' }),
31
+ L.text({ fontSize: '13pt', bold: 'true' }, ['Scope of Work']),
32
+ L.flank({ gap: '12pt', align: 'start' }, [
33
+ L.text({ color: '#888888', width: '24pt' }, ['01']),
34
+ L.text(NoAttr, ['Discovery & Research']),
35
+ ]),
36
+ ]),
37
+ ]),
38
+ ]),
39
+ ])
40
+
41
+ const pdf = await engine.render(doc)
28
42
  ```
29
43
 
30
- ## Usage — Browser
31
-
32
- ```ts
33
- import { LpdfEngine } from '@lpdfio/lpdf/browser';
34
-
35
- const engine = new LpdfEngine('');
36
-
37
- const xml = `<stack><text>Hello, Lpdf</text></stack>`;
38
- const pdf = await engine.renderPdf(xml);
44
+ ## Requirements
39
45
 
40
- const blob = new Blob([pdf], { type: 'application/pdf' });
41
- window.open(URL.createObjectURL(blob));
42
- ```
43
-
44
- ## XML format
46
+ - Node.js 16+
47
+ - No external runtime dependencies — the WASM engine is embedded in the package.
45
48
 
46
- Documents are defined in a layout XML format. See the [Lpdf documentation](https://lpdf.io/docs) and [examples](https://github.com/lpdfio/lpdf/tree/main/docs/examples) for the full schema.
49
+ ## Docs
47
50
 
48
- ```xml
49
- <stack spacing="m" padding="l">
50
- <text font-size="xl" font="Montserrat-Bold">Invoice #1001</text>
51
- <grid columns="2">
52
- <text>Date</text> <text>2026-04-25</text>
53
- <text>Due</text> <text>2026-05-25</text>
54
- </grid>
55
- </stack>
56
- ```
51
+ [lpdf.io/docs/js](https://lpdf.io/docs/js)
57
52
 
58
- ## License
53
+ --
59
54
 
60
55
  Dual-licensed: Community License (free) and Commercial License (paid). See [LICENSE](LICENSE) for full terms.
package/dist/_shared.d.ts CHANGED
@@ -1,13 +1,10 @@
1
1
  /**
2
2
  * Shared types used by both the Node.js and browser entry points.
3
3
  */
4
+ /** Construction-time configuration for {@link PdfEngine}. Node has no infra options. */
5
+ export interface EngineOptions {
6
+ }
4
7
  export interface RenderOptions {
5
- /**
6
- * Pre-loaded font bytes for custom fonts referenced via <fonts src="…">.
7
- * Keys are the font names used in the document; values are raw TTF/OTF bytes.
8
- * @deprecated Pass font bytes via `LpdfEngine.loadFont()` instead.
9
- */
10
- fontBytes?: Record<string, Uint8Array>;
11
8
  /**
12
9
  * Optional ISO 8601 creation timestamp (e.g. `"2024-06-01T12:00:00"`).
13
10
  * When provided, written as `/CreationDate` in the PDF info dictionary.
package/dist/browser.js CHANGED
@@ -378,63 +378,12 @@ async function __wbg_init(module_or_path) {
378
378
  return __wbg_finalize_init(instance, module);
379
379
  }
380
380
 
381
- // src/kit.ts
382
- function attrKey(camel) {
383
- return camel.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase());
384
- }
385
- function buildAttrs(options) {
386
- const result = {};
387
- for (const [key, val] of Object.entries(options)) {
388
- if (val !== void 0) {
389
- result[attrKey(key)] = val;
390
- }
391
- }
392
- return result;
393
- }
394
- function layout(nodes = []) {
395
- return { type: "layout", nodes };
396
- }
397
- function canvas(layers = []) {
398
- return { type: "canvas", nodes: layers };
399
- }
400
- function section(input = {}) {
401
- return {
402
- type: "section",
403
- attrs: buildAttrs(input.options ?? {}),
404
- nodes: input.nodes ?? []
405
- };
406
- }
407
- function document(input = {}) {
408
- const { tokens, meta, ...restOpts } = input.options ?? {};
409
- const attrs = {
410
- ...buildAttrs(restOpts)
411
- };
412
- if (tokens !== void 0) attrs["tokens"] = tokens;
413
- if (meta !== void 0) attrs["meta"] = meta;
414
- return {
415
- version: 1,
416
- type: "document",
417
- attrs,
418
- nodes: input.sections ?? []
419
- };
420
- }
421
- var LpdfKit = Object.freeze({
422
- layout,
423
- canvas,
424
- section,
425
- document
426
- });
427
-
428
381
  // src/browser.ts
429
- async function initLpdf(wasmSource, licenseKey = "", initOptions = {}) {
382
+ var NoAttr = null;
383
+ async function initLpdf(wasmSource, licenseKey = "") {
430
384
  await __wbg_init(wasmSource);
431
385
  const fontMap = /* @__PURE__ */ new Map();
432
386
  const imageMap = /* @__PURE__ */ new Map();
433
- if (initOptions.fontBytes) {
434
- for (const [name, bytes] of Object.entries(initOptions.fontBytes)) {
435
- fontMap.set(name, bytes);
436
- }
437
- }
438
387
  return {
439
388
  loadFont(name, bytes) {
440
389
  fontMap.set(name, bytes);
@@ -442,27 +391,37 @@ async function initLpdf(wasmSource, licenseKey = "", initOptions = {}) {
442
391
  loadImage(name, bytes) {
443
392
  imageMap.set(name, bytes);
444
393
  },
445
- async renderPdf(xml, callOptions = {}) {
394
+ async render(input, callOptions = {}) {
446
395
  const engine = new LpdfEngine(licenseKey);
447
396
  for (const [name, bytes] of fontMap) {
448
397
  engine.load_font(name, bytes);
449
398
  }
450
- if (callOptions.fontBytes) {
451
- for (const [name, bytes] of Object.entries(callOptions.fontBytes)) {
452
- if (!fontMap.has(name)) engine.load_font(name, bytes);
453
- }
454
- }
455
399
  for (const [name, bytes] of imageMap) {
456
400
  engine.load_image(name, bytes);
457
401
  }
458
- const dataJson = callOptions.data != null ? JSON.stringify(callOptions.data) : null;
459
- const pdf = engine.render_pdf(xml, dataJson);
402
+ if (callOptions.createdOn) {
403
+ engine.set_created_on(callOptions.createdOn);
404
+ }
405
+ let pdf;
406
+ if (typeof input === "string") {
407
+ const dataJson = callOptions.data != null ? JSON.stringify(callOptions.data) : null;
408
+ pdf = engine.render_pdf(input, dataJson);
409
+ } else {
410
+ const wasmExt = engine;
411
+ if (typeof wasmExt.render_tree_pdf === "function") {
412
+ pdf = wasmExt.render_tree_pdf(JSON.stringify(input));
413
+ } else {
414
+ const mod = engine;
415
+ const xml = mod.constructor.kit_to_xml?.(JSON.stringify(input)) ?? "";
416
+ pdf = engine.render_pdf(xml, null);
417
+ }
418
+ }
460
419
  engine.free();
461
420
  return pdf;
462
421
  }
463
422
  };
464
423
  }
465
424
  export {
466
- LpdfKit,
425
+ NoAttr,
467
426
  initLpdf
468
427
  };
package/dist/canvas.d.ts CHANGED
@@ -100,7 +100,9 @@ export interface LpdfCanvasImgNode {
100
100
  attrs: Record<string, string>;
101
101
  }
102
102
  export type LpdfCanvasPrimitiveNode = LpdfCanvasRectNode | LpdfCanvasLineNode | LpdfCanvasEllipseNode | LpdfCanvasCircleNode | LpdfCanvasPathNode | LpdfCanvasTextNode | LpdfCanvasImgNode;
103
- export interface CanvasLayerOptions {
103
+ /** @deprecated Use {@link LayerAttr} */
104
+ export type CanvasLayerOptions = LayerAttr;
105
+ export interface LayerAttr {
104
106
  page?: PageScope | string;
105
107
  opacity?: number;
106
108
  transform?: CanvasTransform;
@@ -115,17 +117,17 @@ declare function line(x1: number, y1: number, x2: number, y2: number, style?: Ca
115
117
  declare function ellipse(cx: number, cy: number, rx: number, ry: number, style?: CanvasEllipseStyle): LpdfCanvasEllipseNode;
116
118
  declare function circle(cx: number, cy: number, r: number, style?: CanvasEllipseStyle): LpdfCanvasCircleNode;
117
119
  declare function path(d: string, style?: CanvasPathStyle): LpdfCanvasPathNode;
118
- declare function canvasText(x: number, y: number, content: string, style?: CanvasTextStyle, runs?: CanvasRun[]): LpdfCanvasTextNode;
119
- declare function img(x: number, y: number, w: number, h: number, name: string): LpdfCanvasImgNode;
120
- declare function layer(nodes: LpdfCanvasPrimitiveNode[], options?: CanvasLayerOptions): LpdfCanvasLayerNode;
120
+ declare function textAt(x: number, y: number, content: string, style?: CanvasTextStyle, runs?: CanvasRun[]): LpdfCanvasTextNode;
121
+ declare function imgAt(x: number, y: number, w: number, h: number, name: string): LpdfCanvasImgNode;
122
+ declare function layer(attrs: LayerAttr | null, nodes: LpdfCanvasPrimitiveNode[]): LpdfCanvasLayerNode;
121
123
  export declare const LpdfCanvas: Readonly<{
122
124
  rect: typeof rect;
123
125
  line: typeof line;
124
126
  ellipse: typeof ellipse;
125
127
  circle: typeof circle;
126
128
  path: typeof path;
127
- text: typeof canvasText;
128
- img: typeof img;
129
+ textAt: typeof textAt;
130
+ imgAt: typeof imgAt;
129
131
  layer: typeof layer;
130
132
  }>;
131
133
  export {};
package/dist/canvas.js CHANGED
@@ -124,7 +124,7 @@ function path(d, style) {
124
124
  attrs['line-join'] = style.lineJoin;
125
125
  return { type: 'canvas-path', attrs };
126
126
  }
127
- function canvasText(x, y, content, style, runs) {
127
+ function textAt(x, y, content, style, runs) {
128
128
  const attrs = { x: String(x), y: String(y) };
129
129
  if (style?.font !== undefined)
130
130
  attrs['font'] = style.font;
@@ -153,21 +153,21 @@ function canvasText(x, y, content, style, runs) {
153
153
  }
154
154
  return node;
155
155
  }
156
- function img(x, y, w, h, name) {
156
+ function imgAt(x, y, w, h, name) {
157
157
  return {
158
158
  type: 'canvas-img',
159
159
  attrs: { x: String(x), y: String(y), w: String(w), h: String(h), name },
160
160
  };
161
161
  }
162
- function layer(nodes, options) {
163
- const attrs = {};
164
- if (options?.page !== undefined)
165
- attrs['page'] = options.page;
166
- if (options?.opacity !== undefined)
167
- attrs['opacity'] = String(options.opacity);
168
- if (options?.transform !== undefined)
169
- attrs['transform'] = options.transform.toString();
170
- return { type: 'canvas-layer', attrs, nodes };
162
+ function layer(attrs, nodes) {
163
+ const a = {};
164
+ if (attrs?.page !== undefined)
165
+ a['page'] = attrs.page;
166
+ if (attrs?.opacity !== undefined)
167
+ a['opacity'] = String(attrs.opacity);
168
+ if (attrs?.transform !== undefined)
169
+ a['transform'] = attrs.transform.toString();
170
+ return { type: 'canvas-layer', attrs: a, nodes };
171
171
  }
172
172
  exports.LpdfCanvas = Object.freeze({
173
173
  rect,
@@ -175,7 +175,7 @@ exports.LpdfCanvas = Object.freeze({
175
175
  ellipse,
176
176
  circle,
177
177
  path,
178
- text: canvasText,
179
- img,
178
+ textAt,
179
+ imgAt,
180
180
  layer,
181
181
  });
package/dist/engine.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { RenderOptions } from './_shared';
2
- import type { LpdfDocument } from './kit';
2
+ import type { PdfDocument } from './kit';
3
3
  /** Thrown when the lpdf engine returns a layout or parse error. */
4
4
  export declare class LpdfRenderError extends Error {
5
5
  constructor(message: string);
@@ -15,7 +15,7 @@ export interface EncryptPermissions {
15
15
  assemble?: boolean;
16
16
  print_hq?: boolean;
17
17
  }
18
- /** RC4-128 encryption options passed to {@link LpdfEngine.setEncryption}. */
18
+ /** RC4-128 encryption options passed to {@link PdfEngine.setEncryption}. */
19
19
  export interface EncryptOptions {
20
20
  /** Open password shown to readers. Empty string = no open password required. */
21
21
  userPassword: string;
@@ -24,26 +24,29 @@ export interface EncryptOptions {
24
24
  /** Permission flags applied to the document. Omitted flags default to `true`. */
25
25
  permissions?: EncryptPermissions;
26
26
  }
27
- export declare class LpdfEngine {
28
- private readonly _licenseKey;
29
- private readonly _opts;
27
+ export declare class PdfEngine {
28
+ private _licenseKey;
30
29
  private readonly _fonts;
31
30
  private readonly _images;
32
31
  private _disposed;
33
32
  private _encrypt;
34
- constructor(licenseKey: string, options?: RenderOptions);
33
+ constructor();
34
+ /**
35
+ * Set the license key. Returns `this` for chaining.
36
+ */
37
+ setLicenseKey(key: string): this;
35
38
  /**
36
39
  * Register raw TTF/OTF bytes for a custom font name used in `<font src="…">`.
37
- * Call before `renderPdf`. Returns `this` for chaining.
40
+ * Call before `render`. Returns `this` for chaining.
38
41
  */
39
42
  loadFont(name: string, bytes: Uint8Array): this;
40
43
  /**
41
44
  * Register raw image bytes (PNG or JPEG) for an image name used in `<img name="…">`.
42
- * Call before `renderPdf`. Returns `this` for chaining.
45
+ * Call before `render`. Returns `this` for chaining.
43
46
  */
44
47
  loadImage(name: string, bytes: Uint8Array): this;
45
48
  /**
46
- * Configure RC4-128 encryption for all subsequent `renderPdf` calls.
49
+ * Configure RC4-128 encryption for all subsequent `render` calls.
47
50
  * Returns `this` for chaining.
48
51
  */
49
52
  setEncryption(options: EncryptOptions): this;
@@ -53,7 +56,7 @@ export declare class LpdfEngine {
53
56
  */
54
57
  clearEncryption(): this;
55
58
  /**
56
- * Release held resources. Idempotent. Subsequent `renderPdf` / `loadFont`
59
+ * Release held resources. Idempotent. Subsequent `render` / `loadFont`
57
60
  * calls after disposal will throw.
58
61
  */
59
62
  dispose(): void;
@@ -62,9 +65,9 @@ export declare class LpdfEngine {
62
65
  /**
63
66
  * Render an lpdf XML string to PDF bytes (Node.js).
64
67
  */
65
- renderPdf(input: string, callOptions?: RenderOptions): Promise<Uint8Array>;
68
+ render(input: string, callOptions?: RenderOptions): Promise<Uint8Array>;
66
69
  /**
67
- * Render an `LpdfDocument` tree (built with `LpdfKit`) to PDF bytes (Node.js).
70
+ * Render a `PdfDocument` tree (built with `Pdf.document`) to PDF bytes (Node.js).
68
71
  */
69
- renderPdf(input: LpdfDocument, callOptions?: RenderOptions): Promise<Uint8Array>;
72
+ render(input: PdfDocument, callOptions?: RenderOptions): Promise<Uint8Array>;
70
73
  }
package/dist/engine.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LpdfEngine = exports.LpdfRenderError = void 0;
3
+ exports.PdfEngine = exports.LpdfRenderError = void 0;
4
4
  const node_fs_1 = require("node:fs");
5
5
  // require() path is relative to the compiled output at dist/engine.js.
6
6
  // In the published package, wasm-pack artifacts live in dist/wasm/.
@@ -16,18 +16,25 @@ class LpdfRenderError extends Error {
16
16
  }
17
17
  }
18
18
  exports.LpdfRenderError = LpdfRenderError;
19
- class LpdfEngine {
20
- constructor(licenseKey, options = {}) {
19
+ class PdfEngine {
20
+ constructor() {
21
+ this._licenseKey = '';
21
22
  this._fonts = new Map();
22
23
  this._images = new Map();
23
24
  this._disposed = false;
24
25
  this._encrypt = null;
25
- this._licenseKey = licenseKey;
26
- this._opts = options;
26
+ }
27
+ /**
28
+ * Set the license key. Returns `this` for chaining.
29
+ */
30
+ setLicenseKey(key) {
31
+ this._throwIfDisposed();
32
+ this._licenseKey = key;
33
+ return this;
27
34
  }
28
35
  /**
29
36
  * Register raw TTF/OTF bytes for a custom font name used in `<font src="…">`.
30
- * Call before `renderPdf`. Returns `this` for chaining.
37
+ * Call before `render`. Returns `this` for chaining.
31
38
  */
32
39
  loadFont(name, bytes) {
33
40
  this._throwIfDisposed();
@@ -36,7 +43,7 @@ class LpdfEngine {
36
43
  }
37
44
  /**
38
45
  * Register raw image bytes (PNG or JPEG) for an image name used in `<img name="…">`.
39
- * Call before `renderPdf`. Returns `this` for chaining.
46
+ * Call before `render`. Returns `this` for chaining.
40
47
  */
41
48
  loadImage(name, bytes) {
42
49
  this._throwIfDisposed();
@@ -44,7 +51,7 @@ class LpdfEngine {
44
51
  return this;
45
52
  }
46
53
  /**
47
- * Configure RC4-128 encryption for all subsequent `renderPdf` calls.
54
+ * Configure RC4-128 encryption for all subsequent `render` calls.
48
55
  * Returns `this` for chaining.
49
56
  */
50
57
  setEncryption(options) {
@@ -62,7 +69,7 @@ class LpdfEngine {
62
69
  return this;
63
70
  }
64
71
  /**
65
- * Release held resources. Idempotent. Subsequent `renderPdf` / `loadFont`
72
+ * Release held resources. Idempotent. Subsequent `render` / `loadFont`
66
73
  * calls after disposal will throw.
67
74
  */
68
75
  dispose() {
@@ -71,28 +78,20 @@ class LpdfEngine {
71
78
  [Symbol.dispose]() { this.dispose(); }
72
79
  _throwIfDisposed() {
73
80
  if (this._disposed)
74
- throw new Error('LpdfEngine has been disposed.');
81
+ throw new Error('PdfEngine has been disposed.');
75
82
  }
76
- async renderPdf(input, callOptions = {}) {
83
+ async render(input, callOptions = {}) {
77
84
  this._throwIfDisposed();
78
- // Merge fonts: instance-level loadFont() calls take precedence over the
79
- // deprecated fontBytes option, which is kept for one-version compat.
80
- const allFonts = new Map(this._fonts);
81
- const extraBytes = { ...this._opts.fontBytes, ...callOptions.fontBytes };
82
- for (const [name, bytes] of Object.entries(extraBytes)) {
83
- if (!allFonts.has(name))
84
- allFonts.set(name, bytes);
85
- }
86
85
  const engine = new WasmEngine(this._licenseKey);
87
- const createdOn = callOptions.createdOn ?? this._opts.createdOn;
88
- if (createdOn) {
89
- engine.set_created_on(createdOn);
86
+ if (callOptions.createdOn) {
87
+ engine.set_created_on(callOptions.createdOn);
90
88
  }
91
89
  let pdf;
92
90
  try {
93
91
  if (typeof input === 'string') {
94
92
  // XML path — auto-load fonts and images declared via src="…".
95
93
  const xml = input;
94
+ const allFonts = new Map(this._fonts);
96
95
  for (const [key, src] of extractAssetSrcs(xml, 'font')) {
97
96
  if (!allFonts.has(key)) {
98
97
  try {
@@ -126,6 +125,7 @@ class LpdfEngine {
126
125
  else {
127
126
  // JSON (Kit tree) path — pass JSON directly to render_tree_pdf.
128
127
  const json = JSON.stringify(input);
128
+ const allFonts = new Map(this._fonts);
129
129
  for (const [key, src] of extractFontSrcsFromJson(json)) {
130
130
  if (!allFonts.has(key)) {
131
131
  try {
@@ -156,7 +156,7 @@ class LpdfEngine {
156
156
  return pdf;
157
157
  }
158
158
  }
159
- exports.LpdfEngine = LpdfEngine;
159
+ exports.PdfEngine = PdfEngine;
160
160
  // ── Helpers ───────────────────────────────────────────────────────────────────
161
161
  /** Extract `ref??name → src` pairs from `<font>` or `<image>` tags in XML. */
162
162
  function extractAssetSrcs(xml, tag) {