zklicensing 0.1.0-beta.2 → 0.1.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/README.md +335 -97
  2. package/build/appsLookup.d.ts +14 -0
  3. package/build/appsLookup.d.ts.map +1 -0
  4. package/build/appsLookup.js +12 -0
  5. package/build/appsLookup.js.map +1 -0
  6. package/build/archiveBootstrap.d.ts +15 -1
  7. package/build/archiveBootstrap.d.ts.map +1 -0
  8. package/build/archiveBootstrap.js +62 -9
  9. package/build/archiveBootstrap.js.map +1 -0
  10. package/build/bindClient.d.ts +51 -0
  11. package/build/bindClient.d.ts.map +1 -0
  12. package/build/bindClient.js +115 -0
  13. package/build/bindClient.js.map +1 -0
  14. package/build/buyClient.d.ts +10 -3
  15. package/build/buyClient.d.ts.map +1 -0
  16. package/build/buyClient.js +33 -15
  17. package/build/buyClient.js.map +1 -0
  18. package/build/contractInterface.d.ts +11 -5
  19. package/build/contractInterface.d.ts.map +1 -0
  20. package/build/contractInterface.js +82 -17
  21. package/build/contractInterface.js.map +1 -0
  22. package/build/countryStats.d.ts +6 -1
  23. package/build/countryStats.d.ts.map +1 -0
  24. package/build/countryStats.js +33 -9
  25. package/build/countryStats.js.map +1 -0
  26. package/build/deployClient.d.ts.map +1 -0
  27. package/build/deployClient.js +1 -1
  28. package/build/deployClient.js.map +1 -0
  29. package/build/deviceIdentity.d.ts +68 -0
  30. package/build/deviceIdentity.d.ts.map +1 -0
  31. package/build/deviceIdentity.js +209 -0
  32. package/build/deviceIdentity.js.map +1 -0
  33. package/build/freezeClient.d.ts.map +1 -0
  34. package/build/freezeClient.js +1 -1
  35. package/build/freezeClient.js.map +1 -0
  36. package/build/generationClient.d.ts +1 -0
  37. package/build/generationClient.d.ts.map +1 -0
  38. package/build/generationClient.js +2 -2
  39. package/build/generationClient.js.map +1 -0
  40. package/build/index.d.ts +27 -37
  41. package/build/index.d.ts.map +1 -0
  42. package/build/index.js +85 -116
  43. package/build/index.js.map +1 -0
  44. package/build/licenseLeaf.d.ts +76 -0
  45. package/build/licenseLeaf.d.ts.map +1 -0
  46. package/build/licenseLeaf.js +189 -0
  47. package/build/licenseLeaf.js.map +1 -0
  48. package/build/licenseRecord.d.ts +20 -1
  49. package/build/licenseRecord.d.ts.map +1 -0
  50. package/build/licenseRecord.js +1 -1
  51. package/build/licenseRecord.js.map +1 -0
  52. package/build/licenseStore.d.ts +17 -2
  53. package/build/licenseStore.d.ts.map +1 -0
  54. package/build/licenseStore.js +167 -7
  55. package/build/licenseStore.js.map +1 -0
  56. package/build/manifestVerify.d.ts.map +1 -0
  57. package/build/manifestVerify.js +8 -3
  58. package/build/manifestVerify.js.map +1 -0
  59. package/build/migrateClient.d.ts +6 -21
  60. package/build/migrateClient.d.ts.map +1 -0
  61. package/build/migrateClient.js +30 -17
  62. package/build/migrateClient.js.map +1 -0
  63. package/build/onChainRoot.d.ts +67 -0
  64. package/build/onChainRoot.d.ts.map +1 -0
  65. package/build/onChainRoot.js +87 -0
  66. package/build/onChainRoot.js.map +1 -0
  67. package/build/ownershipLicenseHash.d.ts +25 -0
  68. package/build/ownershipLicenseHash.d.ts.map +1 -0
  69. package/build/ownershipLicenseHash.js +29 -0
  70. package/build/ownershipLicenseHash.js.map +1 -0
  71. package/build/ownershipSignature.d.ts +122 -0
  72. package/build/ownershipSignature.d.ts.map +1 -0
  73. package/build/ownershipSignature.js +244 -0
  74. package/build/ownershipSignature.js.map +1 -0
  75. package/build/proveErrors.d.ts +35 -0
  76. package/build/proveErrors.d.ts.map +1 -0
  77. package/build/proveErrors.js +49 -0
  78. package/build/proveErrors.js.map +1 -0
  79. package/build/refundClient.d.ts +2 -11
  80. package/build/refundClient.d.ts.map +1 -0
  81. package/build/refundClient.js +35 -17
  82. package/build/refundClient.js.map +1 -0
  83. package/build/renewClient.d.ts +4 -1
  84. package/build/renewClient.d.ts.map +1 -0
  85. package/build/renewClient.js +11 -4
  86. package/build/renewClient.js.map +1 -0
  87. package/build/seatName.d.ts +8 -0
  88. package/build/seatName.d.ts.map +1 -0
  89. package/build/seatName.js +136 -0
  90. package/build/seatName.js.map +1 -0
  91. package/build/statsClient.d.ts +47 -4
  92. package/build/statsClient.d.ts.map +1 -0
  93. package/build/statsClient.js +44 -5
  94. package/build/statsClient.js.map +1 -0
  95. package/build/trustAnchorVerify.d.ts +48 -0
  96. package/build/trustAnchorVerify.d.ts.map +1 -0
  97. package/build/trustAnchorVerify.js +431 -0
  98. package/build/trustAnchorVerify.js.map +1 -0
  99. package/build/trustAnchorVerifyCli.d.ts +35 -0
  100. package/build/trustAnchorVerifyCli.d.ts.map +1 -0
  101. package/build/trustAnchorVerifyCli.js +177 -0
  102. package/build/trustAnchorVerifyCli.js.map +1 -0
  103. package/build/txBroadcastClient.d.ts +26 -0
  104. package/build/txBroadcastClient.d.ts.map +1 -0
  105. package/build/txBroadcastClient.js +20 -0
  106. package/build/txBroadcastClient.js.map +1 -0
  107. package/build/unbindClient.d.ts +56 -0
  108. package/build/unbindClient.d.ts.map +1 -0
  109. package/build/unbindClient.js +113 -0
  110. package/build/unbindClient.js.map +1 -0
  111. package/build/vendorAccountClient.d.ts +56 -0
  112. package/build/vendorAccountClient.d.ts.map +1 -0
  113. package/build/vendorAccountClient.js +47 -0
  114. package/build/vendorAccountClient.js.map +1 -0
  115. package/build/verifyCore.d.ts +1 -1
  116. package/build/verifyCore.d.ts.map +1 -0
  117. package/build/verifyCore.js +11 -4
  118. package/build/verifyCore.js.map +1 -0
  119. package/build/verifyOffline.d.ts +85 -0
  120. package/build/verifyOffline.d.ts.map +1 -0
  121. package/build/verifyOffline.js +139 -0
  122. package/build/verifyOffline.js.map +1 -0
  123. package/build/verifyService.d.ts.map +1 -0
  124. package/build/verifyService.js +582 -455
  125. package/build/verifyService.js.map +1 -0
  126. package/build/verifyWithAncestors.d.ts +18 -0
  127. package/build/verifyWithAncestors.d.ts.map +1 -0
  128. package/build/verifyWithAncestors.js +119 -0
  129. package/build/verifyWithAncestors.js.map +1 -0
  130. package/build/zipToState.d.ts +2 -0
  131. package/build/zipToState.d.ts.map +1 -0
  132. package/build/zipToState.js +94 -0
  133. package/build/zipToState.js.map +1 -0
  134. package/package.json +57 -13
  135. package/src/appsLookup.ts +48 -0
  136. package/src/archiveBootstrap.ts +342 -0
  137. package/src/bindClient.ts +175 -0
  138. package/src/buyClient.ts +304 -0
  139. package/src/contractInterface.d.ts +61 -0
  140. package/src/contractInterface.ts +313 -0
  141. package/src/countryStats.ts +171 -0
  142. package/src/deployClient.ts +388 -0
  143. package/src/deviceIdentity.ts +249 -0
  144. package/src/freezeClient.ts +117 -0
  145. package/src/generationClient.ts +165 -0
  146. package/src/index.ts +329 -0
  147. package/src/licenseLeaf.ts +221 -0
  148. package/src/licenseRecord.ts +108 -0
  149. package/src/licenseStore.ts +538 -0
  150. package/src/manifestVerify.ts +111 -0
  151. package/src/migrateClient.ts +84 -0
  152. package/src/onChainRoot.ts +107 -0
  153. package/src/ownershipLicenseHash.ts +31 -0
  154. package/src/ownershipSignature.ts +354 -0
  155. package/src/proveErrors.ts +70 -0
  156. package/src/refundClient.ts +158 -0
  157. package/src/renewClient.ts +214 -0
  158. package/src/seatName.ts +165 -0
  159. package/src/statsClient.ts +235 -0
  160. package/src/trustAnchorVerify.ts +548 -0
  161. package/src/trustAnchorVerifyCli.ts +179 -0
  162. package/src/txBroadcastClient.ts +48 -0
  163. package/src/unbindClient.ts +149 -0
  164. package/src/vendorAccountClient.ts +110 -0
  165. package/src/verifyCore.ts +92 -0
  166. package/src/verifyOffline.ts +212 -0
  167. package/src/verifyService.ts +969 -0
  168. package/src/verifyWithAncestors.ts +153 -0
  169. package/src/zipToState.ts +94 -0
  170. package/build/licenseProof.d.ts +0 -26
  171. package/build/licenseProof.js +0 -41
  172. package/build/ownership.d.ts +0 -34
  173. package/build/ownership.js +0 -147
