zklicensing 0.1.0-beta.2 → 0.1.0-beta.21

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.
Files changed (317) hide show
  1. package/README.md +417 -201
  2. package/build/agent.d.ts +371 -0
  3. package/build/agent.d.ts.map +1 -0
  4. package/build/agent.js +553 -0
  5. package/build/agent.js.map +1 -0
  6. package/build/agentActions.d.ts +841 -0
  7. package/build/agentActions.d.ts.map +1 -0
  8. package/build/agentActions.js +581 -0
  9. package/build/agentActions.js.map +1 -0
  10. package/build/agentRecord.d.ts +83 -0
  11. package/build/agentRecord.d.ts.map +1 -0
  12. package/build/agentRecord.js +69 -0
  13. package/build/agentRecord.js.map +1 -0
  14. package/build/agentVendor.d.ts +220 -0
  15. package/build/agentVendor.d.ts.map +1 -0
  16. package/build/agentVendor.js +306 -0
  17. package/build/agentVendor.js.map +1 -0
  18. package/build/appsLookup.d.ts +14 -0
  19. package/build/appsLookup.d.ts.map +1 -0
  20. package/build/appsLookup.js +12 -0
  21. package/build/appsLookup.js.map +1 -0
  22. package/build/archiveBootstrap.d.ts +31 -5
  23. package/build/archiveBootstrap.d.ts.map +1 -0
  24. package/build/archiveBootstrap.js +140 -47
  25. package/build/archiveBootstrap.js.map +1 -0
  26. package/build/atomicJson.d.ts +5 -0
  27. package/build/atomicJson.d.ts.map +1 -0
  28. package/build/atomicJson.js +55 -0
  29. package/build/atomicJson.js.map +1 -0
  30. package/build/bindClient.d.ts +85 -0
  31. package/build/bindClient.d.ts.map +1 -0
  32. package/build/bindClient.js +187 -0
  33. package/build/bindClient.js.map +1 -0
  34. package/build/buyClient.d.ts +27 -4
  35. package/build/buyClient.d.ts.map +1 -0
  36. package/build/buyClient.js +72 -26
  37. package/build/buyClient.js.map +1 -0
  38. package/build/chainHead.d.ts +61 -0
  39. package/build/chainHead.d.ts.map +1 -0
  40. package/build/chainHead.js +88 -0
  41. package/build/chainHead.js.map +1 -0
  42. package/build/compactMerkleMap.d.ts +72 -0
  43. package/build/compactMerkleMap.d.ts.map +1 -0
  44. package/build/compactMerkleMap.js +224 -0
  45. package/build/compactMerkleMap.js.map +1 -0
  46. package/build/contractInterface.d.ts +191 -51
  47. package/build/contractInterface.d.ts.map +1 -0
  48. package/build/contractInterface.js +234 -43
  49. package/build/contractInterface.js.map +1 -0
  50. package/build/contractTypes.d.ts +9 -0
  51. package/build/contractTypes.d.ts.map +1 -0
  52. package/build/contractTypes.js +28 -0
  53. package/build/contractTypes.js.map +1 -0
  54. package/build/countryStats.d.ts +12 -3
  55. package/build/countryStats.d.ts.map +1 -0
  56. package/build/countryStats.js +87 -23
  57. package/build/countryStats.js.map +1 -0
  58. package/build/deployClient.d.ts +138 -24
  59. package/build/deployClient.d.ts.map +1 -0
  60. package/build/deployClient.js +91 -31
  61. package/build/deployClient.js.map +1 -0
  62. package/build/deviceIdentity.d.ts +68 -0
  63. package/build/deviceIdentity.d.ts.map +1 -0
  64. package/build/deviceIdentity.js +209 -0
  65. package/build/deviceIdentity.js.map +1 -0
  66. package/build/freezeClient.d.ts +26 -6
  67. package/build/freezeClient.d.ts.map +1 -0
  68. package/build/freezeClient.js +30 -6
  69. package/build/freezeClient.js.map +1 -0
  70. package/build/generationClient.d.ts +6 -3
  71. package/build/generationClient.d.ts.map +1 -0
  72. package/build/generationClient.js +25 -38
  73. package/build/generationClient.js.map +1 -0
  74. package/build/holderSecret.d.ts +70 -0
  75. package/build/holderSecret.d.ts.map +1 -0
  76. package/build/holderSecret.js +76 -0
  77. package/build/holderSecret.js.map +1 -0
  78. package/build/index.d.ts +38 -38
  79. package/build/index.d.ts.map +1 -0
  80. package/build/index.js +97 -121
  81. package/build/index.js.map +1 -0
  82. package/build/keysClient.d.ts +142 -0
  83. package/build/keysClient.d.ts.map +1 -0
  84. package/build/keysClient.js +109 -0
  85. package/build/keysClient.js.map +1 -0
  86. package/build/licenseLeaf.d.ts +76 -0
  87. package/build/licenseLeaf.d.ts.map +1 -0
  88. package/build/licenseLeaf.js +189 -0
  89. package/build/licenseLeaf.js.map +1 -0
  90. package/build/licenseRecord.d.ts +68 -5
  91. package/build/licenseRecord.d.ts.map +1 -0
  92. package/build/licenseRecord.js +26 -1
  93. package/build/licenseRecord.js.map +1 -0
  94. package/build/licenseStore.d.ts +81 -4
  95. package/build/licenseStore.d.ts.map +1 -0
  96. package/build/licenseStore.js +400 -30
  97. package/build/licenseStore.js.map +1 -0
  98. package/build/licenseTrustless.d.ts +43 -0
  99. package/build/licenseTrustless.d.ts.map +1 -0
  100. package/build/licenseTrustless.js +180 -0
  101. package/build/licenseTrustless.js.map +1 -0
  102. package/build/manifestVerify.d.ts +29 -1
  103. package/build/manifestVerify.d.ts.map +1 -0
  104. package/build/manifestVerify.js +46 -4
  105. package/build/manifestVerify.js.map +1 -0
  106. package/build/minaPriceHistory.d.ts +9 -0
  107. package/build/minaPriceHistory.d.ts.map +1 -0
  108. package/build/minaPriceHistory.js +152 -0
  109. package/build/minaPriceHistory.js.map +1 -0
  110. package/build/onChainRoot.d.ts +60 -0
  111. package/build/onChainRoot.d.ts.map +1 -0
  112. package/build/onChainRoot.js +74 -0
  113. package/build/onChainRoot.js.map +1 -0
  114. package/build/ownershipLicenseHash.d.ts +25 -0
  115. package/build/ownershipLicenseHash.d.ts.map +1 -0
  116. package/build/ownershipLicenseHash.js +29 -0
  117. package/build/ownershipLicenseHash.js.map +1 -0
  118. package/build/ownershipSignature.d.ts +153 -0
  119. package/build/ownershipSignature.d.ts.map +1 -0
  120. package/build/ownershipSignature.js +297 -0
  121. package/build/ownershipSignature.js.map +1 -0
  122. package/build/permitCheckFlow.d.ts +155 -0
  123. package/build/permitCheckFlow.d.ts.map +1 -0
  124. package/build/permitCheckFlow.js +196 -0
  125. package/build/permitCheckFlow.js.map +1 -0
  126. package/build/permitDescribe.d.ts +124 -0
  127. package/build/permitDescribe.d.ts.map +1 -0
  128. package/build/permitDescribe.js +324 -0
  129. package/build/permitDescribe.js.map +1 -0
  130. package/build/permitInterface.d.ts +85 -0
  131. package/build/permitInterface.d.ts.map +1 -0
  132. package/build/permitInterface.js +121 -0
  133. package/build/permitInterface.js.map +1 -0
  134. package/build/permitMessages.d.ts +313 -0
  135. package/build/permitMessages.d.ts.map +1 -0
  136. package/build/permitMessages.js +462 -0
  137. package/build/permitMessages.js.map +1 -0
  138. package/build/permitProof.d.ts +108 -0
  139. package/build/permitProof.d.ts.map +1 -0
  140. package/build/permitProof.js +202 -0
  141. package/build/permitProof.js.map +1 -0
  142. package/build/permitRegistryRebuild.d.ts +166 -0
  143. package/build/permitRegistryRebuild.d.ts.map +1 -0
  144. package/build/permitRegistryRebuild.js +347 -0
  145. package/build/permitRegistryRebuild.js.map +1 -0
  146. package/build/permitTree.d.ts +88 -0
  147. package/build/permitTree.d.ts.map +1 -0
  148. package/build/permitTree.js +230 -0
  149. package/build/permitTree.js.map +1 -0
  150. package/build/permitsClient.d.ts +680 -0
  151. package/build/permitsClient.d.ts.map +1 -0
  152. package/build/permitsClient.js +597 -0
  153. package/build/permitsClient.js.map +1 -0
  154. package/build/proveErrors.d.ts +50 -0
  155. package/build/proveErrors.d.ts.map +1 -0
  156. package/build/proveErrors.js +76 -0
  157. package/build/proveErrors.js.map +1 -0
  158. package/build/receipt.d.ts +95 -0
  159. package/build/receipt.d.ts.map +1 -0
  160. package/build/receipt.js +84 -0
  161. package/build/receipt.js.map +1 -0
  162. package/build/refundClient.d.ts +7 -12
  163. package/build/refundClient.d.ts.map +1 -0
  164. package/build/refundClient.js +52 -21
  165. package/build/refundClient.js.map +1 -0
  166. package/build/registryTrustVerify.d.ts +78 -0
  167. package/build/registryTrustVerify.d.ts.map +1 -0
  168. package/build/registryTrustVerify.js +129 -0
  169. package/build/registryTrustVerify.js.map +1 -0
  170. package/build/releaseClient.d.ts +26 -0
  171. package/build/releaseClient.d.ts.map +1 -0
  172. package/build/releaseClient.js +65 -0
  173. package/build/releaseClient.js.map +1 -0
  174. package/build/renewClient.d.ts +28 -2
  175. package/build/renewClient.d.ts.map +1 -0
  176. package/build/renewClient.js +31 -27
  177. package/build/renewClient.js.map +1 -0
  178. package/build/seatName.d.ts +8 -0
  179. package/build/seatName.d.ts.map +1 -0
  180. package/build/seatName.js +136 -0
  181. package/build/seatName.js.map +1 -0
  182. package/build/slotConstants.d.ts +15 -0
  183. package/build/slotConstants.d.ts.map +1 -0
  184. package/build/slotConstants.js +17 -0
  185. package/build/slotConstants.js.map +1 -0
  186. package/build/statsClient.d.ts +61 -7
  187. package/build/statsClient.d.ts.map +1 -0
  188. package/build/statsClient.js +44 -5
  189. package/build/statsClient.js.map +1 -0
  190. package/build/successorChain.d.ts +35 -0
  191. package/build/successorChain.d.ts.map +1 -0
  192. package/build/successorChain.js +69 -0
  193. package/build/successorChain.js.map +1 -0
  194. package/build/taxId.d.ts +44 -0
  195. package/build/taxId.d.ts.map +1 -0
  196. package/build/taxId.js +212 -0
  197. package/build/taxId.js.map +1 -0
  198. package/build/trustAnchorVerify.d.ts +49 -0
  199. package/build/trustAnchorVerify.d.ts.map +1 -0
  200. package/build/trustAnchorVerify.js +432 -0
  201. package/build/trustAnchorVerify.js.map +1 -0
  202. package/build/trustAnchorVerifyCli.d.ts +45 -0
  203. package/build/trustAnchorVerifyCli.d.ts.map +1 -0
  204. package/build/trustAnchorVerifyCli.js +235 -0
  205. package/build/trustAnchorVerifyCli.js.map +1 -0
  206. package/build/txBroadcastClient.d.ts +26 -0
  207. package/build/txBroadcastClient.d.ts.map +1 -0
  208. package/build/txBroadcastClient.js +20 -0
  209. package/build/txBroadcastClient.js.map +1 -0
  210. package/build/unbindClient.d.ts +77 -0
  211. package/build/unbindClient.d.ts.map +1 -0
  212. package/build/unbindClient.js +169 -0
  213. package/build/unbindClient.js.map +1 -0
  214. package/build/units.d.ts +28 -0
  215. package/build/units.d.ts.map +1 -0
  216. package/build/units.js +65 -0
  217. package/build/units.js.map +1 -0
  218. package/build/vatRates.d.ts +54 -0
  219. package/build/vatRates.d.ts.map +1 -0
  220. package/build/vatRates.js +82 -0
  221. package/build/vatRates.js.map +1 -0
  222. package/build/vatRatesData.d.ts +5 -0
  223. package/build/vatRatesData.d.ts.map +1 -0
  224. package/build/vatRatesData.js +42 -0
  225. package/build/vatRatesData.js.map +1 -0
  226. package/build/vendorAccountClient.d.ts +66 -0
  227. package/build/vendorAccountClient.d.ts.map +1 -0
  228. package/build/vendorAccountClient.js +47 -0
  229. package/build/vendorAccountClient.js.map +1 -0
  230. package/build/verifyCore.d.ts +4 -1
  231. package/build/verifyCore.d.ts.map +1 -0
  232. package/build/verifyCore.js +21 -10
  233. package/build/verifyCore.js.map +1 -0
  234. package/build/verifyOffline.d.ts +85 -0
  235. package/build/verifyOffline.d.ts.map +1 -0
  236. package/build/verifyOffline.js +139 -0
  237. package/build/verifyOffline.js.map +1 -0
  238. package/build/verifyService.d.ts.map +1 -0
  239. package/build/verifyService.js +571 -501
  240. package/build/verifyService.js.map +1 -0
  241. package/build/verifyWithAncestors.d.ts +19 -0
  242. package/build/verifyWithAncestors.d.ts.map +1 -0
  243. package/build/verifyWithAncestors.js +127 -0
  244. package/build/verifyWithAncestors.js.map +1 -0
  245. package/build/zipToState.d.ts +2 -0
  246. package/build/zipToState.d.ts.map +1 -0
  247. package/build/zipToState.js +94 -0
  248. package/build/zipToState.js.map +1 -0
  249. package/package.json +141 -16
  250. package/src/agent.ts +682 -0
  251. package/src/agentActions.ts +637 -0
  252. package/src/agentRecord.ts +121 -0
  253. package/src/agentVendor.ts +356 -0
  254. package/src/appsLookup.ts +48 -0
  255. package/src/archiveBootstrap.ts +386 -0
  256. package/src/atomicJson.ts +53 -0
  257. package/src/bindClient.ts +297 -0
  258. package/src/buyClient.ts +344 -0
  259. package/src/chainHead.ts +106 -0
  260. package/src/compactMerkleMap.ts +222 -0
  261. package/src/contractInterface.ts +465 -0
  262. package/src/contractTypes.ts +31 -0
  263. package/src/countryStats.ts +200 -0
  264. package/src/deployClient.ts +517 -0
  265. package/src/deviceIdentity.ts +249 -0
  266. package/src/freezeClient.ts +162 -0
  267. package/src/generationClient.ts +145 -0
  268. package/src/holderSecret.ts +91 -0
  269. package/src/index.ts +362 -0
  270. package/src/keysClient.ts +135 -0
  271. package/src/licenseLeaf.ts +221 -0
  272. package/src/licenseRecord.ts +190 -0
  273. package/src/licenseStore.ts +767 -0
  274. package/src/licenseTrustless.ts +207 -0
  275. package/src/manifestVerify.ts +164 -0
  276. package/src/minaPriceHistory.ts +166 -0
  277. package/src/onChainRoot.ts +90 -0
  278. package/src/ownershipLicenseHash.ts +31 -0
  279. package/src/ownershipSignature.ts +421 -0
  280. package/src/permitCheckFlow.ts +227 -0
  281. package/src/permitDescribe.ts +362 -0
  282. package/src/permitInterface.ts +146 -0
  283. package/src/permitMessages.ts +572 -0
  284. package/src/permitProof.ts +230 -0
  285. package/src/permitRegistryRebuild.ts +423 -0
  286. package/src/permitTree.ts +232 -0
  287. package/src/permitsClient.ts +746 -0
  288. package/src/proveErrors.ts +98 -0
  289. package/src/receipt.ts +156 -0
  290. package/src/refundClient.ts +177 -0
  291. package/src/registryTrustVerify.ts +192 -0
  292. package/src/releaseClient.ts +101 -0
  293. package/src/renewClient.ts +234 -0
  294. package/src/seatName.ts +165 -0
  295. package/src/slotConstants.ts +18 -0
  296. package/src/statsClient.ts +249 -0
  297. package/src/successorChain.ts +87 -0
  298. package/src/taxId.ts +227 -0
  299. package/src/trustAnchorVerify.ts +550 -0
  300. package/src/trustAnchorVerifyCli.ts +234 -0
  301. package/src/txBroadcastClient.ts +48 -0
  302. package/src/unbindClient.ts +233 -0
  303. package/src/units.ts +74 -0
  304. package/src/vatRates.ts +100 -0
  305. package/src/vatRatesData.ts +43 -0
  306. package/src/vendorAccountClient.ts +120 -0
  307. package/src/verifyCore.ts +100 -0
  308. package/src/verifyOffline.ts +212 -0
  309. package/src/verifyService.ts +982 -0
  310. package/src/verifyWithAncestors.ts +163 -0
  311. package/src/zipToState.ts +94 -0
  312. package/build/licenseProof.d.ts +0 -26
  313. package/build/licenseProof.js +0 -41
  314. package/build/migrateClient.d.ts +0 -43
  315. package/build/migrateClient.js +0 -47
  316. package/build/ownership.d.ts +0 -34
  317. package/build/ownership.js +0 -147
