@broadpaper/license 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +143 -0
- package/THIRD-PARTY-NOTICES.md +255 -0
- package/dist/index.d.ts +372 -0
- package/dist/index.js +412 -0
- package/dist/index.js.map +1 -0
- package/package.json +29 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
BroadPaper — Software Licence
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Codingbadger Creative Limited, trading as BroadPaper.
|
|
4
|
+
Registered in England and Wales, company number 16896863.
|
|
5
|
+
hello@broadpaper.com
|
|
6
|
+
|
|
7
|
+
This is proprietary software, not open source. It is free to evaluate, with
|
|
8
|
+
every feature enabled and no trial clock, and requires a paid Licence for
|
|
9
|
+
production use. The full agreement is the Terms and Conditions at
|
|
10
|
+
https://www.broadpaper.com/legal/terms/ ; this notice is the part of it you need
|
|
11
|
+
in the package, and where the two differ, those Terms prevail.
|
|
12
|
+
|
|
13
|
+
Version of 9 September 2026.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
1. DEFINITIONS
|
|
17
|
+
|
|
18
|
+
"Software" means the BroadPaper packages published by us — @broadpaper/core,
|
|
19
|
+
@broadpaper/blocks, @broadpaper/renderer, @broadpaper/forme, @broadpaper/pdf,
|
|
20
|
+
@broadpaper/server, @broadpaper/license, @broadpaper/editor, @broadpaper/react,
|
|
21
|
+
@broadpaper/angular and BroadPaper.Client — together with their documentation
|
|
22
|
+
and updates.
|
|
23
|
+
|
|
24
|
+
"Licence" means a signed licence certificate we have issued to your
|
|
25
|
+
Organisation, and the rights granted with it. A Licence belongs to the
|
|
26
|
+
Organisation, not to an individual.
|
|
27
|
+
|
|
28
|
+
"Product" means an application your Organisation builds that incorporates the
|
|
29
|
+
Software.
|
|
30
|
+
|
|
31
|
+
"Internal User" means someone who works for your Organisation: an employee, an
|
|
32
|
+
officer, or a contractor engaged by you and working under your direction.
|
|
33
|
+
"External User" means anyone else, including your customers, their staff, your
|
|
34
|
+
partners and the public.
|
|
35
|
+
|
|
36
|
+
"Licence Year" means the twelve months from the date a paid Licence is issued
|
|
37
|
+
or renewed.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
2. EVALUATION
|
|
41
|
+
|
|
42
|
+
You may install and use the Software free of charge, worldwide and
|
|
43
|
+
non-exclusively, for development, testing and evaluation. Every feature is
|
|
44
|
+
enabled, nothing expires, and there is no limit on how long you take.
|
|
45
|
+
|
|
46
|
+
Documents generated without a paid Licence carry a visible BroadPaper
|
|
47
|
+
evaluation mark. This grant does not permit production use, whether or not you
|
|
48
|
+
charge for it and whether or not the mark is present in the output. Removing,
|
|
49
|
+
suppressing or circumventing the mark does not make unlicensed production use
|
|
50
|
+
permitted.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
3. PAID LICENCES
|
|
54
|
+
|
|
55
|
+
Subject to payment, we grant your Organisation a non-exclusive,
|
|
56
|
+
non-transferable, worldwide licence to install and use the Software in
|
|
57
|
+
Products, in any number of Products and for an unlimited number of users,
|
|
58
|
+
developers, documents and renders. Two types are offered, unlocking identical
|
|
59
|
+
software and differing only in who the resulting Product may be made available
|
|
60
|
+
to:
|
|
61
|
+
|
|
62
|
+
Internal — Products for your Organisation's Internal Users only.
|
|
63
|
+
SaaS / OEM — the above, and Products made available to External Users:
|
|
64
|
+
software you sell, host, embed, ship or otherwise make
|
|
65
|
+
available outside your Organisation.
|
|
66
|
+
|
|
67
|
+
Because the Software cannot and does not detect how it is deployed, which type
|
|
68
|
+
you need is determined by the use you actually make of it, not by what the
|
|
69
|
+
software permits.
|
|
70
|
+
|
|
71
|
+
A Licence runs for the Licence Year. When it ends you may continue to use any
|
|
72
|
+
version of the Software released during a Licence Year you paid for,
|
|
73
|
+
indefinitely and under this notice, but you will receive no further updates or
|
|
74
|
+
support unless you renew, and the Software stops rendering without the
|
|
75
|
+
evaluation mark once the certificate's grace period has passed.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
4. REDISTRIBUTION
|
|
79
|
+
|
|
80
|
+
You may redistribute the Software only as a compiled, integrated part of a
|
|
81
|
+
Product. You may not distribute it on its own, offer it as a component for
|
|
82
|
+
others to build with, or make its functionality available as a stand-alone
|
|
83
|
+
report-design service. The end users of your Product do not need their own
|
|
84
|
+
Licence.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
5. LICENCE CERTIFICATES
|
|
88
|
+
|
|
89
|
+
A Licence is a cryptographically signed certificate recording your
|
|
90
|
+
Organisation, its Licence type and its expiry date. The Software verifies it
|
|
91
|
+
locally, against a public key compiled into the package, and makes no network
|
|
92
|
+
call to do so.
|
|
93
|
+
|
|
94
|
+
It is not a secret, and we do not ask you to treat it as one: it may appear in
|
|
95
|
+
your application's configuration, its build and its distributed code. You may
|
|
96
|
+
not share it with anyone outside your Organisation for their own use, alter it,
|
|
97
|
+
or interfere with the Software's licence checking or its evaluation mark.
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
6. RESTRICTIONS
|
|
101
|
+
|
|
102
|
+
Except as expressly permitted above, you may not: copy, modify, translate or
|
|
103
|
+
create derivative works of the Software beyond what integrating it into your
|
|
104
|
+
Product requires; reverse engineer it beyond what applicable law allows; remove
|
|
105
|
+
any proprietary notice; use it to build a competing report designer; or use it
|
|
106
|
+
in breach of any law, including to generate documents intended to deceive.
|
|
107
|
+
|
|
108
|
+
We own the Software and everything in it that is not third-party material.
|
|
109
|
+
Nothing here transfers ownership. Your templates, your data, your themes and
|
|
110
|
+
the documents your Product produces are yours; we claim no rights in them and,
|
|
111
|
+
because the Software makes no calls to us, we never receive them.
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
7. THIRD-PARTY COMPONENTS
|
|
115
|
+
|
|
116
|
+
The Software incorporates third-party components under their own licences.
|
|
117
|
+
These are listed in the THIRD-PARTY-NOTICES.md file distributed with each
|
|
118
|
+
package — including the fonts and Rust crates statically linked into the Forme
|
|
119
|
+
engine, which no dependency manifest reveals. Those licences govern those
|
|
120
|
+
components.
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
8. NO WARRANTY, AND LIABILITY
|
|
124
|
+
|
|
125
|
+
Except for the limited ninety-day warranty in the Terms, the Software is
|
|
126
|
+
provided "AS IS", without warranty of any kind, express or implied, including
|
|
127
|
+
merchantability, fitness for a particular purpose and non-infringement. We do
|
|
128
|
+
not warrant that the Software is error-free, or that a document it produces
|
|
129
|
+
meets any regulatory or legal requirement that applies to you: that remains
|
|
130
|
+
your responsibility.
|
|
131
|
+
|
|
132
|
+
To the extent the law allows, we are not liable for any loss of profit,
|
|
133
|
+
revenue, business, data or goodwill, or for any indirect or consequential
|
|
134
|
+
loss. Our total liability in any twelve-month period is limited to the amount
|
|
135
|
+
you paid us in that period, or $100 if you paid nothing. Nothing here limits
|
|
136
|
+
liability for death or personal injury caused by negligence, for fraud, or for
|
|
137
|
+
anything else that cannot be limited by law.
|
|
138
|
+
|
|
139
|
+
This notice is governed by the law of England and Wales.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
Questions, and licence purchases: hello@broadpaper.com
|
|
143
|
+
Pricing and the full Terms: https://www.broadpaper.com/legal/terms/
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
BroadPaper is built on the work below. This file is generated by
|
|
4
|
+
`scripts/third-party-notices.mjs` from what is actually installed — including
|
|
5
|
+
the contents of the WebAssembly engine, which carries its own dependencies and
|
|
6
|
+
its own fonts inside a single binary. Do not edit it by hand.
|
|
7
|
+
|
|
8
|
+
It ships inside every published package and beside the demo, because two of the
|
|
9
|
+
licences here require their notice to travel with the software.
|
|
10
|
+
|
|
11
|
+
## The PDF engine
|
|
12
|
+
|
|
13
|
+
`@formepdf/core` and `@formepdf/shared` — the browserless layout and PDF engine,
|
|
14
|
+
Rust compiled to WebAssembly. Used unmodified, as an npm dependency.
|
|
15
|
+
|
|
16
|
+
MIT License
|
|
17
|
+
|
|
18
|
+
Copyright (c) 2026 Daniel Molitor
|
|
19
|
+
|
|
20
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
21
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
22
|
+
in the Software without restriction, including without limitation the rights
|
|
23
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
24
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
25
|
+
furnished to do so, subject to the following conditions:
|
|
26
|
+
|
|
27
|
+
The above copyright notice and this permission notice shall be included in all
|
|
28
|
+
copies or substantial portions of the Software.
|
|
29
|
+
|
|
30
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
31
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
32
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
33
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
34
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
35
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
36
|
+
SOFTWARE.
|
|
37
|
+
|
|
38
|
+
## Fonts inside the engine
|
|
39
|
+
|
|
40
|
+
The engine binary carries complete font files, and subsets of them are embedded
|
|
41
|
+
into any PDF containing a character the standard PDF faces cannot represent — a
|
|
42
|
+
Greek or Cyrillic name, a symbol. Documents produced this way are unrestricted:
|
|
43
|
+
the licence below exempts anything created *with* the font. The notice is
|
|
44
|
+
required because the font software itself travels inside the engine.
|
|
45
|
+
|
|
46
|
+
### Noto Sans Regular
|
|
47
|
+
|
|
48
|
+
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
|
49
|
+
|
|
50
|
+
Licensed under the SIL Open Font License, Version 1.1.
|
|
51
|
+
|
|
52
|
+
Its own declaration, verbatim from the font's name table:
|
|
53
|
+
|
|
54
|
+
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-
|
|
55
|
+
greek-cyrillic)Noto SansRegular2.015;GOOG;NotoSans-RegularNoto Sans RegularV
|
|
56
|
+
ersion 2.015; ttfautohint (v1.8.4.7-5d5b)NotoSans-RegularNoto is a trademark
|
|
57
|
+
of Google LLC.Monotype Imaging Inc.Monotype Design TeamDesigned by Monotype
|
|
58
|
+
design team, Irene Vlachou.http://www.google.com/get/noto/http://www.monoty
|
|
59
|
+
pe.com/studioThis Font Software is licensed under the SIL Open Font License,
|
|
60
|
+
Version 1.1. This license is available with a FAQ at: https://scripts.sil.o
|
|
61
|
+
rg/OFLhttps://scripts.sil.org/OFLflorin symbolTitling Alternates I and J for
|
|
62
|
+
titling and all cap settingsAccented Greek SCiota adscrip
|
|
63
|
+
t
|
|
64
|
+
|
|
65
|
+
### Noto Sans Bold
|
|
66
|
+
|
|
67
|
+
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
|
68
|
+
|
|
69
|
+
Licensed under the SIL Open Font License, Version 1.1.
|
|
70
|
+
|
|
71
|
+
Its own declaration, verbatim from the font's name table:
|
|
72
|
+
|
|
73
|
+
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-
|
|
74
|
+
greek-cyrillic)Noto SansBold2.015;GOOG;NotoSans-BoldNoto Sans BoldVersion 2.
|
|
75
|
+
015; ttfautohint (v1.8.4.7-5d5b)NotoSans-BoldNoto is a trademark of Google L
|
|
76
|
+
LC.Monotype Imaging Inc.Monotype Design TeamDesigned by Monotype design team
|
|
77
|
+
, Irene Vlachou.http://www.google.com/get/noto/http://www.monotype.com/studi
|
|
78
|
+
oThis Font Software is licensed under the SIL Open Font License, Version 1.1
|
|
79
|
+
. This license is available with a FAQ at: https://scripts.sil.org/OFLhttps:
|
|
80
|
+
//scripts.sil.org/OFLflorin symbolTitling Alternates I and J for titling and
|
|
81
|
+
all cap settingsAccented Greek SCiota adscrip
|
|
82
|
+
t
|
|
83
|
+
|
|
84
|
+
-----------------------------------------------------------
|
|
85
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
86
|
+
-----------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
PREAMBLE
|
|
89
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
90
|
+
development of collaborative font projects, to support the font creation
|
|
91
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
92
|
+
open framework in which fonts may be shared and improved in partnership
|
|
93
|
+
with others.
|
|
94
|
+
|
|
95
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
96
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
97
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
98
|
+
redistributed and/or sold with any software provided that any reserved
|
|
99
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
100
|
+
however, cannot be released under any other type of license. The
|
|
101
|
+
requirement for fonts to remain under this license does not apply
|
|
102
|
+
to any document created using the fonts or their derivatives.
|
|
103
|
+
|
|
104
|
+
DEFINITIONS
|
|
105
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
106
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
107
|
+
include source files, build scripts and documentation.
|
|
108
|
+
|
|
109
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
110
|
+
copyright statement(s).
|
|
111
|
+
|
|
112
|
+
"Original Version" refers to the collection of Font Software components as
|
|
113
|
+
distributed by the Copyright Holder(s).
|
|
114
|
+
|
|
115
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
116
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
117
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
118
|
+
new environment.
|
|
119
|
+
|
|
120
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
121
|
+
writer or other person who contributed to the Font Software.
|
|
122
|
+
|
|
123
|
+
PERMISSION & CONDITIONS
|
|
124
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
125
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
126
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
127
|
+
Software, subject to the following conditions:
|
|
128
|
+
|
|
129
|
+
1) Neither the Font Software nor any of its individual components,
|
|
130
|
+
in Original or Modified Versions, may be sold by itself.
|
|
131
|
+
|
|
132
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
133
|
+
redistributed and/or sold with any software, provided that each copy
|
|
134
|
+
contains the above copyright notice and this license. These can be
|
|
135
|
+
included either as stand-alone text files, human-readable headers or
|
|
136
|
+
in the appropriate machine-readable metadata fields within text or
|
|
137
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
138
|
+
|
|
139
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
140
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
141
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
142
|
+
presented to the users.
|
|
143
|
+
|
|
144
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
145
|
+
Software shall not be used to promote, endorse or advertise any
|
|
146
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
147
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
148
|
+
permission.
|
|
149
|
+
|
|
150
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
151
|
+
must be distributed entirely under this license, and must not be
|
|
152
|
+
distributed under any other license. The requirement for fonts to
|
|
153
|
+
remain under this license does not apply to any document created
|
|
154
|
+
using the Font Software.
|
|
155
|
+
|
|
156
|
+
TERMINATION
|
|
157
|
+
This license becomes null and void if any of the above conditions are
|
|
158
|
+
not met.
|
|
159
|
+
|
|
160
|
+
DISCLAIMER
|
|
161
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
162
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
163
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
164
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
165
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
166
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
167
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
168
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
169
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
170
|
+
|
|
171
|
+
## Rust crates inside the engine
|
|
172
|
+
|
|
173
|
+
These 38 crates are statically linked into the engine binary and are
|
|
174
|
+
therefore redistributed with it. The list is read out of the compiled artefact
|
|
175
|
+
rather than from a manifest, so it reflects what is genuinely in there.
|
|
176
|
+
|
|
177
|
+
- aho-corasick-1.1.4
|
|
178
|
+
- barcoders-2.0.0
|
|
179
|
+
- base64-0.22.1
|
|
180
|
+
- base64ct-1.8.3
|
|
181
|
+
- console_error_panic_hook-0.1.7
|
|
182
|
+
- const-oid-0.9.6
|
|
183
|
+
- der-0.7.10
|
|
184
|
+
- fdeflate-0.3.7
|
|
185
|
+
- hypher-0.1.6
|
|
186
|
+
- image-0.24.9
|
|
187
|
+
- itoa-1.0.17
|
|
188
|
+
- jpeg-decoder-0.3.2
|
|
189
|
+
- memchr-2.8.0
|
|
190
|
+
- miniz_oxide-0.7.4
|
|
191
|
+
- num-bigint-dig-0.8.6
|
|
192
|
+
- num-integer-0.1.46
|
|
193
|
+
- pem-rfc7468-0.7.0
|
|
194
|
+
- png-0.17.16
|
|
195
|
+
- qrcode-0.14.1
|
|
196
|
+
- quick-xml-0.37.5
|
|
197
|
+
- regex-1.12.3
|
|
198
|
+
- regex-automata-0.4.14
|
|
199
|
+
- regex-syntax-0.8.10
|
|
200
|
+
- rsa-0.9.10
|
|
201
|
+
- rustybuzz-0.20.1
|
|
202
|
+
- serde-1.0.228
|
|
203
|
+
- serde-wasm-bindgen-0.6.5
|
|
204
|
+
- serde_core-1.0.228
|
|
205
|
+
- serde_json-1.0.149
|
|
206
|
+
- signature-2.2.0
|
|
207
|
+
- smallvec-1.15.1
|
|
208
|
+
- ttf-parser-0.25.1
|
|
209
|
+
- unicode-bidi-0.3.18
|
|
210
|
+
- unicode-bidi-mirroring-0.4.0
|
|
211
|
+
- unicode-linebreak-0.1.5
|
|
212
|
+
- unicode-properties-0.1.4
|
|
213
|
+
- unicode-script-0.5.8
|
|
214
|
+
- wasm-bindgen-0.2.108
|
|
215
|
+
|
|
216
|
+
## npm dependencies
|
|
217
|
+
|
|
218
|
+
Runtime dependencies of the published packages. A consumer installs these from
|
|
219
|
+
npm themselves, under the licences their own packages carry.
|
|
220
|
+
|
|
221
|
+
| Package | Version | Licence |
|
|
222
|
+
| --- | --- | --- |
|
|
223
|
+
| `@floating-ui/react` | 0.27.20 | MIT |
|
|
224
|
+
| `@formepdf/core` | 0.20.0 | MIT |
|
|
225
|
+
| `@formepdf/shared` | 0.20.0 | MIT |
|
|
226
|
+
| `@noble/ed25519` | 3.2.0 | MIT |
|
|
227
|
+
| `d3-scale` | 4.0.2 | ISC |
|
|
228
|
+
| `d3-shape` | 3.2.0 | ISC |
|
|
229
|
+
| `immer` | 10.2.0 | MIT |
|
|
230
|
+
| `lucide-react` | 0.469.0 | ISC |
|
|
231
|
+
| `pdf-lib` | 1.17.1 | MIT |
|
|
232
|
+
| `prosemirror-commands` | 1.7.2 | MIT |
|
|
233
|
+
| `prosemirror-history` | 1.5.0 | MIT |
|
|
234
|
+
| `prosemirror-keymap` | 1.2.3 | MIT |
|
|
235
|
+
| `prosemirror-model` | 1.25.11 | MIT |
|
|
236
|
+
| `prosemirror-schema-list` | 1.5.1 | MIT |
|
|
237
|
+
| `prosemirror-state` | 1.4.4 | MIT |
|
|
238
|
+
| `prosemirror-view` | 1.42.3 | MIT |
|
|
239
|
+
| `react` | 19.2.8 | MIT |
|
|
240
|
+
| `react-dom` | 19.2.8 | MIT |
|
|
241
|
+
| `tslib` | 2.8.1 | 0BSD |
|
|
242
|
+
| `zod` | 3.25.76 | MIT |
|
|
243
|
+
|
|
244
|
+
### A note on the Chromium backend
|
|
245
|
+
|
|
246
|
+
`@broadpaper/pdf` drives headless Chromium through Playwright, which is an
|
|
247
|
+
optional peer dependency: it is absent from the table above because the host
|
|
248
|
+
installs it deliberately, not because the backend stopped needing it.
|
|
249
|
+
`playwright-core` is Apache-2.0, but it *downloads a browser build separately
|
|
250
|
+
at install time*. That browser is covered by nothing here: it carries its own
|
|
251
|
+
licences, several of them, and they are not ours to restate. Anyone shipping an
|
|
252
|
+
image built on that backend needs to carry Chromium's notices too. The
|
|
253
|
+
browserless engine named at the top of this file has no such tail, which is one
|
|
254
|
+
of the reasons it is the recommended backend.
|
|
255
|
+
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The licence certificate and the states it can be in.
|
|
3
|
+
*
|
|
4
|
+
* A BroadPaper licence is a signed certificate, not a secret. It says who
|
|
5
|
+
* bought what and until when, BroadPaper signs it, and the SDK checks that
|
|
6
|
+
* signature with a public key compiled into the package. Nothing here talks to
|
|
7
|
+
* a network, reads a machine identifier or writes a file: a licence that is
|
|
8
|
+
* valid on a laptop with no route to the internet is valid, full stop.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* What the licence permits. Not a feature gate — both entitlements unlock
|
|
12
|
+
* exactly the same software. The difference is who the resulting application
|
|
13
|
+
* may be put in front of, which is a contractual matter and is presented as
|
|
14
|
+
* one in the account area and the licence agreement.
|
|
15
|
+
*/
|
|
16
|
+
type Entitlement = "internal" | "saas";
|
|
17
|
+
/** The product a licence is for. Present so one signing key can serve more later. */
|
|
18
|
+
declare const PRODUCT = "broadpaper-sdk";
|
|
19
|
+
/**
|
|
20
|
+
* The signed payload.
|
|
21
|
+
*
|
|
22
|
+
* `customerId` is the durable identifier of the buying organisation — a Clerk
|
|
23
|
+
* organisation id — rather than an email address, because people change
|
|
24
|
+
* addresses and organisations outlive their founders.
|
|
25
|
+
*
|
|
26
|
+
* Times are epoch **seconds**, not milliseconds: the payload is base64'd into
|
|
27
|
+
* a string a developer will paste into a config file, and three characters per
|
|
28
|
+
* timestamp is three characters.
|
|
29
|
+
*/
|
|
30
|
+
interface LicensePayload {
|
|
31
|
+
/** Payload schema version. Bumped only when the meaning of a field changes. */
|
|
32
|
+
version: 1;
|
|
33
|
+
/** Which signing key signed this. Lets keys be rotated without reissuing everything. */
|
|
34
|
+
keyId: string;
|
|
35
|
+
/**
|
|
36
|
+
* BroadPaper's own identifier for *this certificate*, `lic_…`.
|
|
37
|
+
*
|
|
38
|
+
* One per issuance, so a renewal or an upgrade carries a new one and the
|
|
39
|
+
* document it produced can be dated from it. The customer is identified by
|
|
40
|
+
* `customerId`, which does not change.
|
|
41
|
+
*/
|
|
42
|
+
licenseId: string;
|
|
43
|
+
/** The licensed organisation's durable id. */
|
|
44
|
+
customerId: string;
|
|
45
|
+
/** The organisation's name, for display in warnings and PDF metadata. */
|
|
46
|
+
customerName: string;
|
|
47
|
+
product: typeof PRODUCT;
|
|
48
|
+
entitlement: Entitlement;
|
|
49
|
+
/** Epoch seconds. */
|
|
50
|
+
issuedAt: number;
|
|
51
|
+
/** Epoch seconds. */
|
|
52
|
+
expiresAt: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Why a licence is not being honoured, or how it is being honoured.
|
|
56
|
+
*
|
|
57
|
+
* These are deliberately coarse. A developer needs to know whether their PDFs
|
|
58
|
+
* will carry the evaluation mark and, if so, what to do about it; a taxonomy of
|
|
59
|
+
* eleven parse failures helps nobody.
|
|
60
|
+
*/
|
|
61
|
+
type LicenseState =
|
|
62
|
+
/** No licence was configured. The SDK works; PDFs carry the evaluation mark. */
|
|
63
|
+
"unlicensed"
|
|
64
|
+
/** A licence was configured but could not be read, or its signature is wrong. */
|
|
65
|
+
| "invalid"
|
|
66
|
+
/** Signed by a key this build of the SDK does not trust. */
|
|
67
|
+
| "untrusted"
|
|
68
|
+
/** For a different product, or a payload version this SDK is older than. */
|
|
69
|
+
| "unsupported"
|
|
70
|
+
/** Valid, signed, and inside its term. */
|
|
71
|
+
| "active"
|
|
72
|
+
/** Past `expiresAt` but inside the grace period: honoured, and warned about. */
|
|
73
|
+
| "grace"
|
|
74
|
+
/** Past `expiresAt` and past the grace period. */
|
|
75
|
+
| "expired";
|
|
76
|
+
/** The outcome of checking a licence. Everything the SDK needs to decide. */
|
|
77
|
+
interface LicenseStatus {
|
|
78
|
+
state: LicenseState;
|
|
79
|
+
/** True when PDFs render clean. `active` and `grace` only. */
|
|
80
|
+
licensed: boolean;
|
|
81
|
+
/** The payload, when one could be read and verified. */
|
|
82
|
+
payload: LicensePayload | null;
|
|
83
|
+
/** What the licence permits, when it is being honoured. */
|
|
84
|
+
entitlement: Entitlement | null;
|
|
85
|
+
/** Expiry as a Date, when known. */
|
|
86
|
+
expiresAt: Date | null;
|
|
87
|
+
/** Days until expiry; negative once expired. Null when there is no licence. */
|
|
88
|
+
daysRemaining: number | null;
|
|
89
|
+
/**
|
|
90
|
+
* A developer-facing sentence. Always present for a state that is not
|
|
91
|
+
* `active`, so callers can log it without composing their own prose.
|
|
92
|
+
*/
|
|
93
|
+
message: string | null;
|
|
94
|
+
}
|
|
95
|
+
/** A public key this build of the SDK will accept signatures from. */
|
|
96
|
+
interface TrustedKey {
|
|
97
|
+
/** Matches `keyId` in the payload. */
|
|
98
|
+
keyId: string;
|
|
99
|
+
/** The raw 32-byte Ed25519 public key, base64url or base64. */
|
|
100
|
+
publicKey: string;
|
|
101
|
+
/** Free text for the key's provenance. Never displayed to end users. */
|
|
102
|
+
note?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* How long an expired licence keeps working.
|
|
107
|
+
*
|
|
108
|
+
* A renewal that is a week late is an accounts payable problem, not a reason to
|
|
109
|
+
* stamp a customer's month-end reports. Thirty days is long enough to cover a
|
|
110
|
+
* card expiring over a holiday and short enough that it is not a second licence
|
|
111
|
+
* term.
|
|
112
|
+
*/
|
|
113
|
+
declare const DEFAULT_GRACE_PERIOD_DAYS = 30;
|
|
114
|
+
interface VerifyOptions {
|
|
115
|
+
/** Fixed clock. Tests and deterministic renders pass one. */
|
|
116
|
+
now?: Date;
|
|
117
|
+
/** Extra keys to trust, on top of the ones built into this SDK. */
|
|
118
|
+
trustedKeys?: readonly TrustedKey[];
|
|
119
|
+
/** Overrides {@link DEFAULT_GRACE_PERIOD_DAYS}. */
|
|
120
|
+
gracePeriodDays?: number;
|
|
121
|
+
}
|
|
122
|
+
/** The status of a caller that supplied no licence at all. */
|
|
123
|
+
declare function unlicensed(): LicenseStatus;
|
|
124
|
+
/**
|
|
125
|
+
* Checks a licence string and reports what it entitles the caller to.
|
|
126
|
+
*
|
|
127
|
+
* Never throws for a bad licence: a malformed string, a forged signature and an
|
|
128
|
+
* expired term are all ordinary answers, and a render is not the place to
|
|
129
|
+
* discover that a config file has a typo in it.
|
|
130
|
+
*/
|
|
131
|
+
declare function verifyLicense(license: string | null | undefined, options?: VerifyOptions): Promise<LicenseStatus>;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Configuring BroadPaper once, for the life of the process.
|
|
135
|
+
*
|
|
136
|
+
* import { BroadPaper } from "@broadpaper/forme";
|
|
137
|
+
* BroadPaper.configure({ license: process.env.BROADPAPER_LICENSE });
|
|
138
|
+
*
|
|
139
|
+
* The licence is not a credential, so this is not a secrets API: it is the same
|
|
140
|
+
* shape of thing as setting a locale. A browser bundle that carries the licence
|
|
141
|
+
* string in plain text is fine — the string is a signed certificate, and
|
|
142
|
+
* possessing it grants nothing beyond what its payload already says.
|
|
143
|
+
*
|
|
144
|
+
* Configuration is deliberately process-global rather than an argument to every
|
|
145
|
+
* render. Threading a licence through `renderPdf`, the render service, the
|
|
146
|
+
* batch endpoint, the .NET client and every future export path is exactly the
|
|
147
|
+
* kind of plumbing that ends with one path quietly forgetting it, and a
|
|
148
|
+
* customer who has paid discovering a watermark in production.
|
|
149
|
+
*
|
|
150
|
+
* The store hangs off a `Symbol.for` key rather than a module-level variable so
|
|
151
|
+
* that two copies of this package in one dependency tree — the usual result of
|
|
152
|
+
* a mixed-version install — still agree about the licence.
|
|
153
|
+
*/
|
|
154
|
+
|
|
155
|
+
interface BroadPaperConfig {
|
|
156
|
+
/**
|
|
157
|
+
* The licence string, `BP1.…`. Read from `BROADPAPER_LICENSE` when this is
|
|
158
|
+
* not set and the runtime has environment variables.
|
|
159
|
+
*/
|
|
160
|
+
license?: string | null;
|
|
161
|
+
/**
|
|
162
|
+
* Public keys to trust in addition to the ones built into the SDK. This is
|
|
163
|
+
* how a development licence is honoured on a developer's machine without a
|
|
164
|
+
* development key ever being trusted by a production build.
|
|
165
|
+
*/
|
|
166
|
+
trustedKeys?: readonly TrustedKey[];
|
|
167
|
+
/** Overrides the 30-day post-expiry grace period. Mostly for tests. */
|
|
168
|
+
gracePeriodDays?: number;
|
|
169
|
+
/** Where licence warnings go. Defaults to `console.warn`. */
|
|
170
|
+
logger?: ((message: string) => void) | null;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Sets the licence and any other SDK-wide options. Call it once, at startup.
|
|
174
|
+
*
|
|
175
|
+
* Successive calls merge, so a host can set the licence in one place and the
|
|
176
|
+
* grace period in another; passing `license: null` clears it.
|
|
177
|
+
*/
|
|
178
|
+
declare function configure(config: BroadPaperConfig): void;
|
|
179
|
+
/** What {@link configure} has been given, plus whatever the environment supplies. */
|
|
180
|
+
declare function getConfig(): BroadPaperConfig;
|
|
181
|
+
/** Forgets the configuration entirely. Exists for tests. */
|
|
182
|
+
declare function resetConfig(): void;
|
|
183
|
+
/**
|
|
184
|
+
* `BroadPaper.configure({ … })`, for hosts that prefer a namespace to a bare
|
|
185
|
+
* function. Both are the same store.
|
|
186
|
+
*/
|
|
187
|
+
declare const BroadPaper: {
|
|
188
|
+
configure: typeof configure;
|
|
189
|
+
getConfig: typeof getConfig;
|
|
190
|
+
};
|
|
191
|
+
/** Logs a message once, whatever it takes to reach the developer. */
|
|
192
|
+
declare function warn(message: string): void;
|
|
193
|
+
interface ResolveOptions extends VerifyOptions {
|
|
194
|
+
/** A licence for this call only, overriding the configured one. */
|
|
195
|
+
license?: string | null;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* The licence status for the current configuration.
|
|
199
|
+
*
|
|
200
|
+
* Memoised on the licence string, because every PDF asks and a signature check
|
|
201
|
+
* per page of a five-hundred-page batch is waste. `configure` clears it, and a
|
|
202
|
+
* per-call `license` bypasses it.
|
|
203
|
+
*
|
|
204
|
+
* Whatever the answer, any developer-facing message is logged once. That is the
|
|
205
|
+
* only thing the SDK does that a caller did not ask for, and it is the
|
|
206
|
+
* difference between a developer seeing "your licence expired" and a developer
|
|
207
|
+
* seeing an unexplained watermark.
|
|
208
|
+
*/
|
|
209
|
+
declare function resolveLicenseStatus(options?: ResolveOptions): Promise<LicenseStatus>;
|
|
210
|
+
|
|
211
|
+
/** The only string format this SDK can read. */
|
|
212
|
+
declare const FORMAT_PREFIX = "BP1";
|
|
213
|
+
/** A licence string split into its parts, before any signature check. */
|
|
214
|
+
interface ParsedLicense {
|
|
215
|
+
prefix: string;
|
|
216
|
+
/** The exact text that was signed. */
|
|
217
|
+
signedText: string;
|
|
218
|
+
encodedPayload: string;
|
|
219
|
+
signature: Uint8Array;
|
|
220
|
+
payload: LicensePayload;
|
|
221
|
+
}
|
|
222
|
+
declare class LicenseFormatError extends Error {
|
|
223
|
+
/** `unsupported` when the licence is well-formed but newer than this SDK. */
|
|
224
|
+
readonly kind: "invalid" | "unsupported";
|
|
225
|
+
constructor(message: string,
|
|
226
|
+
/** `unsupported` when the licence is well-formed but newer than this SDK. */
|
|
227
|
+
kind?: "invalid" | "unsupported");
|
|
228
|
+
}
|
|
229
|
+
/** Whitespace is stripped: licences get pasted, wrapped and indented. */
|
|
230
|
+
declare function normalizeLicense(license: string): string;
|
|
231
|
+
/**
|
|
232
|
+
* Reads a licence string without verifying it.
|
|
233
|
+
*
|
|
234
|
+
* Nothing here decides whether a licence is *honoured* — that needs the
|
|
235
|
+
* signature — but a structurally broken string can be rejected before any
|
|
236
|
+
* cryptography happens, and the account UI can display a licence's contents
|
|
237
|
+
* without holding a public key.
|
|
238
|
+
*/
|
|
239
|
+
declare function parseLicense(license: string): ParsedLicense;
|
|
240
|
+
/**
|
|
241
|
+
* Encodes a payload into the text that gets signed.
|
|
242
|
+
*
|
|
243
|
+
* Exported because BroadPaper's own licence issuer must produce byte-identical
|
|
244
|
+
* input to what the SDK verifies, and the only way to guarantee that is for
|
|
245
|
+
* both to call this function.
|
|
246
|
+
*/
|
|
247
|
+
declare function encodeSigningInput(payload: LicensePayload): {
|
|
248
|
+
signedText: string;
|
|
249
|
+
encodedPayload: string;
|
|
250
|
+
};
|
|
251
|
+
/** Assembles the final licence string from a payload and its signature. */
|
|
252
|
+
declare function formatLicense(payload: LicensePayload, signature: Uint8Array): string;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* The evaluation mark.
|
|
256
|
+
*
|
|
257
|
+
* This is the only thing an unlicensed BroadPaper does differently. Every
|
|
258
|
+
* block, both PDF backends, the designer, data binding, pagination and the
|
|
259
|
+
* render service behave identically with and without a licence; what changes is
|
|
260
|
+
* that the file says, on every page, that it was produced with an evaluation
|
|
261
|
+
* copy.
|
|
262
|
+
*
|
|
263
|
+
* It is drawn to be unmistakable in a document review and harmless to a
|
|
264
|
+
* developer evaluating the product: a light diagonal line across the page,
|
|
265
|
+
* behind nothing and over everything, at an opacity that leaves the report
|
|
266
|
+
* entirely readable. Making the output illegible would only push people towards
|
|
267
|
+
* evaluating something else.
|
|
268
|
+
*
|
|
269
|
+
* Each backend draws the spec with its own primitives — the Forme engine has a
|
|
270
|
+
* page-native watermark node, Chromium gets a printed overlay — because a
|
|
271
|
+
* single drawing implementation would mean one of them post-processing a file
|
|
272
|
+
* the other had already finished, and a stamping pass that can be skipped is a
|
|
273
|
+
* stamping pass that eventually is.
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
interface WatermarkSpec {
|
|
277
|
+
text: string;
|
|
278
|
+
/** Points. The engines size the mark from this, not from the page. */
|
|
279
|
+
fontSize: number;
|
|
280
|
+
/** Degrees, anticlockwise from horizontal. */
|
|
281
|
+
angle: number;
|
|
282
|
+
/** Hex, without alpha. */
|
|
283
|
+
color: string;
|
|
284
|
+
/** 0–1. */
|
|
285
|
+
opacity: number;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* The mark itself.
|
|
289
|
+
*
|
|
290
|
+
* No dashes or typographic punctuation: the standard PDF faces carry no em
|
|
291
|
+
* dash, and a theme that names a font the engine does not have falls back to
|
|
292
|
+
* them, which turned "BroadPaper — Evaluation Copy" into "BroadPaper
|
|
293
|
+
* Evaluation Copy" in half the documents and a question mark in the rest.
|
|
294
|
+
*/
|
|
295
|
+
declare const EVALUATION_WATERMARK: WatermarkSpec;
|
|
296
|
+
/**
|
|
297
|
+
* The mark a render should carry, or null when the licence says none.
|
|
298
|
+
*
|
|
299
|
+
* Backends call this rather than reading the licence status themselves, so
|
|
300
|
+
* "licensed" and "no watermark" cannot drift apart.
|
|
301
|
+
*/
|
|
302
|
+
declare function resolveWatermark(options?: ResolveOptions): Promise<WatermarkSpec | null>;
|
|
303
|
+
/** The pure half of {@link resolveWatermark}, for callers that already have a status. */
|
|
304
|
+
declare function watermarkFor(status: LicenseStatus): WatermarkSpec | null;
|
|
305
|
+
/**
|
|
306
|
+
* CSS that paints the mark on every `.bp-page` of a rendered document.
|
|
307
|
+
*
|
|
308
|
+
* Used by the Chromium backend and by the designer's print path — the two
|
|
309
|
+
* places a PDF is produced by a browser rather than by the engine. `position:
|
|
310
|
+
* fixed` would put it on the viewport rather than on each page, so it is an
|
|
311
|
+
* absolutely positioned pseudo-element on the page box, which prints once per
|
|
312
|
+
* sheet.
|
|
313
|
+
*
|
|
314
|
+
* `print-color-adjust` matters: without it Chromium drops the mark from the
|
|
315
|
+
* printed file exactly as it drops any other background colour.
|
|
316
|
+
*/
|
|
317
|
+
declare function watermarkCss(spec?: WatermarkSpec): string;
|
|
318
|
+
/**
|
|
319
|
+
* The PDF Producer string for a render.
|
|
320
|
+
*
|
|
321
|
+
* Licensed output records the licence id. It is not a secret — it identifies a
|
|
322
|
+
* customer's licence, not their account — and having it in the file means a
|
|
323
|
+
* document that turns up somewhere it should not can be traced back to the
|
|
324
|
+
* licence that produced it without any of the tracking a phone-home would need.
|
|
325
|
+
*/
|
|
326
|
+
declare function producerString(status: LicenseStatus): string;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* The public keys this build of the SDK will accept licence signatures from.
|
|
330
|
+
*
|
|
331
|
+
* **This file contains public keys only.** BroadPaper's private signing key
|
|
332
|
+
* lives in the licence issuer's secret store and is never in this repository,
|
|
333
|
+
* never in the npm package and never in a browser bundle. Publishing the
|
|
334
|
+
* public half is the point: it is what lets a licence be checked with no
|
|
335
|
+
* network call.
|
|
336
|
+
*
|
|
337
|
+
* Add a production key with:
|
|
338
|
+
*
|
|
339
|
+
* node scripts/licence-keys.mjs --production --key-id bp-1
|
|
340
|
+
*
|
|
341
|
+
* which prints the private key once, for the operator to paste into the
|
|
342
|
+
* issuer's configuration, and writes the public half into this array.
|
|
343
|
+
*
|
|
344
|
+
* The list is an allowlist, so it is also the rotation mechanism: issue with a
|
|
345
|
+
* new `keyId`, ship an SDK release trusting both, and drop the old entry once
|
|
346
|
+
* every licence signed with it has expired. Licences carry their `keyId` inside
|
|
347
|
+
* the signed payload, so an attacker cannot point one at a different key.
|
|
348
|
+
*
|
|
349
|
+
* It starts empty on purpose. A key here is trusted by every copy of the SDK in
|
|
350
|
+
* the world, including production installs, which is exactly why a development
|
|
351
|
+
* key must never be added to it — development keys are supplied at runtime
|
|
352
|
+
* instead, through `configure({ trustedKeys })` or `BROADPAPER_TRUSTED_KEYS`,
|
|
353
|
+
* so a licence signed in development cannot be honoured by a production build.
|
|
354
|
+
*/
|
|
355
|
+
|
|
356
|
+
declare const TRUSTED_KEYS: readonly TrustedKey[];
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* base64url and UTF-8, without depending on Node or on the DOM.
|
|
360
|
+
*
|
|
361
|
+
* The SDK runs in Node, in edge runtimes, in a worker and in a browser, and the
|
|
362
|
+
* licence string has to decode identically in all four. `atob`/`btoa` exist
|
|
363
|
+
* everywhere modern but are byte-oriented and mangle anything above U+00FF, so
|
|
364
|
+
* text goes through `TextEncoder`/`TextDecoder` first and only bytes are
|
|
365
|
+
* base64'd. The tables below are the whole implementation, which is smaller
|
|
366
|
+
* than the runtime detection needed to use `Buffer` where it happens to exist.
|
|
367
|
+
*/
|
|
368
|
+
declare function bytesToBase64Url(bytes: Uint8Array): string;
|
|
369
|
+
/** Throws on anything that is not base64/base64url. Padding is optional. */
|
|
370
|
+
declare function base64UrlToBytes(text: string): Uint8Array;
|
|
371
|
+
|
|
372
|
+
export { BroadPaper, type BroadPaperConfig, DEFAULT_GRACE_PERIOD_DAYS, EVALUATION_WATERMARK, type Entitlement, FORMAT_PREFIX, LicenseFormatError, type LicensePayload, type LicenseState, type LicenseStatus, PRODUCT, type ParsedLicense, type ResolveOptions, TRUSTED_KEYS, type TrustedKey, type VerifyOptions, type WatermarkSpec, base64UrlToBytes, bytesToBase64Url, configure, encodeSigningInput, formatLicense, getConfig, normalizeLicense, parseLicense, producerString, resetConfig, resolveLicenseStatus, resolveWatermark, unlicensed, verifyLicense, warn, watermarkCss, watermarkFor };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
// src/verify.ts
|
|
2
|
+
import { verifyAsync } from "@noble/ed25519";
|
|
3
|
+
|
|
4
|
+
// src/encoding.ts
|
|
5
|
+
var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
6
|
+
var LOOKUP = /* @__PURE__ */ (() => {
|
|
7
|
+
const t = new Int8Array(128).fill(-1);
|
|
8
|
+
for (let i = 0; i < ALPHABET.length; i++) t[ALPHABET.charCodeAt(i)] = i;
|
|
9
|
+
t["+".charCodeAt(0)] = 62;
|
|
10
|
+
t["/".charCodeAt(0)] = 63;
|
|
11
|
+
return t;
|
|
12
|
+
})();
|
|
13
|
+
function bytesToBase64Url(bytes) {
|
|
14
|
+
let out = "";
|
|
15
|
+
let i = 0;
|
|
16
|
+
for (; i + 2 < bytes.length; i += 3) {
|
|
17
|
+
const n = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
|
|
18
|
+
out += ALPHABET[n >>> 18 & 63] + ALPHABET[n >>> 12 & 63] + ALPHABET[n >>> 6 & 63] + ALPHABET[n & 63];
|
|
19
|
+
}
|
|
20
|
+
const rest = bytes.length - i;
|
|
21
|
+
if (rest === 1) {
|
|
22
|
+
const n = bytes[i] << 16;
|
|
23
|
+
out += ALPHABET[n >>> 18 & 63] + ALPHABET[n >>> 12 & 63];
|
|
24
|
+
} else if (rest === 2) {
|
|
25
|
+
const n = bytes[i] << 16 | bytes[i + 1] << 8;
|
|
26
|
+
out += ALPHABET[n >>> 18 & 63] + ALPHABET[n >>> 12 & 63] + ALPHABET[n >>> 6 & 63];
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function base64UrlToBytes(text) {
|
|
31
|
+
let end = text.length;
|
|
32
|
+
while (end > 0 && text[end - 1] === "=") end--;
|
|
33
|
+
const chars = [];
|
|
34
|
+
for (let i2 = 0; i2 < end; i2++) {
|
|
35
|
+
const code = text.charCodeAt(i2);
|
|
36
|
+
const value = code < 128 ? LOOKUP[code] : -1;
|
|
37
|
+
if (value < 0) throw new Error(`not base64: ${JSON.stringify(text[i2])} at ${i2}`);
|
|
38
|
+
chars.push(value);
|
|
39
|
+
}
|
|
40
|
+
if (chars.length % 4 === 1) throw new Error("not base64: truncated");
|
|
41
|
+
const out = new Uint8Array(Math.floor(chars.length * 3 / 4));
|
|
42
|
+
let o = 0;
|
|
43
|
+
let i = 0;
|
|
44
|
+
for (; i + 3 < chars.length; i += 4) {
|
|
45
|
+
const n = chars[i] << 18 | chars[i + 1] << 12 | chars[i + 2] << 6 | chars[i + 3];
|
|
46
|
+
out[o++] = n >>> 16 & 255;
|
|
47
|
+
out[o++] = n >>> 8 & 255;
|
|
48
|
+
out[o++] = n & 255;
|
|
49
|
+
}
|
|
50
|
+
const rest = chars.length - i;
|
|
51
|
+
if (rest === 2) {
|
|
52
|
+
out[o++] = (chars[i] << 18 | chars[i + 1] << 12) >>> 16;
|
|
53
|
+
} else if (rest === 3) {
|
|
54
|
+
const n = chars[i] << 18 | chars[i + 1] << 12 | chars[i + 2] << 6;
|
|
55
|
+
out[o++] = n >>> 16 & 255;
|
|
56
|
+
out[o++] = n >>> 8 & 255;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
var encoder = /* @__PURE__ */ new TextEncoder();
|
|
61
|
+
var decoder = /* @__PURE__ */ new TextDecoder("utf-8", { fatal: true });
|
|
62
|
+
var utf8ToBytes = (text) => encoder.encode(text);
|
|
63
|
+
var bytesToUtf8 = (bytes) => decoder.decode(bytes);
|
|
64
|
+
|
|
65
|
+
// src/format.ts
|
|
66
|
+
var FORMAT_PREFIX = "BP1";
|
|
67
|
+
var LicenseFormatError = class extends Error {
|
|
68
|
+
constructor(message, kind = "invalid") {
|
|
69
|
+
super(message);
|
|
70
|
+
this.kind = kind;
|
|
71
|
+
this.name = "LicenseFormatError";
|
|
72
|
+
}
|
|
73
|
+
kind;
|
|
74
|
+
};
|
|
75
|
+
var ENTITLEMENTS = ["internal", "saas"];
|
|
76
|
+
function normalizeLicense(license) {
|
|
77
|
+
return license.replace(/\s+/g, "");
|
|
78
|
+
}
|
|
79
|
+
function parseLicense(license) {
|
|
80
|
+
const text = normalizeLicense(license);
|
|
81
|
+
if (!text) throw new LicenseFormatError("the licence string is empty");
|
|
82
|
+
const parts = text.split(".");
|
|
83
|
+
if (parts.length !== 3) throw new LicenseFormatError(`expected three dot-separated parts, found ${parts.length}`);
|
|
84
|
+
const [prefix, encodedPayload, encodedSignature] = parts;
|
|
85
|
+
if (prefix !== FORMAT_PREFIX) {
|
|
86
|
+
const known = /^BP\d+$/.test(prefix);
|
|
87
|
+
throw new LicenseFormatError(
|
|
88
|
+
known ? `licence format ${prefix} is newer than this version of BroadPaper, which reads ${FORMAT_PREFIX}` : `unrecognised licence prefix ${JSON.stringify(prefix)}`,
|
|
89
|
+
known ? "unsupported" : "invalid"
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (!encodedPayload || !encodedSignature) throw new LicenseFormatError("the licence string has an empty part");
|
|
93
|
+
let json;
|
|
94
|
+
let signature;
|
|
95
|
+
try {
|
|
96
|
+
json = bytesToUtf8(base64UrlToBytes(encodedPayload));
|
|
97
|
+
signature = base64UrlToBytes(encodedSignature);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
throw new LicenseFormatError(`the licence string is not valid base64 (${e.message})`);
|
|
100
|
+
}
|
|
101
|
+
if (signature.length !== 64) throw new LicenseFormatError(`an Ed25519 signature is 64 bytes, this one is ${signature.length}`);
|
|
102
|
+
let raw;
|
|
103
|
+
try {
|
|
104
|
+
raw = JSON.parse(json);
|
|
105
|
+
} catch {
|
|
106
|
+
throw new LicenseFormatError("the licence payload is not valid JSON");
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
prefix,
|
|
110
|
+
signedText: `${prefix}.${encodedPayload}`,
|
|
111
|
+
encodedPayload,
|
|
112
|
+
signature,
|
|
113
|
+
payload: readPayload(raw)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function readPayload(raw) {
|
|
117
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new LicenseFormatError("the licence payload is not an object");
|
|
118
|
+
const o = raw;
|
|
119
|
+
const version = o.version;
|
|
120
|
+
if (version !== 1) {
|
|
121
|
+
const numeric = typeof version === "number" && Number.isInteger(version) && version > 1;
|
|
122
|
+
throw new LicenseFormatError(
|
|
123
|
+
numeric ? `licence payload version ${version} is newer than this version of BroadPaper, which reads version 1` : "the licence payload has no usable version",
|
|
124
|
+
numeric ? "unsupported" : "invalid"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const text = (key) => {
|
|
128
|
+
const value = o[key];
|
|
129
|
+
if (typeof value !== "string" || value === "") throw new LicenseFormatError(`the licence payload is missing ${key}`);
|
|
130
|
+
return value;
|
|
131
|
+
};
|
|
132
|
+
const seconds = (key) => {
|
|
133
|
+
const value = o[key];
|
|
134
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new LicenseFormatError(`the licence payload is missing ${key}`);
|
|
135
|
+
return value;
|
|
136
|
+
};
|
|
137
|
+
const entitlement = text("entitlement");
|
|
138
|
+
if (!ENTITLEMENTS.includes(entitlement)) {
|
|
139
|
+
throw new LicenseFormatError(`this version of BroadPaper does not know the entitlement ${JSON.stringify(entitlement)}`, "unsupported");
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
...o,
|
|
143
|
+
version: 1,
|
|
144
|
+
keyId: text("keyId"),
|
|
145
|
+
licenseId: text("licenseId"),
|
|
146
|
+
customerId: text("customerId"),
|
|
147
|
+
customerName: text("customerName"),
|
|
148
|
+
product: text("product"),
|
|
149
|
+
entitlement,
|
|
150
|
+
issuedAt: seconds("issuedAt"),
|
|
151
|
+
expiresAt: seconds("expiresAt")
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function encodeSigningInput(payload) {
|
|
155
|
+
const encodedPayload = bytesToBase64Url(utf8ToBytes(JSON.stringify(payload)));
|
|
156
|
+
return { encodedPayload, signedText: `${FORMAT_PREFIX}.${encodedPayload}` };
|
|
157
|
+
}
|
|
158
|
+
function formatLicense(payload, signature) {
|
|
159
|
+
if (signature.length !== 64) throw new LicenseFormatError(`an Ed25519 signature is 64 bytes, this one is ${signature.length}`);
|
|
160
|
+
const { encodedPayload } = encodeSigningInput(payload);
|
|
161
|
+
return `${FORMAT_PREFIX}.${encodedPayload}.${bytesToBase64Url(signature)}`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/trusted-keys.ts
|
|
165
|
+
var TRUSTED_KEYS = [
|
|
166
|
+
{ keyId: "bp-2026", publicKey: "woKmWyIazae7SpGhi4dwA7zNK1lWdboq88Rl5xscTs4", note: "production, generated 2026-09-08" }
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
// src/types.ts
|
|
170
|
+
var PRODUCT = "broadpaper-sdk";
|
|
171
|
+
|
|
172
|
+
// src/verify.ts
|
|
173
|
+
var DEFAULT_GRACE_PERIOD_DAYS = 30;
|
|
174
|
+
var DAY_MS = 864e5;
|
|
175
|
+
function unlicensed() {
|
|
176
|
+
return {
|
|
177
|
+
state: "unlicensed",
|
|
178
|
+
licensed: false,
|
|
179
|
+
payload: null,
|
|
180
|
+
entitlement: null,
|
|
181
|
+
expiresAt: null,
|
|
182
|
+
daysRemaining: null,
|
|
183
|
+
message: "No BroadPaper licence is configured, so PDFs carry the evaluation watermark. Everything else works; see https://www.broadpaper.com/docs/guide/licensing."
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function failure(state, message, payload = null) {
|
|
187
|
+
return {
|
|
188
|
+
state,
|
|
189
|
+
licensed: false,
|
|
190
|
+
payload,
|
|
191
|
+
entitlement: null,
|
|
192
|
+
expiresAt: payload ? new Date(payload.expiresAt * 1e3) : null,
|
|
193
|
+
daysRemaining: null,
|
|
194
|
+
message
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async function verifyLicense(license, options = {}) {
|
|
198
|
+
if (!license || !license.trim()) return unlicensed();
|
|
199
|
+
let parsed;
|
|
200
|
+
try {
|
|
201
|
+
parsed = parseLicense(license);
|
|
202
|
+
} catch (e) {
|
|
203
|
+
if (e instanceof LicenseFormatError) {
|
|
204
|
+
return failure(
|
|
205
|
+
e.kind,
|
|
206
|
+
e.kind === "unsupported" ? `This BroadPaper licence needs a newer version of the SDK (${e.message}). Update @broadpaper/* or the PDF will carry the evaluation watermark.` : `The BroadPaper licence could not be read (${e.message}), so PDFs carry the evaluation watermark.`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
throw e;
|
|
210
|
+
}
|
|
211
|
+
const { payload } = parsed;
|
|
212
|
+
if (payload.product !== PRODUCT) {
|
|
213
|
+
return failure(
|
|
214
|
+
"invalid",
|
|
215
|
+
`This licence is for ${JSON.stringify(payload.product)}, not the BroadPaper SDK, so PDFs carry the evaluation watermark.`,
|
|
216
|
+
payload
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const key = findKey(payload.keyId, options.trustedKeys);
|
|
220
|
+
if (!key) {
|
|
221
|
+
return failure(
|
|
222
|
+
"untrusted",
|
|
223
|
+
`This BroadPaper licence was signed with key ${JSON.stringify(payload.keyId)}, which this build does not trust. A licence issued for development is not honoured by a production build; check BROADPAPER_LICENSE points at the right one.`,
|
|
224
|
+
payload
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
let signatureOk = false;
|
|
228
|
+
try {
|
|
229
|
+
signatureOk = await verifyAsync(parsed.signature, utf8ToBytes(parsed.signedText), base64UrlToBytes(key.publicKey));
|
|
230
|
+
} catch {
|
|
231
|
+
signatureOk = false;
|
|
232
|
+
}
|
|
233
|
+
if (!signatureOk) {
|
|
234
|
+
return failure("invalid", "This BroadPaper licence failed its signature check \u2014 it has been altered or truncated. PDFs carry the evaluation watermark.", payload);
|
|
235
|
+
}
|
|
236
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
237
|
+
const expiresAt = new Date(payload.expiresAt * 1e3);
|
|
238
|
+
const graceDays = options.gracePeriodDays ?? DEFAULT_GRACE_PERIOD_DAYS;
|
|
239
|
+
const msRemaining = expiresAt.getTime() - now.getTime();
|
|
240
|
+
const daysRemaining = Math.floor(msRemaining / DAY_MS);
|
|
241
|
+
if (msRemaining > 0) {
|
|
242
|
+
return {
|
|
243
|
+
state: "active",
|
|
244
|
+
licensed: true,
|
|
245
|
+
payload,
|
|
246
|
+
entitlement: payload.entitlement,
|
|
247
|
+
expiresAt,
|
|
248
|
+
daysRemaining,
|
|
249
|
+
message: null
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (msRemaining > -graceDays * DAY_MS) {
|
|
253
|
+
const daysOver = Math.max(1, Math.ceil(-msRemaining / DAY_MS));
|
|
254
|
+
return {
|
|
255
|
+
state: "grace",
|
|
256
|
+
licensed: true,
|
|
257
|
+
payload,
|
|
258
|
+
entitlement: payload.entitlement,
|
|
259
|
+
expiresAt,
|
|
260
|
+
daysRemaining,
|
|
261
|
+
message: `The BroadPaper licence for ${payload.customerName} expired ${daysOver} day${daysOver === 1 ? "" : "s"} ago and is inside its ${graceDays}-day grace period. Renew it and copy the new licence from your account, or PDFs will start carrying the evaluation watermark.`
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return failure(
|
|
265
|
+
"expired",
|
|
266
|
+
`The BroadPaper licence for ${payload.customerName} expired on ${expiresAt.toISOString().slice(0, 10)} and its ${graceDays}-day grace period has passed, so PDFs carry the evaluation watermark. Renewing issues a new licence in your BroadPaper account.`,
|
|
267
|
+
payload
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
function findKey(keyId, extra) {
|
|
271
|
+
return extra?.find((k) => k.keyId === keyId) ?? TRUSTED_KEYS.find((k) => k.keyId === keyId);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/config.ts
|
|
275
|
+
var STORE_KEY = /* @__PURE__ */ Symbol.for("broadpaper.license.store");
|
|
276
|
+
function store() {
|
|
277
|
+
const g = globalThis;
|
|
278
|
+
let s = g[STORE_KEY];
|
|
279
|
+
if (!s) {
|
|
280
|
+
s = { config: {}, cache: null, logged: /* @__PURE__ */ new Set() };
|
|
281
|
+
g[STORE_KEY] = s;
|
|
282
|
+
}
|
|
283
|
+
return s;
|
|
284
|
+
}
|
|
285
|
+
function configure(config) {
|
|
286
|
+
const s = store();
|
|
287
|
+
s.config = { ...s.config, ...config };
|
|
288
|
+
s.cache = null;
|
|
289
|
+
s.logged.clear();
|
|
290
|
+
}
|
|
291
|
+
function getConfig() {
|
|
292
|
+
return { ...store().config };
|
|
293
|
+
}
|
|
294
|
+
function resetConfig() {
|
|
295
|
+
const g = globalThis;
|
|
296
|
+
delete g[STORE_KEY];
|
|
297
|
+
}
|
|
298
|
+
var BroadPaper = { configure, getConfig };
|
|
299
|
+
function env(name) {
|
|
300
|
+
const p = globalThis.process;
|
|
301
|
+
const value = p?.env?.[name];
|
|
302
|
+
return value && value.trim() ? value : void 0;
|
|
303
|
+
}
|
|
304
|
+
function trustedKeysFromEnv() {
|
|
305
|
+
const raw = env("BROADPAPER_TRUSTED_KEYS");
|
|
306
|
+
if (!raw) return [];
|
|
307
|
+
try {
|
|
308
|
+
const parsed = JSON.parse(raw);
|
|
309
|
+
if (!Array.isArray(parsed)) throw new Error("expected a JSON array");
|
|
310
|
+
return parsed.map((entry, i) => {
|
|
311
|
+
const k = entry;
|
|
312
|
+
if (typeof k?.keyId !== "string" || typeof k?.publicKey !== "string") throw new Error(`entry ${i} needs keyId and publicKey`);
|
|
313
|
+
return { keyId: k.keyId, publicKey: k.publicKey };
|
|
314
|
+
});
|
|
315
|
+
} catch (e) {
|
|
316
|
+
warn(`BROADPAPER_TRUSTED_KEYS could not be read (${e.message}); it is being ignored.`);
|
|
317
|
+
return [];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function warn(message) {
|
|
321
|
+
const s = store();
|
|
322
|
+
if (s.logged.has(message)) return;
|
|
323
|
+
s.logged.add(message);
|
|
324
|
+
const logger = s.config.logger;
|
|
325
|
+
if (logger === null) return;
|
|
326
|
+
const line = `[BroadPaper] ${message}`;
|
|
327
|
+
if (logger) logger(line);
|
|
328
|
+
else console.warn(line);
|
|
329
|
+
}
|
|
330
|
+
async function resolveLicenseStatus(options = {}) {
|
|
331
|
+
const s = store();
|
|
332
|
+
const config = s.config;
|
|
333
|
+
const license = options.license !== void 0 ? options.license : config.license ?? env("BROADPAPER_LICENSE") ?? null;
|
|
334
|
+
const trustedKeys = [...options.trustedKeys ?? [], ...config.trustedKeys ?? [], ...trustedKeysFromEnv()];
|
|
335
|
+
const gracePeriodDays = options.gracePeriodDays ?? config.gracePeriodDays;
|
|
336
|
+
if (!license) {
|
|
337
|
+
const status = unlicensed();
|
|
338
|
+
if (status.message) warn(status.message);
|
|
339
|
+
return status;
|
|
340
|
+
}
|
|
341
|
+
const verify = () => verifyLicense(license, { ...options.now ? { now: options.now } : {}, trustedKeys, ...gracePeriodDays !== void 0 ? { gracePeriodDays } : {} }).then((status) => {
|
|
342
|
+
if (status.message) warn(status.message);
|
|
343
|
+
return status;
|
|
344
|
+
});
|
|
345
|
+
if (options.now || options.license !== void 0) return verify();
|
|
346
|
+
const key = `${license}|${trustedKeys.map((k) => k.keyId).join(",")}|${gracePeriodDays ?? ""}`;
|
|
347
|
+
if (s.cache?.key !== key) s.cache = { key, status: verify() };
|
|
348
|
+
return s.cache.status;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/watermark.ts
|
|
352
|
+
var EVALUATION_WATERMARK = {
|
|
353
|
+
text: "BroadPaper Evaluation Copy",
|
|
354
|
+
fontSize: 44,
|
|
355
|
+
angle: -35,
|
|
356
|
+
color: "#c8102e",
|
|
357
|
+
opacity: 0.12
|
|
358
|
+
};
|
|
359
|
+
async function resolveWatermark(options = {}) {
|
|
360
|
+
const status = await resolveLicenseStatus(options);
|
|
361
|
+
return watermarkFor(status);
|
|
362
|
+
}
|
|
363
|
+
function watermarkFor(status) {
|
|
364
|
+
return status.licensed ? null : EVALUATION_WATERMARK;
|
|
365
|
+
}
|
|
366
|
+
function watermarkCss(spec = EVALUATION_WATERMARK) {
|
|
367
|
+
const text = spec.text.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
368
|
+
return [
|
|
369
|
+
".bp-page{position:relative;}",
|
|
370
|
+
".bp-page::after{",
|
|
371
|
+
`content:"${text}";`,
|
|
372
|
+
"position:absolute;inset:0;",
|
|
373
|
+
"display:flex;align-items:center;justify-content:center;",
|
|
374
|
+
"pointer-events:none;z-index:2147483647;",
|
|
375
|
+
`transform:rotate(${spec.angle}deg);`,
|
|
376
|
+
"font-family:Helvetica,Arial,sans-serif;font-weight:700;letter-spacing:0.04em;white-space:nowrap;",
|
|
377
|
+
`font-size:${spec.fontSize}pt;color:${spec.color};opacity:${spec.opacity};`,
|
|
378
|
+
"-webkit-print-color-adjust:exact;print-color-adjust:exact;",
|
|
379
|
+
"}"
|
|
380
|
+
].join("");
|
|
381
|
+
}
|
|
382
|
+
function producerString(status) {
|
|
383
|
+
if (!status.licensed || !status.payload) return "BroadPaper (evaluation)";
|
|
384
|
+
return `BroadPaper (${status.payload.licenseId})`;
|
|
385
|
+
}
|
|
386
|
+
export {
|
|
387
|
+
BroadPaper,
|
|
388
|
+
DEFAULT_GRACE_PERIOD_DAYS,
|
|
389
|
+
EVALUATION_WATERMARK,
|
|
390
|
+
FORMAT_PREFIX,
|
|
391
|
+
LicenseFormatError,
|
|
392
|
+
PRODUCT,
|
|
393
|
+
TRUSTED_KEYS,
|
|
394
|
+
base64UrlToBytes,
|
|
395
|
+
bytesToBase64Url,
|
|
396
|
+
configure,
|
|
397
|
+
encodeSigningInput,
|
|
398
|
+
formatLicense,
|
|
399
|
+
getConfig,
|
|
400
|
+
normalizeLicense,
|
|
401
|
+
parseLicense,
|
|
402
|
+
producerString,
|
|
403
|
+
resetConfig,
|
|
404
|
+
resolveLicenseStatus,
|
|
405
|
+
resolveWatermark,
|
|
406
|
+
unlicensed,
|
|
407
|
+
verifyLicense,
|
|
408
|
+
warn,
|
|
409
|
+
watermarkCss,
|
|
410
|
+
watermarkFor
|
|
411
|
+
};
|
|
412
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/verify.ts","../src/encoding.ts","../src/format.ts","../src/trusted-keys.ts","../src/types.ts","../src/config.ts","../src/watermark.ts"],"sourcesContent":["/**\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 entitlement: null,\n expiresAt: 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 entitlement: null,\n expiresAt: payload ? new Date(payload.expiresAt * 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 const expiresAt = new Date(payload.expiresAt * 1000);\n const graceDays = options.gracePeriodDays ?? DEFAULT_GRACE_PERIOD_DAYS;\n const msRemaining = expiresAt.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 entitlement: payload.entitlement,\n expiresAt,\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 entitlement: payload.entitlement,\n expiresAt,\n daysRemaining,\n message:\n `The BroadPaper licence for ${payload.customerName} 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.customerName} expired on ${expiresAt.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 * 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 Entitlement, type LicensePayload } 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 ENTITLEMENTS: readonly Entitlement[] = [\"internal\", \"saas\"];\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 version = o.version;\n if (version !== 1) {\n const numeric = typeof version === \"number\" && Number.isInteger(version) && version > 1;\n throw new LicenseFormatError(\n numeric ? `licence payload version ${version} is newer than this version of BroadPaper, which reads version 1` : \"the licence payload has no usable version\",\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\n const entitlement = text(\"entitlement\");\n if (!ENTITLEMENTS.includes(entitlement as Entitlement)) {\n // An entitlement this SDK does not know is a newer commercial model, and\n // refusing to honour a licence we cannot classify would punish the customer\n // for buying something new. It is reported as unsupported so the developer\n // is told to upgrade.\n throw new LicenseFormatError(`this version of BroadPaper does not know the entitlement ${JSON.stringify(entitlement)}`, \"unsupported\");\n }\n\n return {\n ...o,\n version: 1,\n keyId: text(\"keyId\"),\n licenseId: text(\"licenseId\"),\n customerId: text(\"customerId\"),\n customerName: text(\"customerName\"),\n product: text(\"product\") as typeof PRODUCT,\n entitlement: entitlement as Entitlement,\n issuedAt: seconds(\"issuedAt\"),\n expiresAt: seconds(\"expiresAt\")\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","/**\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 * What the licence permits. Not a feature gate — both entitlements unlock\n * exactly the same software. The difference is who the resulting application\n * may be put in front of, which is a contractual matter and is presented as\n * one in the account area and the licence agreement.\n */\nexport type Entitlement = \"internal\" | \"saas\";\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 * `customerId` is the durable identifier of the buying organisation — a Clerk\n * organisation id — rather than an email address, because people change\n * addresses and organisations outlive their founders.\n *\n * Times are epoch **seconds**, not milliseconds: the payload is base64'd into\n * a string a developer will paste into a config file, and three characters per\n * timestamp is three characters.\n */\nexport interface LicensePayload {\n /** Payload schema version. Bumped only when the meaning of a field changes. */\n version: 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 customer is identified by\n * `customerId`, which does not change.\n */\n licenseId: string;\n /** The licensed organisation's durable id. */\n customerId: string;\n /** The organisation's name, for display in warnings and PDF metadata. */\n customerName: string;\n product: typeof PRODUCT;\n entitlement: Entitlement;\n /** Epoch seconds. */\n issuedAt: number;\n /** Epoch seconds. */\n expiresAt: 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 payload version this SDK is older than. */\n | \"unsupported\"\n /** Valid, signed, and inside its term. */\n | \"active\"\n /** Past `expiresAt` but inside the grace period: honoured, and warned about. */\n | \"grace\"\n /** Past `expiresAt` 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 /** What the licence permits, when it is being honoured. */\n entitlement: Entitlement | null;\n /** Expiry as a Date, when known. */\n expiresAt: Date | null;\n /** Days until expiry; negative once expired. Null when there is no licence. */\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 * 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\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"],"mappings":"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","names":["i"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@broadpaper/license",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "BroadPaper licence certificates: offline Ed25519 verification, entitlement states and the evaluation watermark. Contains only the public verification keys.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"THIRD-PARTY-NOTICES.md"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@noble/ed25519": "^3.2.0"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup src/index.ts --format esm --dts --sourcemap --clean",
|
|
27
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
28
|
+
}
|
|
29
|
+
}
|