@@ -0,0 +1,235 @@
1
+ // Copyright (c) 2025-2026 zkLicensing project developers
2
+ // SPDX-License-Identifier: BUSL-1.1
3
+
4
+ /**
5
+ * statsClient.ts
6
+ *
7
+ * Browser-safe HTTP client for the vendor-facing keeper endpoints that back
8
+ * the dashboard: GET /stats, GET /transactions, and GET /apps/vendor/:addr.
9
+ *
10
+ * Types mirror the keeper's response shapes so a dashboard implementation
11
+ * (this repo's zklicensing.com dashboard or a third-party one) doesn't have
12
+ * to re-derive them. New optional fields on the server should be added here
13
+ * as `?:` so older clients still typecheck against a newer keeper.
14
+ */
15
+
16
+ import type { CountryBreakdown } from './countryStats.js';
17
+ import type { FiatRateSnapshot } from './licenseRecord.js';
18
+
19
+ export type Tier = 'monthly' | 'yearly' | 'fiveYear' | 'perpetual';
20
+
21
+ export type AppRecord = {
22
+ appId: string;
23
+ name: string;
24
+ description: string;
25
+ longDescription?: string;
26
+ category: string;
27
+ website: string;
28
+ // Absent on `status: 'not-deployed'` stub rows (returned by
29
+ // GET /apps/vendor/:addr?network=… for apps the vendor owns but hasn't
30
+ // deployed on the queried network). Present on every other projection.
31
+ zkAppAddress?: string;
32
+ vendorAddress: string;
33
+ priceMonthlyMina: number;
34
+ priceYearlyMina: number;
35
+ priceFiveYearMina: number;
36
+ pricePerpetualMina: number;
37
+ // Also absent on `status: 'not-deployed'` stub rows. See zkAppAddress note.
38
+ txHash?: string;
39
+ verificationKeyHash?: string;
40
+ logo?: string;
41
+ // Best favicon URL for the vendor's website, resolved server-side by the
42
+ // keeper (parses `<link rel="icon">` tags on the website). Undefined until
43
+ // the vendor's next edit for grandfathered apps — clients should fall back
44
+ // to `${host}/favicon.ico` in that case.
45
+ iconUrl?: string;
46
+ tags?: string[];
47
+ contactEmail?: string;
48
+ supportEmail?: string;
49
+ country?: string;
50
+ status?: 'pending' | 'active' | 'inactive' | 'rejected' | 'not-deployed';
51
+ rejectionReason?: string;
52
+ createdAt: string;
53
+ approvedAt?: string;
54
+ // Which network this record projection is scoped to. Present on responses
55
+ // from GET /apps?network=… and GET /apps/vendor/:addr?network=… — the keeper
56
+ // stamps it so a dashboard rendering multiple projections doesn't have to
57
+ // track the query it made.
58
+ network?: 'devnet' | 'mainnet';
59
+ // Sibling networks this app is also deployed to. Empty or omitted when the
60
+ // app only exists on `network`. Dashboards use this to render "Also deploy
61
+ // to X →" / "Promote to X →" cross-origin CTAs.
62
+ alsoOnNetworks?: ('devnet' | 'mainnet')[];
63
+ // Per-deployment sync bookkeeping, flattened from AppRecord.deployments[network]
64
+ // by the keeper's network-scoped list handlers.
65
+ firstEventSlot?: number;
66
+ lastSyncedSlot?: number;
67
+ onChainVersion?: number;
68
+ deploymentHistory?: unknown[];
69
+ pendingEdit?: Partial<AppRecord> & { editedAt: string };
70
+ // Append-only audit trail of status transitions. Optional so older keepers
71
+ // that don't yet emit it still typecheck.
72
+ statusHistory?: { status: string; at: string; actor: string; note?: string }[];
73
+ // Vendor legal / billing block — collected at registration for compliance
74
+ // (CRD Art. 6, e-Commerce Directive Art. 5) and reused in the vendor's
75
+ // tax-year CSV export. All optional here so older keepers that don't yet
76
+ // return these fields still typecheck. `country` (top-level above) is the
77
+ // billing country and pairs with `billingAddress` — the address struct
78
+ // intentionally omits a country field to avoid drift.
79
+ legalName?: string;
80
+ billingAddress?: { line1: string; line2?: string; city: string; postalCode: string };
81
+ invoiceEmail?: string;
82
+ vatId?: string;
83
+ companyRegistrationRegistry?: string;
84
+ companyRegistrationNumber?: string;
85
+ // Registration fee (in MINA) actually paid at deploy time. Stamped from
86
+ // the keeper's REGISTRATION_FEE constant when the record was created.
87
+ // Absent on pre-persistence records — consumers should fall back to the
88
+ // legacy flat 100 MINA fee for records without this field.
89
+ registrationFeeMina?: number;
90
+ };
91
+
92
+ export type VendorStatsResponse = {
93
+ apps: AppRecord[];
94
+ activeLicenses: number;
95
+ totalLicenses: number;
96
+ totalRevenueMina: number;
97
+ pendingRevenueMina?: number;
98
+ // Vendor's post-fee share of refunded purchases, in MINA. Optional so older
99
+ // keepers (pre-refund-tracking) still typecheck against this SDK.
100
+ refundedRevenueMina?: number;
101
+ renewalRate: number | null;
102
+ monthlyRevenueMina: { month: string; mina: number }[];
103
+ licensesByTier?: { monthly: number; yearly: number; fiveYear: number; perpetual: number };
104
+ deltas: { revenuePct: number | null };
105
+ countryBreakdown?: CountryBreakdown;
106
+ };
107
+
108
+ export type Transaction = {
109
+ type: 'purchase' | 'renewal' | 'release' | 'refund';
110
+ appId: string;
111
+ appName: string;
112
+ // Only populated on the admin __all response — vendor-scoped queries omit it
113
+ // since the caller already knows the vendor from the query itself.
114
+ vendorAddress?: string;
115
+ tier: Tier | null;
116
+ amountMina: number;
117
+ txHash: string;
118
+ date: string; // ISO
119
+ // Buyer's ISO-3166 alpha-2 country at purchase (present on purchase rows and
120
+ // any downstream renewal/refund/release rows for the same record). Optional
121
+ // for pre-country-capture legacy rows.
122
+ buyerCountry?: string;
123
+ // MINA→fiat rates snapshotted at the moment the underlying purchase/renewal
124
+ // confirmed — same fields as the receipt email. Missing on archive-replayed
125
+ // records and on rows created before the first successful CoinGecko fetch.
126
+ fiatSnapshot?: FiatRateSnapshot;
127
+ };
128
+
129
+ export type TransactionsResponse = { transactions: Transaction[] };
130
+
131
+ export type VendorAppsResponse = { apps: AppRecord[] };
132
+
133
+ function baseUrl(url: string): string {
134
+ return url.replace(/\/+$/, '');
135
+ }
136
+
137
+ // Admin __all mode: pass `adminToken` and omit `vendorAddress` (or pass '__all').
138
+ // Fetches aggregate over every registered app. Server gates with Bearer auth.
139
+ // tzOffsetMinutes: signed minutes east of UTC — shifts tax-year cutovers on the
140
+ // countryBreakdown so a UK vendor's 2026 doesn't include a Dec 31 23:30 PST
141
+ // purchase. Default omitted → UTC bucketing preserved for existing callers.
142
+ export async function fetchVendorStats(opts: {
143
+ keeperUrl: string;
144
+ vendorAddress: string;
145
+ network: 'devnet' | 'mainnet';
146
+ adminToken?: string;
147
+ // Vendor dashboard-session bearer for the per-vendor read path. Mutually
148
+ // exclusive with adminToken (adminToken wins if both set — the '__all'
149
+ // path never has a session).
150
+ vendorSessionToken?: string;
151
+ tzOffsetMinutes?: number;
152
+ fetcher?: typeof fetch;
153
+ signal?: AbortSignal;
154
+ }): Promise<VendorStatsResponse | null> {
155
+ const fetcher = opts.fetcher ?? fetch;
156
+ const headers: Record<string, string> = {};
157
+ if (opts.adminToken) headers.Authorization = `Bearer ${opts.adminToken}`;
158
+ else if (opts.vendorSessionToken) headers.Authorization = `VendorSession ${opts.vendorSessionToken}`;
159
+ const tzQ = typeof opts.tzOffsetMinutes === 'number' ? `&tz=${opts.tzOffsetMinutes}` : '';
160
+ const resp = await fetcher(
161
+ `${baseUrl(opts.keeperUrl)}/stats?vendor=${encodeURIComponent(opts.vendorAddress)}&network=${opts.network}${tzQ}`,
162
+ { signal: opts.signal, headers },
163
+ );
164
+ if (!resp.ok) return null;
165
+ return await resp.json() as VendorStatsResponse;
166
+ }
167
+
168
+ export async function fetchTransactions(opts: {
169
+ keeperUrl: string;
170
+ vendorAddress: string;
171
+ network: 'devnet' | 'mainnet';
172
+ adminToken?: string;
173
+ vendorSessionToken?: string;
174
+ // Rolling window in days. Default 30. Ignored when both `from` and `to` are
175
+ // set (explicit range wins) — used for the dashboard's "last N days" view.
176
+ days?: number;
177
+ // Explicit inclusive-start / exclusive-end ISO dates (YYYY-MM-DD). When both
178
+ // are set the server filters to [from, to) instead of the rolling window.
179
+ // Used by the CSV export to fetch an exact tax year without over-fetching.
180
+ from?: string;
181
+ to?: string;
182
+ fetcher?: typeof fetch;
183
+ signal?: AbortSignal;
184
+ }): Promise<TransactionsResponse | null> {
185
+ const fetcher = opts.fetcher ?? fetch;
186
+ const headers: Record<string, string> = {};
187
+ if (opts.adminToken) headers.Authorization = `Bearer ${opts.adminToken}`;
188
+ else if (opts.vendorSessionToken) headers.Authorization = `VendorSession ${opts.vendorSessionToken}`;
189
+ const qs = new URLSearchParams({ vendor: opts.vendorAddress, network: opts.network });
190
+ if (opts.from && opts.to) {
191
+ qs.set('from', opts.from);
192
+ qs.set('to', opts.to);
193
+ } else {
194
+ qs.set('days', String(opts.days ?? 30));
195
+ }
196
+ const resp = await fetcher(
197
+ `${baseUrl(opts.keeperUrl)}/transactions?${qs.toString()}`,
198
+ { signal: opts.signal, headers },
199
+ );
200
+ if (!resp.ok) return null;
201
+ return await resp.json() as TransactionsResponse;
202
+ }
203
+
204
+ // Admin all-apps mode: pass `adminToken` and set `vendorAddress` to '__all'.
205
+ // Hits GET /apps (no auth needed today; the admin overload just uses a
206
+ // different URL) so vendors visiting their own dashboard still hit the same
207
+ // per-vendor endpoint.
208
+ export async function fetchVendorApps(opts: {
209
+ keeperUrl: string;
210
+ vendorAddress: string;
211
+ adminToken?: string;
212
+ vendorSessionToken?: string;
213
+ // Network scope for the vendor projection. Required for the per-vendor path
214
+ // — the keeper returns records projected against `deployments[network]` plus
215
+ // stub rows for apps the vendor owns but hasn't deployed on this network
216
+ // (status: 'not-deployed'). Omitted only in admin __all mode.
217
+ network?: 'devnet' | 'mainnet';
218
+ fetcher?: typeof fetch;
219
+ signal?: AbortSignal;
220
+ }): Promise<VendorAppsResponse | null> {
221
+ const fetcher = opts.fetcher ?? fetch;
222
+ const headers: Record<string, string> = {};
223
+ if (opts.adminToken) headers.Authorization = `Bearer ${opts.adminToken}`;
224
+ else if (opts.vendorSessionToken) headers.Authorization = `VendorSession ${opts.vendorSessionToken}`;
225
+ const isAdminAll = opts.adminToken && opts.vendorAddress === '__all';
226
+ if (!isAdminAll && !opts.network) {
227
+ throw new Error("fetchVendorApps: `network` is required for the per-vendor path");
228
+ }
229
+ const url = isAdminAll
230
+ ? `${baseUrl(opts.keeperUrl)}/apps?all=1`
231
+ : `${baseUrl(opts.keeperUrl)}/apps/vendor/${encodeURIComponent(opts.vendorAddress)}?network=${opts.network}`;
232
+ const resp = await fetcher(url, { signal: opts.signal, headers });
233
+ if (!resp.ok) return null;
234
+ return await resp.json() as VendorAppsResponse;
235
+ }