@jasy/pdf 1.0.0-alpha.3 → 1.0.0-alpha.4
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 +21 -0
- package/README.md +23 -13
- package/dist/api/structure.d.ts +5 -0
- package/dist/api/structure.js +8 -0
- package/dist/assets/font-data.js +17 -2
- package/dist/assets/font-data.ts +32 -2
- package/dist/crypto/security-handler.d.ts +46 -0
- package/dist/crypto/security-handler.js +129 -0
- package/dist/crypto/webcrypto.d.ts +11 -0
- package/dist/crypto/webcrypto.js +62 -0
- package/dist/renderer/pdf-renderer.js +2 -0
- package/dist/utils/md5.js +4 -5
- package/dist/utils/pdf-object-manager.d.ts +8 -0
- package/dist/utils/pdf-object-manager.js +0 -0
- package/dist/utils/ttf-subsetter.js +1 -1
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Florian Heuberger
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ account, no upload, nothing leaves your machine.
|
|
|
37
37
|
## You bring the line items. jasy does the rest.
|
|
38
38
|
|
|
39
39
|
You never compute a total, a VAT breakdown or a rounding again. You hand jasy the line items - it
|
|
40
|
-
**derives** the document totals and the EN-16931 VAT breakdown, spec-correct. That is
|
|
40
|
+
**derives** the document totals and the EN-16931 VAT breakdown, spec-correct. That is _why_ the
|
|
41
41
|
invoices validate: the amounts are correct **by construction**, so the single biggest class of
|
|
42
42
|
EN-16931 failures (the BR-CO total checks) simply cannot happen.
|
|
43
43
|
|
|
@@ -48,13 +48,23 @@ const { bytes, xml } = await renderZugferd({
|
|
|
48
48
|
number: "RE-2026-001",
|
|
49
49
|
issueDate: "2026-06-17",
|
|
50
50
|
currency: "EUR",
|
|
51
|
-
seller: {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
seller: {
|
|
52
|
+
name: "Northwind Studio GmbH",
|
|
53
|
+
vatId: "DE123456789",
|
|
54
|
+
address: { city: "Berlin", postCode: "10115", country: "DE" },
|
|
55
|
+
},
|
|
56
|
+
buyer: {
|
|
57
|
+
name: "Globex Corporation Ltd",
|
|
58
|
+
address: { city: "Munich", postCode: "80331", country: "DE" },
|
|
59
|
+
},
|
|
55
60
|
lines: [
|
|
56
|
-
{
|
|
57
|
-
|
|
61
|
+
{
|
|
62
|
+
name: "Brand identity design",
|
|
63
|
+
quantity: 2,
|
|
64
|
+
unit: "HUR",
|
|
65
|
+
netUnitPrice: 100,
|
|
66
|
+
vat: { category: "S", ratePercent: 19 },
|
|
67
|
+
},
|
|
58
68
|
],
|
|
59
69
|
});
|
|
60
70
|
// bytes -> a valid ZUGFeRD PDF/A-3 · xml -> the embedded EN-16931 XML
|
|
@@ -123,7 +133,7 @@ verify all of it:
|
|
|
123
133
|
- **Compression.** Content streams and images are FlateDecode-compressed; the spreadsheets `jasy export`
|
|
124
134
|
writes are real `.xlsx` ZIPs we deflate with our own writer and CRC32, zero dependencies.
|
|
125
135
|
- **Real font metrics.** Text is laid out with the Adobe AFM metrics of the standard-14 fonts - kerning
|
|
126
|
-
and word-wrap are
|
|
136
|
+
and word-wrap are _computed_, not guessed.
|
|
127
137
|
- **PDF/A-3, matched not approximated.** The conformance graph is hand-built and **passes veraPDF**, the
|
|
128
138
|
official ISO 19005 validator.
|
|
129
139
|
- **Byte-exact round-trips.** Generate and parse are inverses: `generate → parse → regenerate` reproduces
|
|
@@ -135,11 +145,11 @@ verify all of it:
|
|
|
135
145
|
|
|
136
146
|
## Packages
|
|
137
147
|
|
|
138
|
-
| Package
|
|
139
|
-
|
|
|
148
|
+
| Package | What it is |
|
|
149
|
+
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
140
150
|
| **[@jasy/zugferd](https://npmx.dev/@jasy/zugferd)** | ZUGFeRD / XRechnung: your data → PDF/A-3 + EN-16931 XML, with local validation. **The prize.** |
|
|
141
|
-
| **[@jasy/cli](https://npmx.dev/@jasy/cli)**
|
|
142
|
-
| **[@jasy/pdf](https://npmx.dev/@jasy/pdf)**
|
|
151
|
+
| **[@jasy/cli](https://npmx.dev/@jasy/cli)** | the `jasy` terminal: read · validate · export, headless **and** interactive |
|
|
152
|
+
| **[@jasy/pdf](https://npmx.dev/@jasy/pdf)** | the declarative, Flutter-style PDF layout engine that powers them |
|
|
143
153
|
|
|
144
154
|
---
|
|
145
155
|
|
|
@@ -158,7 +168,7 @@ verify all of it:
|
|
|
158
168
|
|
|
159
169
|
jasy targets the documents that matter here: invoices, reports, quotes, datasheets. It is **not** a
|
|
160
170
|
LaTeX / WeasyPrint replacement - no microtypography, hyphenation or bidi, and arbitrary multi-page flow
|
|
161
|
-
of
|
|
171
|
+
of _any_ content is still maturing. For e-invoices (a table, totals, a footer) it is complete - they
|
|
162
172
|
even paginate. We would rather under-promise and over-deliver in the demo above.
|
|
163
173
|
|
|
164
174
|
> **Status:** young and pre-1.0. The API can still shift between minor versions. Everything shown here
|
package/dist/api/structure.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { PDFElement } from "../elements/pdf-element.js";
|
|
|
4
4
|
import { DefaultTextStyleElement } from "../elements/layout/default-text-style-element.js";
|
|
5
5
|
import type { OverflowPolicy } from "../layout/fragmentation.js";
|
|
6
6
|
import { PageSize } from "../constants/page-sizes.js";
|
|
7
|
+
import { type EncryptOptions } from "../crypto/security-handler.js";
|
|
8
|
+
export type { EncryptOptions, Permissions } from "../crypto/security-handler.js";
|
|
7
9
|
import { StackOptions } from "./layout.js";
|
|
8
10
|
import { Insets } from "./insets.js";
|
|
9
11
|
import { TextDefaults } from "./text.js";
|
|
@@ -120,6 +122,9 @@ export interface RenderOptions {
|
|
|
120
122
|
/** What to do when content is taller than a page and cannot break: `"error"` throws (default),
|
|
121
123
|
* `"warn"` logs and clips, `"ignore"` clips silently. It is always clipped either way. */
|
|
122
124
|
onOverflow?: OverflowPolicy;
|
|
125
|
+
/** Encrypt the PDF with a password (AES-256, the newest standard). NOT compatible with PDF/A
|
|
126
|
+
* (ZUGFeRD invoices) - encrypting one throws, since PDF/A forbids encryption. */
|
|
127
|
+
encrypt?: EncryptOptions;
|
|
123
128
|
}
|
|
124
129
|
/** Renders a `Document(...)` tree to the raw PDF string. */
|
|
125
130
|
export declare function renderPdf(doc: PDFDocumentElement, options?: RenderOptions): Promise<string>;
|
package/dist/api/structure.js
CHANGED
|
@@ -7,6 +7,7 @@ import { Orientation } from "../renderer/pdf-config.js";
|
|
|
7
7
|
import { PDFDocument } from "../renderer/pdf-document-class.js";
|
|
8
8
|
import { FontStyle } from "../utils/pdf-object-manager.js";
|
|
9
9
|
import { getArrayBuffer } from "../utils/utf8-to-windows1252-encoder.js";
|
|
10
|
+
import { createSecurityHandler } from "../crypto/security-handler.js";
|
|
10
11
|
import { Column } from "./layout.js";
|
|
11
12
|
import { toEdges } from "./insets.js";
|
|
12
13
|
import { toTextStyleOverride } from "./text.js";
|
|
@@ -117,6 +118,11 @@ export async function renderPdf(doc, options) {
|
|
|
117
118
|
...options?.fonts,
|
|
118
119
|
};
|
|
119
120
|
const attachments = options?.attachments ?? [];
|
|
121
|
+
// The security handler's key derivation is async (WebCrypto), so build it here, before the sync
|
|
122
|
+
// PDFDocument constructor wires it into the object manager.
|
|
123
|
+
const securityHandler = options?.encrypt
|
|
124
|
+
? await createSecurityHandler(options.encrypt)
|
|
125
|
+
: undefined;
|
|
120
126
|
// A throwaway PDFDocument whose build() yields this tree, reusing the engine's standard
|
|
121
127
|
// font registration + config handling (the constructor does both). Custom fonts are
|
|
122
128
|
// registered here, before layout/render, so both the metrics and the backend see them.
|
|
@@ -155,6 +161,8 @@ export async function renderPdf(doc, options) {
|
|
|
155
161
|
om.setPdfVersion(options.pdfVersion);
|
|
156
162
|
if (options?.documentId)
|
|
157
163
|
om.enableDocumentId();
|
|
164
|
+
if (securityHandler)
|
|
165
|
+
om.setSecurityHandler(securityHandler);
|
|
158
166
|
}
|
|
159
167
|
build() {
|
|
160
168
|
return doc;
|