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.
- package/README.md +335 -97
- package/build/appsLookup.d.ts +14 -0
- package/build/appsLookup.d.ts.map +1 -0
- package/build/appsLookup.js +12 -0
- package/build/appsLookup.js.map +1 -0
- package/build/archiveBootstrap.d.ts +15 -1
- package/build/archiveBootstrap.d.ts.map +1 -0
- package/build/archiveBootstrap.js +62 -9
- package/build/archiveBootstrap.js.map +1 -0
- package/build/bindClient.d.ts +51 -0
- package/build/bindClient.d.ts.map +1 -0
- package/build/bindClient.js +115 -0
- package/build/bindClient.js.map +1 -0
- package/build/buyClient.d.ts +10 -3
- package/build/buyClient.d.ts.map +1 -0
- package/build/buyClient.js +33 -15
- package/build/buyClient.js.map +1 -0
- package/build/contractInterface.d.ts +11 -5
- package/build/contractInterface.d.ts.map +1 -0
- package/build/contractInterface.js +82 -17
- package/build/contractInterface.js.map +1 -0
- package/build/countryStats.d.ts +6 -1
- package/build/countryStats.d.ts.map +1 -0
- package/build/countryStats.js +33 -9
- package/build/countryStats.js.map +1 -0
- package/build/deployClient.d.ts.map +1 -0
- package/build/deployClient.js +1 -1
- package/build/deployClient.js.map +1 -0
- package/build/deviceIdentity.d.ts +68 -0
- package/build/deviceIdentity.d.ts.map +1 -0
- package/build/deviceIdentity.js +209 -0
- package/build/deviceIdentity.js.map +1 -0
- package/build/freezeClient.d.ts.map +1 -0
- package/build/freezeClient.js +1 -1
- package/build/freezeClient.js.map +1 -0
- package/build/generationClient.d.ts +1 -0
- package/build/generationClient.d.ts.map +1 -0
- package/build/generationClient.js +2 -2
- package/build/generationClient.js.map +1 -0
- package/build/index.d.ts +27 -37
- package/build/index.d.ts.map +1 -0
- package/build/index.js +85 -116
- package/build/index.js.map +1 -0
- package/build/licenseLeaf.d.ts +76 -0
- package/build/licenseLeaf.d.ts.map +1 -0
- package/build/licenseLeaf.js +189 -0
- package/build/licenseLeaf.js.map +1 -0
- package/build/licenseRecord.d.ts +20 -1
- package/build/licenseRecord.d.ts.map +1 -0
- package/build/licenseRecord.js +1 -1
- package/build/licenseRecord.js.map +1 -0
- package/build/licenseStore.d.ts +17 -2
- package/build/licenseStore.d.ts.map +1 -0
- package/build/licenseStore.js +167 -7
- package/build/licenseStore.js.map +1 -0
- package/build/manifestVerify.d.ts.map +1 -0
- package/build/manifestVerify.js +8 -3
- package/build/manifestVerify.js.map +1 -0
- package/build/migrateClient.d.ts +6 -21
- package/build/migrateClient.d.ts.map +1 -0
- package/build/migrateClient.js +30 -17
- package/build/migrateClient.js.map +1 -0
- package/build/onChainRoot.d.ts +67 -0
- package/build/onChainRoot.d.ts.map +1 -0
- package/build/onChainRoot.js +87 -0
- package/build/onChainRoot.js.map +1 -0
- package/build/ownershipLicenseHash.d.ts +25 -0
- package/build/ownershipLicenseHash.d.ts.map +1 -0
- package/build/ownershipLicenseHash.js +29 -0
- package/build/ownershipLicenseHash.js.map +1 -0
- package/build/ownershipSignature.d.ts +122 -0
- package/build/ownershipSignature.d.ts.map +1 -0
- package/build/ownershipSignature.js +244 -0
- package/build/ownershipSignature.js.map +1 -0
- package/build/proveErrors.d.ts +35 -0
- package/build/proveErrors.d.ts.map +1 -0
- package/build/proveErrors.js +49 -0
- package/build/proveErrors.js.map +1 -0
- package/build/refundClient.d.ts +2 -11
- package/build/refundClient.d.ts.map +1 -0
- package/build/refundClient.js +35 -17
- package/build/refundClient.js.map +1 -0
- package/build/renewClient.d.ts +4 -1
- package/build/renewClient.d.ts.map +1 -0
- package/build/renewClient.js +11 -4
- package/build/renewClient.js.map +1 -0
- package/build/seatName.d.ts +8 -0
- package/build/seatName.d.ts.map +1 -0
- package/build/seatName.js +136 -0
- package/build/seatName.js.map +1 -0
- package/build/statsClient.d.ts +47 -4
- package/build/statsClient.d.ts.map +1 -0
- package/build/statsClient.js +44 -5
- package/build/statsClient.js.map +1 -0
- package/build/trustAnchorVerify.d.ts +48 -0
- package/build/trustAnchorVerify.d.ts.map +1 -0
- package/build/trustAnchorVerify.js +431 -0
- package/build/trustAnchorVerify.js.map +1 -0
- package/build/trustAnchorVerifyCli.d.ts +35 -0
- package/build/trustAnchorVerifyCli.d.ts.map +1 -0
- package/build/trustAnchorVerifyCli.js +177 -0
- package/build/trustAnchorVerifyCli.js.map +1 -0
- package/build/txBroadcastClient.d.ts +26 -0
- package/build/txBroadcastClient.d.ts.map +1 -0
- package/build/txBroadcastClient.js +20 -0
- package/build/txBroadcastClient.js.map +1 -0
- package/build/unbindClient.d.ts +56 -0
- package/build/unbindClient.d.ts.map +1 -0
- package/build/unbindClient.js +113 -0
- package/build/unbindClient.js.map +1 -0
- package/build/vendorAccountClient.d.ts +56 -0
- package/build/vendorAccountClient.d.ts.map +1 -0
- package/build/vendorAccountClient.js +47 -0
- package/build/vendorAccountClient.js.map +1 -0
- package/build/verifyCore.d.ts +1 -1
- package/build/verifyCore.d.ts.map +1 -0
- package/build/verifyCore.js +11 -4
- package/build/verifyCore.js.map +1 -0
- package/build/verifyOffline.d.ts +85 -0
- package/build/verifyOffline.d.ts.map +1 -0
- package/build/verifyOffline.js +139 -0
- package/build/verifyOffline.js.map +1 -0
- package/build/verifyService.d.ts.map +1 -0
- package/build/verifyService.js +582 -455
- package/build/verifyService.js.map +1 -0
- package/build/verifyWithAncestors.d.ts +18 -0
- package/build/verifyWithAncestors.d.ts.map +1 -0
- package/build/verifyWithAncestors.js +119 -0
- package/build/verifyWithAncestors.js.map +1 -0
- package/build/zipToState.d.ts +2 -0
- package/build/zipToState.d.ts.map +1 -0
- package/build/zipToState.js +94 -0
- package/build/zipToState.js.map +1 -0
- package/package.json +57 -13
- package/src/appsLookup.ts +48 -0
- package/src/archiveBootstrap.ts +342 -0
- package/src/bindClient.ts +175 -0
- package/src/buyClient.ts +304 -0
- package/src/contractInterface.d.ts +61 -0
- package/src/contractInterface.ts +313 -0
- package/src/countryStats.ts +171 -0
- package/src/deployClient.ts +388 -0
- package/src/deviceIdentity.ts +249 -0
- package/src/freezeClient.ts +117 -0
- package/src/generationClient.ts +165 -0
- package/src/index.ts +329 -0
- package/src/licenseLeaf.ts +221 -0
- package/src/licenseRecord.ts +108 -0
- package/src/licenseStore.ts +538 -0
- package/src/manifestVerify.ts +111 -0
- package/src/migrateClient.ts +84 -0
- package/src/onChainRoot.ts +107 -0
- package/src/ownershipLicenseHash.ts +31 -0
- package/src/ownershipSignature.ts +354 -0
- package/src/proveErrors.ts +70 -0
- package/src/refundClient.ts +158 -0
- package/src/renewClient.ts +214 -0
- package/src/seatName.ts +165 -0
- package/src/statsClient.ts +235 -0
- package/src/trustAnchorVerify.ts +548 -0
- package/src/trustAnchorVerifyCli.ts +179 -0
- package/src/txBroadcastClient.ts +48 -0
- package/src/unbindClient.ts +149 -0
- package/src/vendorAccountClient.ts +110 -0
- package/src/verifyCore.ts +92 -0
- package/src/verifyOffline.ts +212 -0
- package/src/verifyService.ts +969 -0
- package/src/verifyWithAncestors.ts +153 -0
- package/src/zipToState.ts +94 -0
- package/build/licenseProof.d.ts +0 -26
- package/build/licenseProof.js +0 -41
- package/build/ownership.d.ts +0 -34
- 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
|
+
}
|