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.
- package/README.md +417 -201
- package/build/agent.d.ts +371 -0
- package/build/agent.d.ts.map +1 -0
- package/build/agent.js +553 -0
- package/build/agent.js.map +1 -0
- package/build/agentActions.d.ts +841 -0
- package/build/agentActions.d.ts.map +1 -0
- package/build/agentActions.js +581 -0
- package/build/agentActions.js.map +1 -0
- package/build/agentRecord.d.ts +83 -0
- package/build/agentRecord.d.ts.map +1 -0
- package/build/agentRecord.js +69 -0
- package/build/agentRecord.js.map +1 -0
- package/build/agentVendor.d.ts +220 -0
- package/build/agentVendor.d.ts.map +1 -0
- package/build/agentVendor.js +306 -0
- package/build/agentVendor.js.map +1 -0
- 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 +31 -5
- package/build/archiveBootstrap.d.ts.map +1 -0
- package/build/archiveBootstrap.js +140 -47
- package/build/archiveBootstrap.js.map +1 -0
- package/build/atomicJson.d.ts +5 -0
- package/build/atomicJson.d.ts.map +1 -0
- package/build/atomicJson.js +55 -0
- package/build/atomicJson.js.map +1 -0
- package/build/bindClient.d.ts +85 -0
- package/build/bindClient.d.ts.map +1 -0
- package/build/bindClient.js +187 -0
- package/build/bindClient.js.map +1 -0
- package/build/buyClient.d.ts +27 -4
- package/build/buyClient.d.ts.map +1 -0
- package/build/buyClient.js +72 -26
- package/build/buyClient.js.map +1 -0
- package/build/chainHead.d.ts +61 -0
- package/build/chainHead.d.ts.map +1 -0
- package/build/chainHead.js +88 -0
- package/build/chainHead.js.map +1 -0
- package/build/compactMerkleMap.d.ts +72 -0
- package/build/compactMerkleMap.d.ts.map +1 -0
- package/build/compactMerkleMap.js +224 -0
- package/build/compactMerkleMap.js.map +1 -0
- package/build/contractInterface.d.ts +191 -51
- package/build/contractInterface.d.ts.map +1 -0
- package/build/contractInterface.js +234 -43
- package/build/contractInterface.js.map +1 -0
- package/build/contractTypes.d.ts +9 -0
- package/build/contractTypes.d.ts.map +1 -0
- package/build/contractTypes.js +28 -0
- package/build/contractTypes.js.map +1 -0
- package/build/countryStats.d.ts +12 -3
- package/build/countryStats.d.ts.map +1 -0
- package/build/countryStats.js +87 -23
- package/build/countryStats.js.map +1 -0
- package/build/deployClient.d.ts +138 -24
- package/build/deployClient.d.ts.map +1 -0
- package/build/deployClient.js +91 -31
- 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 +26 -6
- package/build/freezeClient.d.ts.map +1 -0
- package/build/freezeClient.js +30 -6
- package/build/freezeClient.js.map +1 -0
- package/build/generationClient.d.ts +6 -3
- package/build/generationClient.d.ts.map +1 -0
- package/build/generationClient.js +25 -38
- package/build/generationClient.js.map +1 -0
- package/build/holderSecret.d.ts +70 -0
- package/build/holderSecret.d.ts.map +1 -0
- package/build/holderSecret.js +76 -0
- package/build/holderSecret.js.map +1 -0
- package/build/index.d.ts +38 -38
- package/build/index.d.ts.map +1 -0
- package/build/index.js +97 -121
- package/build/index.js.map +1 -0
- package/build/keysClient.d.ts +142 -0
- package/build/keysClient.d.ts.map +1 -0
- package/build/keysClient.js +109 -0
- package/build/keysClient.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 +68 -5
- package/build/licenseRecord.d.ts.map +1 -0
- package/build/licenseRecord.js +26 -1
- package/build/licenseRecord.js.map +1 -0
- package/build/licenseStore.d.ts +81 -4
- package/build/licenseStore.d.ts.map +1 -0
- package/build/licenseStore.js +400 -30
- package/build/licenseStore.js.map +1 -0
- package/build/licenseTrustless.d.ts +43 -0
- package/build/licenseTrustless.d.ts.map +1 -0
- package/build/licenseTrustless.js +180 -0
- package/build/licenseTrustless.js.map +1 -0
- package/build/manifestVerify.d.ts +29 -1
- package/build/manifestVerify.d.ts.map +1 -0
- package/build/manifestVerify.js +46 -4
- package/build/manifestVerify.js.map +1 -0
- package/build/minaPriceHistory.d.ts +9 -0
- package/build/minaPriceHistory.d.ts.map +1 -0
- package/build/minaPriceHistory.js +152 -0
- package/build/minaPriceHistory.js.map +1 -0
- package/build/onChainRoot.d.ts +60 -0
- package/build/onChainRoot.d.ts.map +1 -0
- package/build/onChainRoot.js +74 -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 +153 -0
- package/build/ownershipSignature.d.ts.map +1 -0
- package/build/ownershipSignature.js +297 -0
- package/build/ownershipSignature.js.map +1 -0
- package/build/permitCheckFlow.d.ts +155 -0
- package/build/permitCheckFlow.d.ts.map +1 -0
- package/build/permitCheckFlow.js +196 -0
- package/build/permitCheckFlow.js.map +1 -0
- package/build/permitDescribe.d.ts +124 -0
- package/build/permitDescribe.d.ts.map +1 -0
- package/build/permitDescribe.js +324 -0
- package/build/permitDescribe.js.map +1 -0
- package/build/permitInterface.d.ts +85 -0
- package/build/permitInterface.d.ts.map +1 -0
- package/build/permitInterface.js +121 -0
- package/build/permitInterface.js.map +1 -0
- package/build/permitMessages.d.ts +313 -0
- package/build/permitMessages.d.ts.map +1 -0
- package/build/permitMessages.js +462 -0
- package/build/permitMessages.js.map +1 -0
- package/build/permitProof.d.ts +108 -0
- package/build/permitProof.d.ts.map +1 -0
- package/build/permitProof.js +202 -0
- package/build/permitProof.js.map +1 -0
- package/build/permitRegistryRebuild.d.ts +166 -0
- package/build/permitRegistryRebuild.d.ts.map +1 -0
- package/build/permitRegistryRebuild.js +347 -0
- package/build/permitRegistryRebuild.js.map +1 -0
- package/build/permitTree.d.ts +88 -0
- package/build/permitTree.d.ts.map +1 -0
- package/build/permitTree.js +230 -0
- package/build/permitTree.js.map +1 -0
- package/build/permitsClient.d.ts +680 -0
- package/build/permitsClient.d.ts.map +1 -0
- package/build/permitsClient.js +597 -0
- package/build/permitsClient.js.map +1 -0
- package/build/proveErrors.d.ts +50 -0
- package/build/proveErrors.d.ts.map +1 -0
- package/build/proveErrors.js +76 -0
- package/build/proveErrors.js.map +1 -0
- package/build/receipt.d.ts +95 -0
- package/build/receipt.d.ts.map +1 -0
- package/build/receipt.js +84 -0
- package/build/receipt.js.map +1 -0
- package/build/refundClient.d.ts +7 -12
- package/build/refundClient.d.ts.map +1 -0
- package/build/refundClient.js +52 -21
- package/build/refundClient.js.map +1 -0
- package/build/registryTrustVerify.d.ts +78 -0
- package/build/registryTrustVerify.d.ts.map +1 -0
- package/build/registryTrustVerify.js +129 -0
- package/build/registryTrustVerify.js.map +1 -0
- package/build/releaseClient.d.ts +26 -0
- package/build/releaseClient.d.ts.map +1 -0
- package/build/releaseClient.js +65 -0
- package/build/releaseClient.js.map +1 -0
- package/build/renewClient.d.ts +28 -2
- package/build/renewClient.d.ts.map +1 -0
- package/build/renewClient.js +31 -27
- 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/slotConstants.d.ts +15 -0
- package/build/slotConstants.d.ts.map +1 -0
- package/build/slotConstants.js +17 -0
- package/build/slotConstants.js.map +1 -0
- package/build/statsClient.d.ts +61 -7
- package/build/statsClient.d.ts.map +1 -0
- package/build/statsClient.js +44 -5
- package/build/statsClient.js.map +1 -0
- package/build/successorChain.d.ts +35 -0
- package/build/successorChain.d.ts.map +1 -0
- package/build/successorChain.js +69 -0
- package/build/successorChain.js.map +1 -0
- package/build/taxId.d.ts +44 -0
- package/build/taxId.d.ts.map +1 -0
- package/build/taxId.js +212 -0
- package/build/taxId.js.map +1 -0
- package/build/trustAnchorVerify.d.ts +49 -0
- package/build/trustAnchorVerify.d.ts.map +1 -0
- package/build/trustAnchorVerify.js +432 -0
- package/build/trustAnchorVerify.js.map +1 -0
- package/build/trustAnchorVerifyCli.d.ts +45 -0
- package/build/trustAnchorVerifyCli.d.ts.map +1 -0
- package/build/trustAnchorVerifyCli.js +235 -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 +77 -0
- package/build/unbindClient.d.ts.map +1 -0
- package/build/unbindClient.js +169 -0
- package/build/unbindClient.js.map +1 -0
- package/build/units.d.ts +28 -0
- package/build/units.d.ts.map +1 -0
- package/build/units.js +65 -0
- package/build/units.js.map +1 -0
- package/build/vatRates.d.ts +54 -0
- package/build/vatRates.d.ts.map +1 -0
- package/build/vatRates.js +82 -0
- package/build/vatRates.js.map +1 -0
- package/build/vatRatesData.d.ts +5 -0
- package/build/vatRatesData.d.ts.map +1 -0
- package/build/vatRatesData.js +42 -0
- package/build/vatRatesData.js.map +1 -0
- package/build/vendorAccountClient.d.ts +66 -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 +4 -1
- package/build/verifyCore.d.ts.map +1 -0
- package/build/verifyCore.js +21 -10
- 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 +571 -501
- package/build/verifyService.js.map +1 -0
- package/build/verifyWithAncestors.d.ts +19 -0
- package/build/verifyWithAncestors.d.ts.map +1 -0
- package/build/verifyWithAncestors.js +127 -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 +141 -16
- package/src/agent.ts +682 -0
- package/src/agentActions.ts +637 -0
- package/src/agentRecord.ts +121 -0
- package/src/agentVendor.ts +356 -0
- package/src/appsLookup.ts +48 -0
- package/src/archiveBootstrap.ts +386 -0
- package/src/atomicJson.ts +53 -0
- package/src/bindClient.ts +297 -0
- package/src/buyClient.ts +344 -0
- package/src/chainHead.ts +106 -0
- package/src/compactMerkleMap.ts +222 -0
- package/src/contractInterface.ts +465 -0
- package/src/contractTypes.ts +31 -0
- package/src/countryStats.ts +200 -0
- package/src/deployClient.ts +517 -0
- package/src/deviceIdentity.ts +249 -0
- package/src/freezeClient.ts +162 -0
- package/src/generationClient.ts +145 -0
- package/src/holderSecret.ts +91 -0
- package/src/index.ts +362 -0
- package/src/keysClient.ts +135 -0
- package/src/licenseLeaf.ts +221 -0
- package/src/licenseRecord.ts +190 -0
- package/src/licenseStore.ts +767 -0
- package/src/licenseTrustless.ts +207 -0
- package/src/manifestVerify.ts +164 -0
- package/src/minaPriceHistory.ts +166 -0
- package/src/onChainRoot.ts +90 -0
- package/src/ownershipLicenseHash.ts +31 -0
- package/src/ownershipSignature.ts +421 -0
- package/src/permitCheckFlow.ts +227 -0
- package/src/permitDescribe.ts +362 -0
- package/src/permitInterface.ts +146 -0
- package/src/permitMessages.ts +572 -0
- package/src/permitProof.ts +230 -0
- package/src/permitRegistryRebuild.ts +423 -0
- package/src/permitTree.ts +232 -0
- package/src/permitsClient.ts +746 -0
- package/src/proveErrors.ts +98 -0
- package/src/receipt.ts +156 -0
- package/src/refundClient.ts +177 -0
- package/src/registryTrustVerify.ts +192 -0
- package/src/releaseClient.ts +101 -0
- package/src/renewClient.ts +234 -0
- package/src/seatName.ts +165 -0
- package/src/slotConstants.ts +18 -0
- package/src/statsClient.ts +249 -0
- package/src/successorChain.ts +87 -0
- package/src/taxId.ts +227 -0
- package/src/trustAnchorVerify.ts +550 -0
- package/src/trustAnchorVerifyCli.ts +234 -0
- package/src/txBroadcastClient.ts +48 -0
- package/src/unbindClient.ts +233 -0
- package/src/units.ts +74 -0
- package/src/vatRates.ts +100 -0
- package/src/vatRatesData.ts +43 -0
- package/src/vendorAccountClient.ts +120 -0
- package/src/verifyCore.ts +100 -0
- package/src/verifyOffline.ts +212 -0
- package/src/verifyService.ts +982 -0
- package/src/verifyWithAncestors.ts +163 -0
- package/src/zipToState.ts +94 -0
- package/build/licenseProof.d.ts +0 -26
- package/build/licenseProof.js +0 -41
- package/build/migrateClient.d.ts +0 -43
- package/build/migrateClient.js +0 -47
- package/build/ownership.d.ts +0 -34
- package/build/ownership.js +0 -147
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* verifyWithAncestors.ts
|
|
6
|
+
*
|
|
7
|
+
* Shared address-routing core used by both verifyService.ts and
|
|
8
|
+
* keeperService.ts. Given an already-resolved AppRecord, an already-fetched
|
|
9
|
+
* current-live on-chain root, and the current set of license records, this
|
|
10
|
+
* helper:
|
|
11
|
+
*
|
|
12
|
+
* 1. Tries verifyLicenseCore against the current live contract (a
|
|
13
|
+
* redeployed app's successor starts with its predecessor's licenses,
|
|
14
|
+
* so licenses bought on any generation land here).
|
|
15
|
+
* 2. On "License not found" in current-live, walks the app's
|
|
16
|
+
* deploymentHistory[] newest-first, fetching each retired contract's
|
|
17
|
+
* own on-chain root and re-checking with records filtered to that
|
|
18
|
+
* retired address (a request naming a retired address before the
|
|
19
|
+
* keeper carried the records over).
|
|
20
|
+
* 3. Applies one lazy-bootstrap replay per address on
|
|
21
|
+
* "License state does not match on-chain root" — same self-heal the
|
|
22
|
+
* callers used to do inline.
|
|
23
|
+
*
|
|
24
|
+
* The helper does NOT do VK-hash validation or version admission — those
|
|
25
|
+
* are caller-specific policy (verifyService uses per-generation
|
|
26
|
+
* CANONICAL_VK_HASHES; the backend uses its single compiled canonicalVkHash).
|
|
27
|
+
* Callers do their VK check up front against the current-live account they
|
|
28
|
+
* fetched, then hand the fetched root here.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { PublicKey, fetchAccount } from 'o1js';
|
|
32
|
+
import { LICENSING_APP_STATE } from './contractInterface.js';
|
|
33
|
+
import { verifyLicenseCore, type VerifyResponse } from './verifyCore.js';
|
|
34
|
+
import { readRecords, type LicenseRecord } from './licenseStore.js';
|
|
35
|
+
import { lazyBootstrap } from './archiveBootstrap.js';
|
|
36
|
+
import type { LookupableDeployment } from './appsLookup.js';
|
|
37
|
+
|
|
38
|
+
export type VerifyWithAncestorsInput = {
|
|
39
|
+
// The per-network deployment slice (current live address + retired history).
|
|
40
|
+
// Callers project this from the resolved AppRecord: for a verify request the
|
|
41
|
+
// caller determines which network's deployment to walk (typically the one
|
|
42
|
+
// whose current address matched, or the one the client-pinned address lives
|
|
43
|
+
// on). Cross-network walks aren't needed — mainnet and devnet each keep
|
|
44
|
+
// their own generation history.
|
|
45
|
+
deployment: LookupableDeployment;
|
|
46
|
+
licenseHash: string;
|
|
47
|
+
currentSlot: number;
|
|
48
|
+
currentLiveRoot: string;
|
|
49
|
+
// The current live app's forkActivationSlot state (0 or absent: none).
|
|
50
|
+
currentLiveForkSlot?: number;
|
|
51
|
+
// Callers pre-load records in parallel with the current-live fetch. The
|
|
52
|
+
// helper may reload once after a lazy-bootstrap replay, so also returns
|
|
53
|
+
// the (possibly refreshed) records for the caller to reuse when looking
|
|
54
|
+
// up per-record fields like purchaseSlot.
|
|
55
|
+
records: LicenseRecord[];
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type VerifyWithAncestorsResult = {
|
|
59
|
+
result: VerifyResponse;
|
|
60
|
+
// Address the license was actually found under — usually the current live
|
|
61
|
+
// one, but falls back to a retired address for pre-bump buyers. Callers
|
|
62
|
+
// must key any LicenseRecord lookup on this, not on the request address.
|
|
63
|
+
resolvedAddress: string;
|
|
64
|
+
onChainRoot: string;
|
|
65
|
+
liveRecords: LicenseRecord[];
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// One-shot internal retry for a single network call. Absorbs a lone
|
|
69
|
+
// transient blip from the Mina GraphQL node. Duplicated shape from
|
|
70
|
+
// verifyService's fetchWithOneRetry — kept local to this module so the
|
|
71
|
+
// helper stays self-contained and the two callers don't need to inject
|
|
72
|
+
// their own retry strategy.
|
|
73
|
+
async function fetchWithOneRetry<T>(fn: () => Promise<T>, delayMs = 500): Promise<T> {
|
|
74
|
+
try {
|
|
75
|
+
return await fn();
|
|
76
|
+
} catch {
|
|
77
|
+
await new Promise(r => setTimeout(r, delayMs));
|
|
78
|
+
return fn();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function verifyLicenseWithAncestors(
|
|
83
|
+
input: VerifyWithAncestorsInput,
|
|
84
|
+
): Promise<VerifyWithAncestorsResult> {
|
|
85
|
+
const { deployment, licenseHash, currentSlot, currentLiveRoot } = input;
|
|
86
|
+
let liveRecords = input.records;
|
|
87
|
+
const currentLive = deployment.zkAppAddress;
|
|
88
|
+
|
|
89
|
+
// Step 1: try current-live first.
|
|
90
|
+
let result = verifyLicenseCore({
|
|
91
|
+
zkAppAddress: currentLive,
|
|
92
|
+
licenseHash,
|
|
93
|
+
records: liveRecords,
|
|
94
|
+
onChainRoot: currentLiveRoot,
|
|
95
|
+
currentSlot,
|
|
96
|
+
forkActivationSlot: input.currentLiveForkSlot,
|
|
97
|
+
});
|
|
98
|
+
if (!result.valid && result.reason === 'License state does not match on-chain root') {
|
|
99
|
+
// Local Merkle root diverged from on-chain — either the archive-sync loop
|
|
100
|
+
// hasn't caught up yet or (bug) the local mirror silently drifted. Log the
|
|
101
|
+
// trigger so operators can correlate a spike of these with either a lag
|
|
102
|
+
// window or a genuine drift regression.
|
|
103
|
+
console.log(`[lazy-bootstrap] triggered current-live=${currentLive.slice(0, 12)}… licenseHash=${licenseHash.slice(0, 12)}… reason=root-mismatch`);
|
|
104
|
+
await lazyBootstrap(currentLive);
|
|
105
|
+
liveRecords = await readRecords();
|
|
106
|
+
result = verifyLicenseCore({
|
|
107
|
+
zkAppAddress: currentLive,
|
|
108
|
+
licenseHash,
|
|
109
|
+
records: liveRecords,
|
|
110
|
+
onChainRoot: currentLiveRoot,
|
|
111
|
+
currentSlot,
|
|
112
|
+
forkActivationSlot: input.currentLiveForkSlot,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (result.valid || result.reason !== 'License not found') {
|
|
116
|
+
return { result, resolvedAddress: currentLive, onChainRoot: currentLiveRoot, liveRecords };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Step 2: walk retired addresses newest-first.
|
|
120
|
+
const retiredAddrs = (deployment.deploymentHistory ?? []).map(d => d.zkAppAddress).reverse();
|
|
121
|
+
for (const retired of retiredAddrs) {
|
|
122
|
+
let retiredAccount;
|
|
123
|
+
try {
|
|
124
|
+
const fetched = await fetchWithOneRetry(() => fetchAccount({ publicKey: PublicKey.fromBase58(retired) }));
|
|
125
|
+
retiredAccount = fetched.account;
|
|
126
|
+
} catch {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const retiredRoot = retiredAccount?.zkapp?.appState?.[0]?.toString();
|
|
130
|
+
if (!retiredRoot) continue;
|
|
131
|
+
const retiredForkSlot = Number(retiredAccount?.zkapp?.appState?.[LICENSING_APP_STATE.forkActivationSlot]?.toString() ?? '0');
|
|
132
|
+
let retiredResult = verifyLicenseCore({
|
|
133
|
+
zkAppAddress: retired,
|
|
134
|
+
licenseHash,
|
|
135
|
+
records: liveRecords,
|
|
136
|
+
onChainRoot: retiredRoot,
|
|
137
|
+
currentSlot,
|
|
138
|
+
forkActivationSlot: retiredForkSlot,
|
|
139
|
+
});
|
|
140
|
+
if (!retiredResult.valid && retiredResult.reason === 'License state does not match on-chain root') {
|
|
141
|
+
// Same trigger as the current-live path but on a retired generation —
|
|
142
|
+
// e.g. a pre-bump buyer's request address never got its full history
|
|
143
|
+
// replayed after the process restart.
|
|
144
|
+
console.log(`[lazy-bootstrap] triggered retired=${retired.slice(0, 12)}… licenseHash=${licenseHash.slice(0, 12)}… reason=root-mismatch`);
|
|
145
|
+
await lazyBootstrap(retired);
|
|
146
|
+
liveRecords = await readRecords();
|
|
147
|
+
retiredResult = verifyLicenseCore({
|
|
148
|
+
zkAppAddress: retired,
|
|
149
|
+
licenseHash,
|
|
150
|
+
records: liveRecords,
|
|
151
|
+
onChainRoot: retiredRoot,
|
|
152
|
+
currentSlot,
|
|
153
|
+
forkActivationSlot: retiredForkSlot,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (retiredResult.valid || retiredResult.reason !== 'License not found') {
|
|
157
|
+
return { result: retiredResult, resolvedAddress: retired, onChainRoot: retiredRoot, liveRecords };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Not found anywhere — return the current-live "License not found" verdict.
|
|
162
|
+
return { result, resolvedAddress: currentLive, onChainRoot: currentLiveRoot, liveRecords };
|
|
163
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* zipToState.ts
|
|
6
|
+
*
|
|
7
|
+
* US ZIP-code prefix → 2-letter state code lookup. Used by countryStats.ts to
|
|
8
|
+
* roll US buyers up into per-state buckets for sales-tax reporting. Prefix is
|
|
9
|
+
* the first three digits of the ZIP; every US ZIP starts with three digits
|
|
10
|
+
* that resolve to exactly one state (source: USPS ZIP Code Directory).
|
|
11
|
+
*
|
|
12
|
+
* Data model: inclusive [lo, hi] prefix ranges → state code. Ranges are
|
|
13
|
+
* ordered by lo for readability but the lookup does a linear scan since the
|
|
14
|
+
* table is small (~55 rows) and this runs once per record on a background
|
|
15
|
+
* aggregation, not in a hot loop.
|
|
16
|
+
*
|
|
17
|
+
* Coverage: 50 states, DC, military APO/FPO (AA/AE/AP), Puerto Rico (PR), Guam
|
|
18
|
+
* and adjacent Pacific territories (GU). US Virgin Islands (VI), American
|
|
19
|
+
* Samoa (AS), and Northern Mariana Islands (MP) share prefixes with the
|
|
20
|
+
* Pacific block; we return 'GU' for that range — good enough for
|
|
21
|
+
* digital-goods reporting where those territories don't have their own tax.
|
|
22
|
+
* Returns undefined for prefixes that don't map (very few — USPS reserves
|
|
23
|
+
* some for future assignment).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const RANGES: ReadonlyArray<readonly [number, number, string]> = [
|
|
27
|
+
[ 5, 5, 'NY'],
|
|
28
|
+
[ 6, 9, 'PR'],
|
|
29
|
+
[ 10, 27, 'MA'],
|
|
30
|
+
[ 28, 29, 'RI'],
|
|
31
|
+
[ 30, 38, 'NH'],
|
|
32
|
+
[ 39, 49, 'ME'],
|
|
33
|
+
[ 50, 59, 'VT'],
|
|
34
|
+
[ 60, 69, 'CT'],
|
|
35
|
+
[ 70, 89, 'NJ'],
|
|
36
|
+
[ 90, 99, 'AE'],
|
|
37
|
+
[100, 149, 'NY'],
|
|
38
|
+
[150, 196, 'PA'],
|
|
39
|
+
[197, 199, 'DE'],
|
|
40
|
+
[200, 205, 'DC'],
|
|
41
|
+
[206, 219, 'MD'],
|
|
42
|
+
[220, 246, 'VA'],
|
|
43
|
+
[247, 268, 'WV'],
|
|
44
|
+
[270, 289, 'NC'],
|
|
45
|
+
[290, 299, 'SC'],
|
|
46
|
+
[300, 319, 'GA'],
|
|
47
|
+
[320, 349, 'FL'],
|
|
48
|
+
[350, 369, 'AL'],
|
|
49
|
+
[370, 385, 'TN'],
|
|
50
|
+
[386, 397, 'MS'],
|
|
51
|
+
[398, 399, 'GA'],
|
|
52
|
+
[400, 427, 'KY'],
|
|
53
|
+
[430, 459, 'OH'],
|
|
54
|
+
[460, 479, 'IN'],
|
|
55
|
+
[480, 499, 'MI'],
|
|
56
|
+
[500, 528, 'IA'],
|
|
57
|
+
[530, 549, 'WI'],
|
|
58
|
+
[550, 567, 'MN'],
|
|
59
|
+
[570, 577, 'SD'],
|
|
60
|
+
[580, 588, 'ND'],
|
|
61
|
+
[590, 599, 'MT'],
|
|
62
|
+
[600, 629, 'IL'],
|
|
63
|
+
[630, 658, 'MO'],
|
|
64
|
+
[660, 679, 'KS'],
|
|
65
|
+
[680, 693, 'NE'],
|
|
66
|
+
[700, 714, 'LA'],
|
|
67
|
+
[716, 729, 'AR'],
|
|
68
|
+
[730, 749, 'OK'],
|
|
69
|
+
[750, 799, 'TX'],
|
|
70
|
+
[800, 816, 'CO'],
|
|
71
|
+
[820, 831, 'WY'],
|
|
72
|
+
[832, 838, 'ID'],
|
|
73
|
+
[840, 847, 'UT'],
|
|
74
|
+
[850, 865, 'AZ'],
|
|
75
|
+
[870, 884, 'NM'],
|
|
76
|
+
[889, 898, 'NV'],
|
|
77
|
+
[900, 961, 'CA'],
|
|
78
|
+
[962, 966, 'AP'],
|
|
79
|
+
[967, 968, 'HI'],
|
|
80
|
+
[969, 969, 'GU'],
|
|
81
|
+
[970, 979, 'OR'],
|
|
82
|
+
[980, 994, 'WA'],
|
|
83
|
+
[995, 999, 'AK'],
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
export function zipToState(zip: string): string | undefined {
|
|
87
|
+
const m = /^(\d{3})/.exec(zip);
|
|
88
|
+
if (!m) return undefined;
|
|
89
|
+
const n = parseInt(m[1], 10);
|
|
90
|
+
for (const [lo, hi, st] of RANGES) {
|
|
91
|
+
if (n >= lo && n <= hi) return st;
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
package/build/licenseProof.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// Hand-written declarations for licenseProof.ts.
|
|
2
|
-
// tsc can't emit these automatically because the inferred return types of
|
|
3
|
-
// Struct() and ZkProgram() reference internal o1js paths outside this
|
|
4
|
-
// package's rootDir, triggering TS2742. Callers get full typing on the
|
|
5
|
-
// methods they actually invoke by importing the corresponding o1js types
|
|
6
|
-
// directly (Field, Proof, etc.) in their own code.
|
|
7
|
-
|
|
8
|
-
export const OwnershipChallenge: any;
|
|
9
|
-
export type OwnershipChallenge = any;
|
|
10
|
-
|
|
11
|
-
export const LicenseProof: any;
|
|
12
|
-
|
|
13
|
-
export class LicenseProofProof {
|
|
14
|
-
static publicInputType: any;
|
|
15
|
-
static publicOutputType: any;
|
|
16
|
-
static fromJSON(json: any): Promise<LicenseProofProof>;
|
|
17
|
-
static dummy(...args: any[]): Promise<LicenseProofProof>;
|
|
18
|
-
publicInput: any;
|
|
19
|
-
publicOutput: any;
|
|
20
|
-
proof: any;
|
|
21
|
-
maxProofsVerified: 0 | 1 | 2;
|
|
22
|
-
shouldVerify: any;
|
|
23
|
-
verify(): void;
|
|
24
|
-
verifyIf(condition: any): void;
|
|
25
|
-
toJSON(): { publicInput: string[]; publicOutput: string[]; maxProofsVerified: 0 | 1 | 2; proof: string };
|
|
26
|
-
}
|
package/build/licenseProof.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
-
// All rights reserved.
|
|
3
|
-
/**
|
|
4
|
-
* licenseProof.ts — ZkProgram for ownership challenge-response.
|
|
5
|
-
*
|
|
6
|
-
* Loaded only when the caller needs to *produce* an ownership proof on the
|
|
7
|
-
* client (the verify path never imports this file). Lives in a dedicated
|
|
8
|
-
* subpath (`zklicensing/prove`) so the verify-only entry stays free of o1js.
|
|
9
|
-
*
|
|
10
|
-
* Proves: Poseidon.hash([secretHash]) === licenseHash
|
|
11
|
-
* where secretHash = Poseidon.hash(Encoding.stringToFields(rawSecret)).
|
|
12
|
-
*
|
|
13
|
-
* The nonce sits in the public input. Its sole purpose is replay-resistance:
|
|
14
|
-
* a proof generated for nonce A is mathematically distinct from one for nonce
|
|
15
|
-
* B, so a verifier that issued nonce A will reject any proof not produced for
|
|
16
|
-
* exactly that challenge.
|
|
17
|
-
*/
|
|
18
|
-
import { ZkProgram, Field, Poseidon, Struct } from 'o1js';
|
|
19
|
-
// Struct() / ZkProgram / ZkProgram.Proof() return types reference o1js
|
|
20
|
-
// internal paths outside this package's rootDir, triggering TS2742 on
|
|
21
|
-
// declaration emit. Annotating each export as `any` suppresses the inference;
|
|
22
|
-
// consumers get real types via the hand-written licenseProof.d.ts shim.
|
|
23
|
-
// See contractInterface.ts for the longer rationale on why this workaround.
|
|
24
|
-
export const OwnershipChallenge = Struct({
|
|
25
|
-
licenseHash: Field,
|
|
26
|
-
nonce: Field,
|
|
27
|
-
});
|
|
28
|
-
export const LicenseProof = ZkProgram({
|
|
29
|
-
name: 'license-proof',
|
|
30
|
-
publicInput: OwnershipChallenge,
|
|
31
|
-
methods: {
|
|
32
|
-
prove: {
|
|
33
|
-
privateInputs: [Field], // secretHash — never sent anywhere
|
|
34
|
-
async method(pub, secretHash) {
|
|
35
|
-
Poseidon.hash([secretHash]).assertEquals(pub.licenseHash);
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
export const LicenseProofProof = ZkProgram.Proof(LicenseProof);
|
|
41
|
-
//# sourceMappingURL=licenseProof.js.map
|
package/build/migrateClient.d.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* migrateClient.ts
|
|
3
|
-
*
|
|
4
|
-
* Browser-safe client for /prove/migrate. Assembles a single-hop cross-
|
|
5
|
-
* generation proof against the current live map — the keeper walks the
|
|
6
|
-
* deploymentHistory once, gathers all three witnesses (ancestor / pred /
|
|
7
|
-
* live-empty), and returns a signable tx.
|
|
8
|
-
*
|
|
9
|
-
* Failure surfaces:
|
|
10
|
-
* - 404 "license refunded or unknown": no leaf anywhere in history for
|
|
11
|
-
* this licenseHash. Caller should not retry — it's terminal.
|
|
12
|
-
* - 409 "already migrated": leaf is present in the live map. Caller
|
|
13
|
-
* should refresh their license record and stop.
|
|
14
|
-
* - 409 "migration in flight": another caller is proving right now.
|
|
15
|
-
* `retryAfterMs` on the error tells the caller how long to wait
|
|
16
|
-
* before trying again. See `ProveMigrateError.retryAfterMs`.
|
|
17
|
-
*/
|
|
18
|
-
export interface ProveMigrateRequest {
|
|
19
|
-
keeperUrl: string;
|
|
20
|
-
licenseHash: string;
|
|
21
|
-
appId: string;
|
|
22
|
-
buyerAddress: string;
|
|
23
|
-
fetcher?: typeof fetch;
|
|
24
|
-
signal?: AbortSignal;
|
|
25
|
-
}
|
|
26
|
-
export interface ProveMigrateResponse {
|
|
27
|
-
provenTxJson: string;
|
|
28
|
-
ancestorGen: number;
|
|
29
|
-
expirySlot: number;
|
|
30
|
-
licenseHash: string;
|
|
31
|
-
zkAppAddress: string;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Extends Error with the retryAfterMs hint the keeper returns on the
|
|
35
|
-
* "migration in flight" 409. Callers ignore it for other 4xx surfaces.
|
|
36
|
-
*/
|
|
37
|
-
export declare class ProveMigrateError extends Error {
|
|
38
|
-
readonly status: number;
|
|
39
|
-
readonly retryAfterMs?: number;
|
|
40
|
-
constructor(message: string, status: number, retryAfterMs?: number);
|
|
41
|
-
}
|
|
42
|
-
export declare function proveMigrate(req: ProveMigrateRequest): Promise<ProveMigrateResponse>;
|
|
43
|
-
//# sourceMappingURL=migrateClient.d.ts.map
|
package/build/migrateClient.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
-
// All rights reserved.
|
|
3
|
-
/**
|
|
4
|
-
* Extends Error with the retryAfterMs hint the keeper returns on the
|
|
5
|
-
* "migration in flight" 409. Callers ignore it for other 4xx surfaces.
|
|
6
|
-
*/
|
|
7
|
-
export class ProveMigrateError extends Error {
|
|
8
|
-
status;
|
|
9
|
-
retryAfterMs;
|
|
10
|
-
constructor(message, status, retryAfterMs) {
|
|
11
|
-
super(message);
|
|
12
|
-
this.name = 'ProveMigrateError';
|
|
13
|
-
this.status = status;
|
|
14
|
-
this.retryAfterMs = retryAfterMs;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function baseUrl(url) {
|
|
18
|
-
return url.replace(/\/+$/, '');
|
|
19
|
-
}
|
|
20
|
-
export async function proveMigrate(req) {
|
|
21
|
-
const fetcher = req.fetcher ?? fetch;
|
|
22
|
-
const resp = await fetcher(`${baseUrl(req.keeperUrl)}/prove/migrate`, {
|
|
23
|
-
method: 'POST',
|
|
24
|
-
headers: { 'Content-Type': 'application/json' },
|
|
25
|
-
signal: req.signal,
|
|
26
|
-
body: JSON.stringify({
|
|
27
|
-
licenseHash: req.licenseHash,
|
|
28
|
-
appId: req.appId,
|
|
29
|
-
buyerAddress: req.buyerAddress,
|
|
30
|
-
}),
|
|
31
|
-
});
|
|
32
|
-
if (!resp.ok) {
|
|
33
|
-
let msg = `HTTP ${resp.status}`;
|
|
34
|
-
let retryAfterMs;
|
|
35
|
-
try {
|
|
36
|
-
const body = await resp.json();
|
|
37
|
-
if (typeof body.error === 'string')
|
|
38
|
-
msg = body.error;
|
|
39
|
-
if (typeof body.retryAfterMs === 'number')
|
|
40
|
-
retryAfterMs = body.retryAfterMs;
|
|
41
|
-
}
|
|
42
|
-
catch { /* body wasn't JSON */ }
|
|
43
|
-
throw new ProveMigrateError(msg, resp.status, retryAfterMs);
|
|
44
|
-
}
|
|
45
|
-
return await resp.json();
|
|
46
|
-
}
|
|
47
|
-
//# sourceMappingURL=migrateClient.js.map
|
package/build/ownership.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export declare const OWNERSHIP_CHALLENGE_TTL_MS = 600000;
|
|
2
|
-
export declare const OWNERSHIP_TOKEN_TTL_MS: number;
|
|
3
|
-
export type OwnershipTokenPayload = {
|
|
4
|
-
z: string;
|
|
5
|
-
l: string;
|
|
6
|
-
e: number;
|
|
7
|
-
jti?: string;
|
|
8
|
-
};
|
|
9
|
-
export declare function newJti(): string;
|
|
10
|
-
export type ChallengeStore = {
|
|
11
|
-
issue(licenseHash: string): {
|
|
12
|
-
nonce: string;
|
|
13
|
-
ttl: number;
|
|
14
|
-
};
|
|
15
|
-
consume(licenseHash: string, nonce: string): 'ok' | 'unknown' | 'expired';
|
|
16
|
-
size(): number;
|
|
17
|
-
};
|
|
18
|
-
export declare function createChallengeStore(ttlMs?: number): ChallengeStore;
|
|
19
|
-
export declare function signOwnershipToken(key: Buffer, payload: OwnershipTokenPayload): string;
|
|
20
|
-
export declare function verifyOwnershipToken(key: Buffer, token: string): OwnershipTokenPayload | null;
|
|
21
|
-
export declare function newOwnershipKey(): Buffer;
|
|
22
|
-
export type SessionStore = {
|
|
23
|
-
insert(licenseHash: string, jti: string, exp: number, cap: number): {
|
|
24
|
-
state: 'ok' | 'at-cap';
|
|
25
|
-
active: number;
|
|
26
|
-
};
|
|
27
|
-
has(licenseHash: string, jti: string): boolean;
|
|
28
|
-
releaseSeat(licenseHash: string, jti: string): boolean;
|
|
29
|
-
reset(licenseHash: string): number;
|
|
30
|
-
activeCount(licenseHash: string): number;
|
|
31
|
-
size(): number;
|
|
32
|
-
};
|
|
33
|
-
export declare function createSessionStore(): SessionStore;
|
|
34
|
-
//# sourceMappingURL=ownership.d.ts.map
|
package/build/ownership.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
-
// All rights reserved.
|
|
3
|
-
/**
|
|
4
|
-
* ownership.ts
|
|
5
|
-
*
|
|
6
|
-
* Ownership-token helpers and a small in-memory nonce store for the
|
|
7
|
-
* challenge-response /verify flow.
|
|
8
|
-
*
|
|
9
|
-
* Replay-resistance: the LicenseProof's public input binds (licenseHash,
|
|
10
|
-
* nonce). The keeper hands out a nonce, the client proves against it, the
|
|
11
|
-
* keeper consumes the nonce on the way through. Tokens are HMAC-SHA256 of
|
|
12
|
-
* the (zkAppAddress, licenseHash, exp, jti?) tuple so signature validation
|
|
13
|
-
* is purely cryptographic — no server-side lookup, restart-safe as long as
|
|
14
|
-
* the HMAC key persists.
|
|
15
|
-
*
|
|
16
|
-
* Session tracking: the optional `jti` field lets the caller run a
|
|
17
|
-
* revocation / concurrency layer on top of the stateless HMAC — the token
|
|
18
|
-
* is still validated cryptographically, but the caller can also check that
|
|
19
|
-
* the jti is present in a per-license active-session set. Absent jti keeps
|
|
20
|
-
* old callers working unchanged (there is no session tracking to begin with,
|
|
21
|
-
* so nothing needs to migrate).
|
|
22
|
-
*/
|
|
23
|
-
import { createHmac, randomBytes, timingSafeEqual } from 'crypto';
|
|
24
|
-
import { Field } from 'o1js';
|
|
25
|
-
export const OWNERSHIP_CHALLENGE_TTL_MS = 600_000;
|
|
26
|
-
// A device that stays active refreshes via a fresh /challenge + /respond;
|
|
27
|
-
// a lost/uninstalled device burns its slot for at most this long before
|
|
28
|
-
// the server prunes it (see verifyService session store). 7 days keeps
|
|
29
|
-
// re-prove pressure low on daily-use apps while still bounding the recovery
|
|
30
|
-
// window for owners hitting the concurrent-device cap.
|
|
31
|
-
export const OWNERSHIP_TOKEN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
32
|
-
// Generate a 128-bit random jti. base64url so it drops into token payloads
|
|
33
|
-
// and query strings without escaping.
|
|
34
|
-
export function newJti() {
|
|
35
|
-
return randomBytes(16).toString('base64url');
|
|
36
|
-
}
|
|
37
|
-
export function createChallengeStore(ttlMs = OWNERSHIP_CHALLENGE_TTL_MS) {
|
|
38
|
-
const issued = new Map(); // `${lh}:${nonce}` → expiresAt
|
|
39
|
-
return {
|
|
40
|
-
issue(licenseHash) {
|
|
41
|
-
const nonce = Field.random().toString();
|
|
42
|
-
issued.set(`${licenseHash}:${nonce}`, Date.now() + ttlMs);
|
|
43
|
-
return { nonce, ttl: ttlMs };
|
|
44
|
-
},
|
|
45
|
-
consume(licenseHash, nonce) {
|
|
46
|
-
const key = `${licenseHash}:${nonce}`;
|
|
47
|
-
const expiresAt = issued.get(key);
|
|
48
|
-
if (expiresAt === undefined)
|
|
49
|
-
return 'unknown';
|
|
50
|
-
issued.delete(key);
|
|
51
|
-
if (Date.now() > expiresAt)
|
|
52
|
-
return 'expired';
|
|
53
|
-
return 'ok';
|
|
54
|
-
},
|
|
55
|
-
size: () => issued.size,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
// --- token signing -----------------------------------------------------------
|
|
59
|
-
export function signOwnershipToken(key, payload) {
|
|
60
|
-
const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
|
|
61
|
-
const mac = createHmac('sha256', key).update(body).digest('base64url');
|
|
62
|
-
return `${body}.${mac}`;
|
|
63
|
-
}
|
|
64
|
-
export function verifyOwnershipToken(key, token) {
|
|
65
|
-
const dot = token.indexOf('.');
|
|
66
|
-
if (dot < 0)
|
|
67
|
-
return null;
|
|
68
|
-
const body = token.slice(0, dot);
|
|
69
|
-
const mac = token.slice(dot + 1);
|
|
70
|
-
const expected = createHmac('sha256', key).update(body).digest('base64url');
|
|
71
|
-
const a = Buffer.from(mac);
|
|
72
|
-
const b = Buffer.from(expected);
|
|
73
|
-
if (a.length !== b.length || !timingSafeEqual(a, b))
|
|
74
|
-
return null;
|
|
75
|
-
try {
|
|
76
|
-
const payload = JSON.parse(Buffer.from(body, 'base64url').toString('utf8'));
|
|
77
|
-
if (Date.now() > payload.e)
|
|
78
|
-
return null;
|
|
79
|
-
return payload;
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
export function newOwnershipKey() {
|
|
86
|
-
return randomBytes(32);
|
|
87
|
-
}
|
|
88
|
-
export function createSessionStore() {
|
|
89
|
-
// licenseHash → jti → expiresAt
|
|
90
|
-
const sessions = new Map();
|
|
91
|
-
const pruneLicense = (licenseHash) => {
|
|
92
|
-
const perLic = sessions.get(licenseHash);
|
|
93
|
-
if (!perLic)
|
|
94
|
-
return undefined;
|
|
95
|
-
const now = Date.now();
|
|
96
|
-
for (const [jti, exp] of perLic)
|
|
97
|
-
if (exp <= now)
|
|
98
|
-
perLic.delete(jti);
|
|
99
|
-
if (perLic.size === 0) {
|
|
100
|
-
sessions.delete(licenseHash);
|
|
101
|
-
return undefined;
|
|
102
|
-
}
|
|
103
|
-
return perLic;
|
|
104
|
-
};
|
|
105
|
-
return {
|
|
106
|
-
insert(licenseHash, jti, exp, cap) {
|
|
107
|
-
const perLic = pruneLicense(licenseHash) ?? new Map();
|
|
108
|
-
if (cap > 0 && perLic.size >= cap && !perLic.has(jti)) {
|
|
109
|
-
return { state: 'at-cap', active: perLic.size };
|
|
110
|
-
}
|
|
111
|
-
perLic.set(jti, exp);
|
|
112
|
-
sessions.set(licenseHash, perLic);
|
|
113
|
-
return { state: 'ok', active: perLic.size };
|
|
114
|
-
},
|
|
115
|
-
has(licenseHash, jti) {
|
|
116
|
-
const perLic = pruneLicense(licenseHash);
|
|
117
|
-
return perLic?.has(jti) ?? false;
|
|
118
|
-
},
|
|
119
|
-
releaseSeat(licenseHash, jti) {
|
|
120
|
-
const perLic = sessions.get(licenseHash);
|
|
121
|
-
if (!perLic)
|
|
122
|
-
return false;
|
|
123
|
-
const had = perLic.delete(jti);
|
|
124
|
-
if (perLic.size === 0)
|
|
125
|
-
sessions.delete(licenseHash);
|
|
126
|
-
return had;
|
|
127
|
-
},
|
|
128
|
-
reset(licenseHash) {
|
|
129
|
-
const perLic = sessions.get(licenseHash);
|
|
130
|
-
if (!perLic)
|
|
131
|
-
return 0;
|
|
132
|
-
const n = perLic.size;
|
|
133
|
-
sessions.delete(licenseHash);
|
|
134
|
-
return n;
|
|
135
|
-
},
|
|
136
|
-
activeCount(licenseHash) {
|
|
137
|
-
return pruneLicense(licenseHash)?.size ?? 0;
|
|
138
|
-
},
|
|
139
|
-
size() {
|
|
140
|
-
let n = 0;
|
|
141
|
-
for (const perLic of sessions.values())
|
|
142
|
-
n += perLic.size;
|
|
143
|
-
return n;
|
|
144
|
-
},
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
//# sourceMappingURL=ownership.js.map
|