package/build/units.js ADDED
@@ -0,0 +1,65 @@
1
+ // Copyright (c) 2025-2026 zkLicensing project developers
2
+ // SPDX-License-Identifier: BUSL-1.1
3
+ /**
4
+ * units.ts — the unit amounts are shown in.
5
+ *
6
+ * Devnet amounts are test MINA (tMINA), which has no value; mainnet amounts
7
+ * are MINA. Only what people read changes: field names (`priceYearlyMina`,
8
+ * nanomina amounts) stay the same on both networks. The MINA price in euros
9
+ * or dollars is real and still shown on devnet, but only as a reference for
10
+ * mainnet MINA (`fiatReference`), never as the value of tMINA.
11
+ */
12
+ import { isEuCountry } from './taxId.js';
13
+ /** 'tMINA' on devnet (and any test network), 'MINA' on mainnet. */
14
+ export function minaUnit(network) {
15
+ return network === 'mainnet' ? 'MINA' : 'tMINA';
16
+ }
17
+ /** "12.5 tMINA" / "12.5 MINA" for an amount in MINA (number or decimal string). */
18
+ export function formatMina(amountMina, network) {
19
+ return `${amountMina} ${minaUnit(network)}`;
20
+ }
21
+ /** "12.5 tMINA" for an amount in nanomina. */
22
+ export function formatNanomina(nano, network) {
23
+ const n = BigInt(nano);
24
+ const neg = n < 0n;
25
+ const a = neg ? -n : n;
26
+ const frac = (a % 1000000000n).toString().padStart(9, '0').replace(/0+$/, '');
27
+ return `${neg ? '-' : ''}${(a / 1000000000n).toString()}${frac ? '.' + frac : ''} ${minaUnit(network)}`;
28
+ }
29
+ /**
30
+ * The words that go with a fiat value. Mainnet: "≈ €2.10". Devnet: the same
31
+ * amount of real MINA, said as such ("as MINA ≈ €2.10"), plus a note that
32
+ * tMINA itself has no value.
33
+ */
34
+ export function fiatReference(network) {
35
+ return network === 'mainnet'
36
+ ? { prefix: '≈', note: null }
37
+ : { prefix: 'as MINA ≈', note: 'tMINA has no value; this is what the same amount of mainnet MINA is worth.' };
38
+ }
39
+ const SYMBOL = { eur: '€', usd: '$', gbp: '£' };
40
+ /**
41
+ * Which money a person sees amounts in, by their country: euros in the EU,
42
+ * pounds and euros in the UK, dollars in the US, euros and dollars elsewhere
43
+ * (or when the country is unknown).
44
+ */
45
+ export function fiatCurrencies(country) {
46
+ const c = String(country ?? '').trim().toUpperCase();
47
+ if (isEuCountry(c))
48
+ return ['eur'];
49
+ if (c === 'GB' || c === 'UK')
50
+ return ['gbp', 'eur'];
51
+ if (c === 'US')
52
+ return ['usd'];
53
+ return ['eur', 'usd'];
54
+ }
55
+ /** "€2.10", "-€26.78" for an amount of money. */
56
+ export function formatFiat(amount, currency, digits = 2) {
57
+ const n = typeof amount === 'string' ? Number(amount) : amount;
58
+ return `${n < 0 ? '-' : ''}${SYMBOL[currency]}${Math.abs(n).toFixed(digits)}`;
59
+ }
60
+ /** "€2.10 · $2.30" for the given currencies (a currency without a rate is left out). */
61
+ export function formatFiatList(values, currencies, digits = 2) {
62
+ return currencies.filter(c => values[c] !== undefined && values[c] !== null && values[c] !== '')
63
+ .map(c => formatFiat(values[c], c, digits)).join(' · ');
64
+ }
65
+ //# sourceMappingURL=units.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.js","sourceRoot":"","sources":["../src/units.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * vatRates.ts — `zklicensing/vat`
3
+ *
4
+ * Standard VAT rates (EU member states and the UK, with their history) and
5
+ * the VAT included in a VAT-inclusive price. Prices on zkLicensing are fixed
6
+ * per tier on-chain and include VAT: a buyer pays the listed price, and the
7
+ * VAT in it is at the buyer's country's standard rate on the sale date.
8
+ *
9
+ * standardVatRate('FI', '2026-10-13') → 25.5
10
+ * vatIncludedNano(10_000_000_000n, 25.5) → { netNano: 7_968_127_490n, vatNano: 2_031_872_510n }
11
+ *
12
+ * For vendors' own reporting and buyers' information — an estimate for
13
+ * consumer sales, not tax advice: business buyers with a VAT number are
14
+ * usually reverse-charged, and the EU's €10,000 cross-border threshold is
15
+ * not applied. Countries without VAT in the table give null.
16
+ */
17
+ import { VAT_RATES_FETCHED, VAT_RATES_SOURCE } from './vatRatesData.js';
18
+ export { VAT_RATES_FETCHED, VAT_RATES_SOURCE };
19
+ /** The standard VAT rate (percent) in force in `country` on `date`, or null if the country isn't in the table. */
20
+ export declare function standardVatRate(country: string, date?: Date | string | number): number | null;
21
+ /** Countries in the table (ISO codes). */
22
+ export declare function vatCountries(): string[];
23
+ /** The VAT included in a VAT-inclusive `totalNano` at `ratePct`: vat = total × r / (100 + r), rounded to the nearest nanomina. */
24
+ export declare function vatIncludedNano(totalNano: bigint, ratePct: number): {
25
+ netNano: bigint;
26
+ vatNano: bigint;
27
+ };
28
+ /** Same, for a MINA amount (display only). */
29
+ export declare function vatIncludedMina(totalMina: number, ratePct: number): {
30
+ net: number;
31
+ vat: number;
32
+ };
33
+ /** The price shown to a buyer in `country` on `date`: the total, and the VAT it includes. Null rate outside the table. */
34
+ export declare function priceWithVat(totalNano: bigint, country: string, date?: Date | string | number): {
35
+ totalNano: bigint;
36
+ country: string;
37
+ rate: number | null;
38
+ netNano: bigint;
39
+ vatNano: bigint;
40
+ };
41
+ /** The VAT block of a license receipt (amounts as decimal MINA strings). */
42
+ export type VatReceipt = {
43
+ country: string;
44
+ /** Standard rate (percent) on the sale date; null when the country has no VAT in the table. */
45
+ ratePct: number | null;
46
+ totalMina: string;
47
+ vatMina: string;
48
+ netMina: string;
49
+ /** Which rates table was used. */
50
+ rates: string;
51
+ };
52
+ /** The VAT included in a purchase of `totalNano` by a buyer in `country` on `date`, for the license file. */
53
+ export declare function vatReceipt(totalNano: bigint, country: string, date?: Date | string | number): VatReceipt;
54
+ //# sourceMappingURL=vatRates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vatRates.d.ts","sourceRoot":"","sources":["../src/vatRates.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAsB,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE5F,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;AAQ/C,kHAAkH;AAClH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,IAAI,GAAG,MAAM,GAAG,MAAmB,GAAG,MAAM,GAAG,IAAI,CAQzG;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC;AAOD,kIAAkI;AAClI,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAMxG;AAED,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAGhG;AAED,0HAA0H;AAC1H,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,IAAI,GAAG,MAAM,GAAG,MAAmB,GACxG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAI9F;AAED,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,+FAA+F;IAC/F,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAOF,6GAA6G;AAC7G,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,IAAI,GAAG,MAAM,GAAG,MAAmB,GAAG,UAAU,CAOpH"}
@@ -0,0 +1,82 @@
1
+ // Copyright (c) 2025-2026 zkLicensing project developers
2
+ // SPDX-License-Identifier: BUSL-1.1
3
+ /**
4
+ * vatRates.ts — `zklicensing/vat`
5
+ *
6
+ * Standard VAT rates (EU member states and the UK, with their history) and
7
+ * the VAT included in a VAT-inclusive price. Prices on zkLicensing are fixed
8
+ * per tier on-chain and include VAT: a buyer pays the listed price, and the
9
+ * VAT in it is at the buyer's country's standard rate on the sale date.
10
+ *
11
+ * standardVatRate('FI', '2026-10-13') → 25.5
12
+ * vatIncludedNano(10_000_000_000n, 25.5) → { netNano: 7_968_127_490n, vatNano: 2_031_872_510n }
13
+ *
14
+ * For vendors' own reporting and buyers' information — an estimate for
15
+ * consumer sales, not tax advice: business buyers with a VAT number are
16
+ * usually reverse-charged, and the EU's €10,000 cross-border threshold is
17
+ * not applied. Countries without VAT in the table give null.
18
+ */
19
+ import { STANDARD_VAT_RATES, VAT_RATES_FETCHED, VAT_RATES_SOURCE } from './vatRatesData.js';
20
+ export { VAT_RATES_FETCHED, VAT_RATES_SOURCE };
21
+ function isoDay(date) {
22
+ const d = date instanceof Date ? date : new Date(date);
23
+ if (!Number.isFinite(d.getTime()))
24
+ throw new Error('invalid date');
25
+ return d.toISOString().slice(0, 10);
26
+ }
27
+ /** The standard VAT rate (percent) in force in `country` on `date`, or null if the country isn't in the table. */
28
+ export function standardVatRate(country, date = new Date()) {
29
+ const c = String(country ?? '').toUpperCase();
30
+ const periods = Object.prototype.hasOwnProperty.call(STANDARD_VAT_RATES, c) ? STANDARD_VAT_RATES[c] : undefined;
31
+ if (!periods)
32
+ return null;
33
+ const day = isoDay(date);
34
+ let rate = null;
35
+ for (const [from, r] of periods)
36
+ if (from <= day)
37
+ rate = r;
38
+ return rate;
39
+ }
40
+ /** Countries in the table (ISO codes). */
41
+ export function vatCountries() {
42
+ return Object.keys(STANDARD_VAT_RATES);
43
+ }
44
+ const bp = (ratePct) => {
45
+ if (!Number.isFinite(ratePct) || ratePct < 0 || ratePct >= 100)
46
+ throw new Error('rate must be a percentage in [0, 100)');
47
+ return BigInt(Math.round(ratePct * 100));
48
+ };
49
+ /** The VAT included in a VAT-inclusive `totalNano` at `ratePct`: vat = total × r / (100 + r), rounded to the nearest nanomina. */
50
+ export function vatIncludedNano(totalNano, ratePct) {
51
+ if (totalNano < 0n)
52
+ throw new Error('total must not be negative');
53
+ const r = bp(ratePct);
54
+ const den = 10000n + r;
55
+ const vatNano = (totalNano * r * 2n + den) / (den * 2n);
56
+ return { netNano: totalNano - vatNano, vatNano };
57
+ }
58
+ /** Same, for a MINA amount (display only). */
59
+ export function vatIncludedMina(totalMina, ratePct) {
60
+ const { netNano, vatNano } = vatIncludedNano(BigInt(Math.round(totalMina * 1e9)), ratePct);
61
+ return { net: Number(netNano) / 1e9, vat: Number(vatNano) / 1e9 };
62
+ }
63
+ /** The price shown to a buyer in `country` on `date`: the total, and the VAT it includes. Null rate outside the table. */
64
+ export function priceWithVat(totalNano, country, date = new Date()) {
65
+ const rate = standardVatRate(country, date);
66
+ const split = rate === null ? { netNano: totalNano, vatNano: 0n } : vatIncludedNano(totalNano, rate);
67
+ return { totalNano, country: String(country).toUpperCase(), rate, ...split };
68
+ }
69
+ const minaString = (nano) => {
70
+ const s = nano.toString().padStart(10, '0');
71
+ return `${s.slice(0, -9)}.${s.slice(-9)}`.replace(/\.?0+$/, '') || '0';
72
+ };
73
+ /** The VAT included in a purchase of `totalNano` by a buyer in `country` on `date`, for the license file. */
74
+ export function vatReceipt(totalNano, country, date = new Date()) {
75
+ const p = priceWithVat(totalNano, country, date);
76
+ return {
77
+ country: p.country, ratePct: p.rate,
78
+ totalMina: minaString(p.totalNano), vatMina: minaString(p.vatNano), netMina: minaString(p.netNano),
79
+ rates: `${VAT_RATES_SOURCE}, ${VAT_RATES_FETCHED}`,
80
+ };
81
+ }
82
+ //# sourceMappingURL=vatRates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vatRates.js","sourceRoot":"","sources":["../src/vatRates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare const VAT_RATES_SOURCE = "ibericode/vat-rates (MIT)";
2
+ export declare const VAT_RATES_FETCHED = "2026-10-13";
3
+ /** country → [effective-from date, standard rate %][], oldest first. */
4
+ export declare const STANDARD_VAT_RATES: Readonly<Record<string, ReadonlyArray<readonly [string, number]>>>;
5
+ //# sourceMappingURL=vatRatesData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vatRatesData.d.ts","sourceRoot":"","sources":["../src/vatRatesData.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAC5D,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAE9C,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CA6BjG,CAAC"}
@@ -0,0 +1,42 @@
1
+ // Copyright (c) 2025-2026 zkLicensing project developers
2
+ // SPDX-License-Identifier: BUSL-1.1
3
+ //
4
+ // GENERATED by scripts/build-vat-rates.mjs — do not edit by hand.
5
+ //
6
+ // Standard VAT rates (percent) with the date each took effect, per country.
7
+ // Source: ibericode/vat-rates, https://raw.githubusercontent.com/ibericode/vat-rates/master/vat-rates.json
8
+ // (MIT License, Copyright 2019 Danny van Kooten). Fetched 2026-10-13.
9
+ export const VAT_RATES_SOURCE = 'ibericode/vat-rates (MIT)';
10
+ export const VAT_RATES_FETCHED = '2026-10-13';
11
+ /** country → [effective-from date, standard rate %][], oldest first. */
12
+ export const STANDARD_VAT_RATES = {
13
+ AT: [['1970-01-01', 20], ['2016-01-01', 20]],
14
+ BE: [['1970-01-01', 21]],
15
+ BG: [['1970-01-01', 20]],
16
+ CY: [['1970-01-01', 19]],
17
+ CZ: [['1970-01-01', 21], ['2024-01-01', 21]],
18
+ DE: [['1970-01-01', 19], ['2020-07-01', 16], ['2021-01-01', 19]],
19
+ DK: [['1970-01-01', 25]],
20
+ EE: [['1970-01-01', 20], ['2024-01-01', 22], ['2025-01-01', 22], ['2025-07-01', 24]],
21
+ ES: [['1970-01-01', 21]],
22
+ FI: [['1970-01-01', 24], ['2024-09-01', 25.5], ['2026-01-01', 25.5]],
23
+ FR: [['1970-01-01', 19.6], ['2012-01-01', 19.6], ['2014-01-01', 20]],
24
+ GB: [['2011-01-04', 20]],
25
+ GR: [['1970-01-01', 23], ['2016-01-01', 23], ['2016-06-01', 24]],
26
+ HR: [['1970-01-01', 25]],
27
+ HU: [['1970-01-01', 27]],
28
+ IE: [['1970-01-01', 23], ['2020-09-01', 21], ['2021-03-01', 23]],
29
+ IT: [['1970-01-01', 22]],
30
+ LT: [['1970-01-01', 21]],
31
+ LU: [['1970-01-01', 15], ['2015-01-01', 17], ['2016-01-01', 17], ['2023-01-01', 16], ['2024-01-01', 17]],
32
+ LV: [['1970-01-01', 21]],
33
+ MT: [['1970-01-01', 18]],
34
+ NL: [['1970-01-01', 19], ['2012-10-01', 21], ['2019-01-01', 21]],
35
+ PL: [['1970-01-01', 23]],
36
+ PT: [['1970-01-01', 23]],
37
+ RO: [['1970-01-01', 24], ['2016-01-01', 20], ['2017-01-01', 19], ['2025-08-01', 21]],
38
+ SE: [['1970-01-01', 25]],
39
+ SI: [['1970-01-01', 22]],
40
+ SK: [['1970-01-01', 19], ['2011-01-01', 20], ['2025-01-01', 23]],
41
+ };
42
+ //# sourceMappingURL=vatRatesData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vatRatesData.js","sourceRoot":"","sources":["../src/vatRatesData.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,oCAAoC;AACpC,EAAE;AACF,kEAAkE;AAClE,EAAE;AACF,4EAA4E;AAC5E,2GAA2G;AAC3G,sEAAsE;AAEtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAC5D,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAE9C,wEAAwE;AACxE,MAAM,CAAC,MAAM,kBAAkB,GAAuE;IACpG,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC5C,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC5C,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAChE,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACpF,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACpE,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACpE,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAChE,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAChE,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxG,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAChE,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACpF,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxB,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;CACjE,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * vendorAccountClient.ts
3
+ *
4
+ * Browser-safe client for the vendor's shared legal/billing block —
5
+ * the fields that must stay consistent across every app registered by
6
+ * one vendor wallet (legal entity name, billing country and address,
7
+ * VAT id, company registry). One PATCH updates all of the vendor's
8
+ * apps atomically on the backend, so a legal-entity rename or address
9
+ * move doesn't leave old apps advertising stale CRD Art. 6 disclosures.
10
+ *
11
+ * Signature covers the vendor address, mirroring the "sign the
12
+ * resource id" pattern PUT /apps/:appId uses. The backend verifies
13
+ * against the on-chain vendor recorded on the app records.
14
+ */
15
+ export type VendorLegalBlock = {
16
+ country?: string;
17
+ legalName?: string;
18
+ billingAddress?: {
19
+ line1: string;
20
+ line2?: string;
21
+ city: string;
22
+ postalCode: string;
23
+ };
24
+ invoiceEmail?: string;
25
+ supportEmail?: string;
26
+ vatId?: string;
27
+ companyRegistrationRegistry?: string;
28
+ companyRegistrationNumber?: string;
29
+ termsOfServiceUrl?: string;
30
+ privacyPolicyUrl?: string;
31
+ refundPolicyUrl?: string;
32
+ };
33
+ export type GetVendorLegalRequest = {
34
+ keeperUrl: string;
35
+ vendorAddress: string;
36
+ vendorSessionToken: string;
37
+ fetcher?: typeof fetch;
38
+ signal?: AbortSignal;
39
+ };
40
+ export type GetVendorLegalResponse = {
41
+ legal: VendorLegalBlock | null;
42
+ };
43
+ export type UpdateVendorLegalRequest = {
44
+ keeperUrl: string;
45
+ vendorAddress: string;
46
+ payload: VendorLegalBlock;
47
+ /** The vendor's session (`VendorSession` token) for the network its apps
48
+ * are on — mainnet if any app is on mainnet. Or give a `fetcher` that
49
+ * adds it. */
50
+ sessionToken?: string;
51
+ /** Ignored by the keeper (the old signature over the vendor's own address,
52
+ * which could be replayed); kept so existing callers compile. */
53
+ signature?: {
54
+ field: string;
55
+ scalar: string;
56
+ };
57
+ fetcher?: typeof fetch;
58
+ signal?: AbortSignal;
59
+ };
60
+ export type UpdateVendorLegalResponse = {
61
+ ok: true;
62
+ appsUpdated: number;
63
+ };
64
+ export declare function getVendorLegal(req: GetVendorLegalRequest): Promise<GetVendorLegalResponse>;
65
+ export declare function updateVendorLegal(req: UpdateVendorLegalRequest): Promise<UpdateVendorLegalResponse>;
66
+ //# sourceMappingURL=vendorAccountClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vendorAccountClient.d.ts","sourceRoot":"","sources":["../src/vendorAccountClient.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAW,MAAM,CAAC;IAC3B,aAAa,EAAO,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAY,OAAO,KAAK,CAAC;IACjC,MAAM,CAAC,EAAa,WAAW,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IAGnC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAM,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAQ,gBAAgB,CAAC;IAChC;;kBAEc;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;qEACiE;IACjE,SAAS,CAAC,EAAK;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,OAAO,CAAC,EAAO,OAAO,KAAK,CAAC;IAC5B,MAAM,CAAC,EAAQ,WAAW,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,EAAE,EAAW,IAAI,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAgBF,wBAAsB,cAAc,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAWhG;AAOD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAgBzG"}
@@ -0,0 +1,47 @@
1
+ // Copyright (c) 2025-2026 zkLicensing project developers
2
+ // SPDX-License-Identifier: BUSL-1.1
3
+ function baseUrl(url) {
4
+ return url.replace(/\/+$/, '');
5
+ }
6
+ async function readJsonError(resp) {
7
+ try {
8
+ const body = await resp.json();
9
+ if (typeof body.error === 'string')
10
+ return body.error;
11
+ }
12
+ catch { /* body wasn't JSON */ }
13
+ return `HTTP ${resp.status}`;
14
+ }
15
+ // GET /vendors/:address/legal — fetch the shared legal block for a wallet.
16
+ // Returns `{ legal: null }` for wallets with no registered apps.
17
+ export async function getVendorLegal(req) {
18
+ const fetcher = req.fetcher ?? fetch;
19
+ const resp = await fetcher(`${baseUrl(req.keeperUrl)}/vendors/${encodeURIComponent(req.vendorAddress)}/legal`, {
20
+ signal: req.signal,
21
+ headers: { Authorization: `VendorSession ${req.vendorSessionToken}` },
22
+ });
23
+ if (!resp.ok)
24
+ throw new Error(await readJsonError(resp));
25
+ return await resp.json();
26
+ }
27
+ // PATCH /vendors/:address/legal — updates the block on EVERY app the vendor
28
+ // owns in a single atomic sweep. Authorised by the vendor's session. Bypasses the pendingEdit staging that
29
+ // per-app metadata edits go through; legal fields are factual (not
30
+ // marketing copy) so admin review doesn't gain anything and staleness
31
+ // hurts CRD Art. 6 compliance.
32
+ export async function updateVendorLegal(req) {
33
+ const fetcher = req.fetcher ?? fetch;
34
+ const resp = await fetcher(`${baseUrl(req.keeperUrl)}/vendors/${encodeURIComponent(req.vendorAddress)}/legal`, {
35
+ method: 'PATCH',
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ ...(req.sessionToken ? { Authorization: `VendorSession ${req.sessionToken}` } : {}),
39
+ },
40
+ signal: req.signal,
41
+ body: JSON.stringify({ payload: req.payload }),
42
+ });
43
+ if (!resp.ok)
44
+ throw new Error(await readJsonError(resp));
45
+ return await resp.json();
46
+ }
47
+ //# sourceMappingURL=vendorAccountClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vendorAccountClient.js","sourceRoot":"","sources":["../src/vendorAccountClient.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,oCAAoC;AAsEpC,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAc;IACzC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAA6B,CAAC;QAC1D,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC;IAClC,OAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;AAC/B,CAAC;AAED,2EAA2E;AAC3E,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAA0B;IAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,KAAK,CAAC;IACrC,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,EAClF;QACE,MAAM,EAAG,GAAG,CAAC,MAAM;QACnB,OAAO,EAAE,EAAE,aAAa,EAAE,iBAAiB,GAAG,CAAC,kBAAkB,EAAE,EAAE;KACtE,CACF,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,OAAO,MAAM,IAAI,CAAC,IAAI,EAA4B,CAAC;AACrD,CAAC;AAED,4EAA4E;AAC5E,2GAA2G;AAC3G,mEAAmE;AACnE,sEAAsE;AACtE,+BAA+B;AAC/B,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAA6B;IACnE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,KAAK,CAAC;IACrC,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,EAClF;QACE,MAAM,EAAG,OAAO;QAChB,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,iBAAiB,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpF;QACD,MAAM,EAAG,GAAG,CAAC,MAAM;QACnB,IAAI,EAAK,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;KAClD,CACF,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,OAAO,MAAM,IAAI,CAAC,IAAI,EAA+B,CAAC;AACxD,CAAC"}
@@ -3,6 +3,7 @@ export type VerifyResponse = {
3
3
  valid: boolean;
4
4
  expiresAt: string | null;
5
5
  expirySlot: number;
6
+ effectiveExpirySlot?: number;
6
7
  inGracePeriod: boolean;
7
8
  remainingDays: number;
8
9
  reason: string | null;
@@ -11,10 +12,11 @@ export type VerifyResponse = {
11
12
  * Core license verification.
12
13
  *
13
14
  * @param zkAppAddress - app address (composite key with licenseHash)
14
- * @param licenseHash - Poseidon.hash([secretHash]) as a field string
15
+ * @param licenseHash - Poseidon hash of the buyer's Ed25519 pubkey (see ownershipLicenseHash.ts) as a field string
15
16
  * @param records - current off-chain license records (from licenseStore)
16
17
  * @param onChainRoot - zkApp appState[0] fetched from Mina
17
18
  * @param currentSlot - current blockchain slot (globalSlotSinceGenesis)
19
+ * @param forkActivationSlot - the app's forkActivationSlot state (0: none)
18
20
  */
19
21
  export declare function verifyLicenseCore(params: {
20
22
  zkAppAddress: string;
@@ -22,5 +24,6 @@ export declare function verifyLicenseCore(params: {
22
24
  records: LicenseRecord[];
23
25
  onChainRoot: string;
24
26
  currentSlot: number;
27
+ forkActivationSlot?: number;
25
28
  }): VerifyResponse;
26
29
  //# sourceMappingURL=verifyCore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyCore.d.ts","sourceRoot":"","sources":["../src/verifyCore.ts"],"names":[],"mappings":"AAYA,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGjE,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IAGnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IAIvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAOF;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,GAAG,cAAc,CA+CjB"}
@@ -1,5 +1,5 @@
1
1
  // Copyright (c) 2025-2026 zkLicensing project developers
2
- // All rights reserved.
2
+ // SPDX-License-Identifier: BUSL-1.1
3
3
  /**
4
4
  * verifyCore.ts
5
5
  *
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { Field } from 'o1js';
11
11
  import { buildMap } from './licenseStore.js';
12
- import { GRACE_PERIOD_N, MS_PER_SLOT_N, SLOTS_PER_DAY_N } from './contractInterface.js';
12
+ import { GRACE_PERIOD_N, MS_PER_SLOT_N, SLOTS_PER_DAY_N, effectiveExpirySlot } from './contractInterface.js';
13
13
  function computeRemainingDays(expirySlot, currentSlot) {
14
14
  if (expirySlot === 0)
15
15
  return 0;
@@ -19,10 +19,11 @@ function computeRemainingDays(expirySlot, currentSlot) {
19
19
  * Core license verification.
20
20
  *
21
21
  * @param zkAppAddress - app address (composite key with licenseHash)
22
- * @param licenseHash - Poseidon.hash([secretHash]) as a field string
22
+ * @param licenseHash - Poseidon hash of the buyer's Ed25519 pubkey (see ownershipLicenseHash.ts) as a field string
23
23
  * @param records - current off-chain license records (from licenseStore)
24
24
  * @param onChainRoot - zkApp appState[0] fetched from Mina
25
25
  * @param currentSlot - current blockchain slot (globalSlotSinceGenesis)
26
+ * @param forkActivationSlot - the app's forkActivationSlot state (0: none)
26
27
  */
27
28
  export function verifyLicenseCore(params) {
28
29
  const { zkAppAddress, licenseHash, records, onChainRoot, currentSlot } = params;
@@ -34,21 +35,31 @@ export function verifyLicenseCore(params) {
34
35
  if (computedRoot.toString() !== onChainRoot) {
35
36
  return { valid: false, expiresAt: null, expirySlot: 0, inGracePeriod: false, remainingDays: 0, reason: 'License state does not match on-chain root' };
36
37
  }
38
+ // Post-LicenseLeaf: the map value is `leaf.hash()`, not raw expirySlot.
39
+ // Empty slots still hash to Field(0). Look up the record to recover
40
+ // expirySlot; `buildMap` excludes refunded/empty entries, so a missing
41
+ // record here means either "never bought" or "refunded" (record kept but
42
+ // expirySlot cleared to 0).
43
+ const record = records.find(r => r.zkAppAddress === zkAppAddress && r.licenseHash === licenseHash);
37
44
  if (currentValue === '0') {
38
- return { valid: false, expiresAt: null, expirySlot: 0, inGracePeriod: false, remainingDays: 0, reason: 'License has been refunded' };
45
+ const reason = record?.refunded ? 'License has been refunded' : 'License not found';
46
+ return { valid: false, expiresAt: null, expirySlot: 0, inGracePeriod: false, remainingDays: 0, reason };
39
47
  }
40
- const expirySlot = Number(currentValue);
41
- const inGracePeriod = currentSlot > expirySlot && currentSlot <= expirySlot + GRACE_PERIOD_N;
42
- const expired = currentSlot > expirySlot + GRACE_PERIOD_N;
43
- const expiresAt = new Date(Date.now() + (expirySlot - currentSlot) * MS_PER_SLOT_N).toISOString();
44
- const remainingDays = computeRemainingDays(expirySlot, currentSlot);
48
+ const expirySlot = record?.expirySlot ?? 0;
49
+ const effective = effectiveExpirySlot(expirySlot, params.forkActivationSlot ?? 0);
50
+ const bumped = effective !== expirySlot ? { effectiveExpirySlot: effective } : {};
51
+ const inGracePeriod = currentSlot > effective && currentSlot <= effective + GRACE_PERIOD_N;
52
+ const expired = currentSlot > effective + GRACE_PERIOD_N;
53
+ const expiresAt = new Date(Date.now() + (effective - currentSlot) * MS_PER_SLOT_N).toISOString();
54
+ const remainingDays = computeRemainingDays(effective, currentSlot);
45
55
  if (expired) {
46
- return { valid: false, expiresAt, expirySlot, inGracePeriod: false, remainingDays, reason: 'License has expired' };
56
+ return { valid: false, expiresAt, expirySlot, ...bumped, inGracePeriod: false, remainingDays, reason: 'License has expired' };
47
57
  }
48
58
  return {
49
59
  valid: true,
50
60
  expiresAt,
51
61
  expirySlot,
62
+ ...bumped,
52
63
  inGracePeriod,
53
64
  remainingDays,
54
65
  reason: inGracePeriod ? 'License is in grace period — renew to avoid interruption' : null,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyCore.js","sourceRoot":"","sources":["../src/verifyCore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * verifyOffline.ts
3
+ *
4
+ * Non-custodial device-binding offline verifier. Given:
5
+ * - a serialized MerkleMapWitness for the license entry
6
+ * - a `licensesRoot` value the caller has anchored to (see "Trust anchoring")
7
+ * - the full LicenseLeaf field set (licenseHash, expirySlot, deviceCap,
8
+ * deviceSlots[]) as of that sync — the leaf carries no separate
9
+ * owner-pubkey commitment because `licenseHash` IS it (buy circuit
10
+ * asserts equality)
11
+ * - the caller's device public key
12
+ *
13
+ * this module:
14
+ * 1. Reconstructs the LicenseLeaf hash from its fields.
15
+ * 2. Rebuilds the on-chain root through the witness and asserts it matches
16
+ * the passed `licensesRoot` — proves the leaf field set is authentic
17
+ * relative to that root.
18
+ * 3. If `deviceCap > 0`: computes the device commitment for the caller's
19
+ * pubkey and asserts it appears in `occupied[]`.
20
+ * 4. Asserts `expirySlot > currentSlot` (grace-period handling stays in
21
+ * the online verifier; the device-bound offline path is pass/fail).
22
+ * 5. If `deviceCap === 0`: skips the device check entirely — the app has
23
+ * binding disabled at the vendor level.
24
+ *
25
+ * Trust anchoring — where does `licensesRoot` come from?
26
+ * -------------------------------------------------------
27
+ * This module treats the passed root as ground truth. It does NOT fetch
28
+ * it. Two ways to source it:
29
+ *
30
+ * • Non-custodial (recommended). Fetch it yourself from Mina via
31
+ * `fetchOnChainLicensesRoot({ zkAppAddress, network })` from
32
+ * `zklicensing/on-chain-root`. That reads `zkapp.appState[0]` on
33
+ * the deployed LicensingApp — the same field the circuit updates on
34
+ * every buy/renew/bind/unbind/refund. No trust in the licensing
35
+ * service required.
36
+ *
37
+ * • Custodial (trusted-service). Use whatever root the licensing
38
+ * service returned on its `/verify` or `/witness` response. Faster
39
+ * (no o1js + Mina RPC round-trip) but relies on the service to
40
+ * report the true chain state. If you go this route, cross-check
41
+ * the reported root against the on-chain value on some cadence.
42
+ *
43
+ * The caller fetches the device slot state (occupied[] + freedAt[] + cap)
44
+ * from the vendor SDK or platform verifier alongside the licensesRoot on
45
+ * the sync cadence of their choice. The parallel arrays fold to
46
+ * `deviceSlotsRoot`, so any tampering with slot contents changes the leaf
47
+ * hash and fails the witness check — provided `licensesRoot` itself is
48
+ * trustworthy (see above), verifyOffline needs no trust in whoever
49
+ * served the slot arrays.
50
+ *
51
+ * Not exported at the top-level barrel by default; vendors who ship a
52
+ * device-cap app import from `zklicensing/verify-offline` explicitly.
53
+ */
54
+ import { Field, PublicKey } from 'o1js';
55
+ import { type serializeWitness } from './licenseStore.js';
56
+ export type DeviceSlotSnapshot = {
57
+ slotIndex: number;
58
+ deviceCommitment: string;
59
+ boundAtSlot: number;
60
+ freedAtSlot: number;
61
+ };
62
+ export type VerifyOfflineInput = {
63
+ licensesRoot: string;
64
+ currentSlot: number;
65
+ licenseHash: string;
66
+ expirySlot: number;
67
+ deviceCap: number;
68
+ devices: DeviceSlotSnapshot[];
69
+ witness: ReturnType<typeof serializeWitness>;
70
+ devicePubKey?: PublicKey;
71
+ };
72
+ export type VerifyOfflineResult = {
73
+ valid: boolean;
74
+ reason: string | null;
75
+ };
76
+ /**
77
+ * Pure offline device-binding verifier. See module-level docstring.
78
+ *
79
+ * All errors are returned via `{ valid: false, reason }` rather than thrown
80
+ * — callers integrate this into a boot-time gate and don't want to catch
81
+ * around every call. `reason` is stable enough to key error UX off of.
82
+ */
83
+ export declare function verifyOffline(input: VerifyOfflineInput): VerifyOfflineResult;
84
+ export declare function deviceCommitmentFromFields(x: Field, isOdd: Field): Field;
85
+ //# sourceMappingURL=verifyOffline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyOffline.d.ts","sourceRoot":"","sources":["../src/verifyOffline.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EAAE,KAAK,EAAY,SAAS,EAAU,MAAM,MAAM,CAAC;AAC1D,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAc9E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAS,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAO,MAAM,CAAC;IACzB,WAAW,EAAO,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAO/B,YAAY,EAAM,MAAM,CAAC;IACzB,WAAW,EAAO,MAAM,CAAC;IAMzB,WAAW,EAAO,MAAM,CAAC;IACzB,UAAU,EAAQ,MAAM,CAAC;IACzB,SAAS,EAAS,MAAM,CAAC;IACzB,OAAO,EAAW,kBAAkB,EAAE,CAAC;IAKvC,OAAO,EAAW,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;IAMtD,YAAY,CAAC,EAAK,SAAS,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAG,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAwBF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,mBAAmB,CA0D5E;AAOD,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,CAExE"}