@sip-protocol/sdk 0.7.3 → 0.7.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/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +47556 -19603
- package/dist/browser.mjs +628 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
- package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48396 -19623
- package/dist/index.mjs +537 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +54 -21
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +252 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +47 -6
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +186 -33
- package/src/chains/solana/providers/index.ts +31 -0
- package/src/chains/solana/providers/interface.ts +61 -18
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +338 -67
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +83 -66
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +57 -6
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +23 -0
- package/src/compliance/range-sas.ts +398 -33
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +686 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +254 -4
- package/src/privacy-backends/interface.ts +649 -6
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash.ts +13 -17
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +414 -2
- package/src/privacy-backends/router.ts +283 -3
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +3 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +110 -29
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-2XIVXWHA.mjs +0 -1930
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-7RFRWDCW.mjs +0 -1504
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-F6F73W35.mjs +0 -16166
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-OFDBEIEK.mjs +0 -16166
- package/dist/chunk-SF7YSLF5.mjs +0 -1515
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/chunk-WWUSGOXE.mjs +0 -17129
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-B71aXVzk.d.ts +0 -13264
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-pOIIuwfV.d.mts +0 -13264
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-4O4K45VU.mjs +0 -46
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-NDABAZ6P.mjs +0 -56
- package/dist/solana-Q4NAVBTS.mjs +0 -46
- package/dist/solana-ZYO63LY5.mjs +0 -46
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Tier Cache Implementation for Proof Caching
|
|
3
|
+
*
|
|
4
|
+
* @module proofs/cache/multi-tier-cache
|
|
5
|
+
* @description Combines in-memory LRU and persistent caching with write/read-through
|
|
6
|
+
*
|
|
7
|
+
* M20-13: Implement proof caching layer (#313)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { SingleProof } from '@sip-protocol/types'
|
|
11
|
+
import type {
|
|
12
|
+
CacheKey,
|
|
13
|
+
CacheKeyComponents,
|
|
14
|
+
CacheLookupResult,
|
|
15
|
+
ProofCacheStats,
|
|
16
|
+
CacheEvent,
|
|
17
|
+
CacheEventListener,
|
|
18
|
+
MultiTierCacheConfig,
|
|
19
|
+
CacheWarmingConfig,
|
|
20
|
+
WarmingResult,
|
|
21
|
+
InvalidationRule,
|
|
22
|
+
ILRUCache,
|
|
23
|
+
IPersistentCache,
|
|
24
|
+
IMultiTierCache,
|
|
25
|
+
} from './interface'
|
|
26
|
+
import { DEFAULT_MULTI_TIER_CONFIG, DEFAULT_WARMING_CONFIG } from './interface'
|
|
27
|
+
import { LRUCache } from './lru-cache'
|
|
28
|
+
import { createPersistentCache } from './persistent-cache'
|
|
29
|
+
|
|
30
|
+
// ─── Multi-Tier Cache Implementation ─────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Multi-tier cache combining in-memory LRU with optional persistent storage
|
|
34
|
+
*/
|
|
35
|
+
export class MultiTierCache<T = SingleProof> implements IMultiTierCache<T> {
|
|
36
|
+
private readonly config: MultiTierCacheConfig
|
|
37
|
+
private readonly memoryCache: ILRUCache<T>
|
|
38
|
+
private readonly persistentCache: IPersistentCache<T> | null = null
|
|
39
|
+
private readonly listeners: Set<CacheEventListener> = new Set()
|
|
40
|
+
|
|
41
|
+
private warmingConfig: CacheWarmingConfig = DEFAULT_WARMING_CONFIG
|
|
42
|
+
private warmingInterval: ReturnType<typeof setInterval> | null = null
|
|
43
|
+
private warmingGenerator: ((key: CacheKeyComponents) => Promise<T>) | null = null
|
|
44
|
+
|
|
45
|
+
// Track access patterns for warming predictions
|
|
46
|
+
private accessHistory: Array<{ key: string; timestamp: number }> = []
|
|
47
|
+
private readonly maxHistorySize = 1000
|
|
48
|
+
|
|
49
|
+
constructor(
|
|
50
|
+
config: Partial<MultiTierCacheConfig> = {},
|
|
51
|
+
persistentConfig?: Parameters<typeof createPersistentCache>[0]
|
|
52
|
+
) {
|
|
53
|
+
this.config = { ...DEFAULT_MULTI_TIER_CONFIG, ...config }
|
|
54
|
+
|
|
55
|
+
// Initialize memory cache
|
|
56
|
+
this.memoryCache = new LRUCache<T>(this.config.memory)
|
|
57
|
+
|
|
58
|
+
// Initialize persistent cache if configured
|
|
59
|
+
if (this.config.persistent || persistentConfig) {
|
|
60
|
+
try {
|
|
61
|
+
this.persistentCache = createPersistentCache<T>(
|
|
62
|
+
persistentConfig ?? this.config.persistent
|
|
63
|
+
)
|
|
64
|
+
} catch {
|
|
65
|
+
// Persistent cache not available in this environment
|
|
66
|
+
this.persistentCache = null
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Forward events from memory cache
|
|
71
|
+
this.memoryCache.addEventListener((event) => {
|
|
72
|
+
this.emitEvent(event)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// Forward events from persistent cache
|
|
76
|
+
if (this.persistentCache) {
|
|
77
|
+
this.persistentCache.addEventListener((event) => {
|
|
78
|
+
this.emitEvent({ ...event, data: { ...event.data, tier: 'persistent' } })
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Initialize the multi-tier cache
|
|
85
|
+
*/
|
|
86
|
+
async initialize(): Promise<void> {
|
|
87
|
+
if (this.persistentCache) {
|
|
88
|
+
await this.persistentCache.initialize()
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get an entry from the cache
|
|
94
|
+
*/
|
|
95
|
+
async get(key: CacheKey | string): Promise<CacheLookupResult<T>> {
|
|
96
|
+
const keyStr = typeof key === 'string' ? key : key.key
|
|
97
|
+
|
|
98
|
+
// Track access for warming predictions
|
|
99
|
+
this.trackAccess(keyStr)
|
|
100
|
+
|
|
101
|
+
// Try memory cache first
|
|
102
|
+
const memoryResult = await this.memoryCache.get(key)
|
|
103
|
+
if (memoryResult.hit) {
|
|
104
|
+
return memoryResult
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Try persistent cache if read-through enabled
|
|
108
|
+
if (this.config.readThrough && this.persistentCache) {
|
|
109
|
+
const persistentResult = await this.persistentCache.get(key)
|
|
110
|
+
|
|
111
|
+
if (persistentResult.hit && persistentResult.entry) {
|
|
112
|
+
// Promote to memory cache if configured
|
|
113
|
+
if (this.config.promoteOnAccess) {
|
|
114
|
+
await this.memoryCache.set(
|
|
115
|
+
key,
|
|
116
|
+
persistentResult.entry.value,
|
|
117
|
+
persistentResult.entry.metadata.ttlMs
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return persistentResult
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
hit: false,
|
|
127
|
+
missReason: 'not_found',
|
|
128
|
+
lookupTimeMs: memoryResult.lookupTimeMs,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Set an entry in the cache
|
|
134
|
+
*/
|
|
135
|
+
async set(key: CacheKey | string, value: T, ttlMs?: number): Promise<boolean> {
|
|
136
|
+
// Always set in memory cache
|
|
137
|
+
const memorySuccess = await this.memoryCache.set(key, value, ttlMs)
|
|
138
|
+
|
|
139
|
+
// Write-through to persistent cache if enabled
|
|
140
|
+
if (this.config.writeThrough && this.persistentCache) {
|
|
141
|
+
await this.persistentCache.set(key, value, ttlMs)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return memorySuccess
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Delete an entry from the cache
|
|
149
|
+
*/
|
|
150
|
+
async delete(key: CacheKey | string): Promise<boolean> {
|
|
151
|
+
const memoryDeleted = await this.memoryCache.delete(key)
|
|
152
|
+
|
|
153
|
+
// Also delete from persistent cache
|
|
154
|
+
if (this.persistentCache) {
|
|
155
|
+
await this.persistentCache.delete(key)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return memoryDeleted
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Check if an entry exists
|
|
163
|
+
*/
|
|
164
|
+
async has(key: CacheKey | string): Promise<boolean> {
|
|
165
|
+
// Check memory first
|
|
166
|
+
if (await this.memoryCache.has(key)) {
|
|
167
|
+
return true
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Check persistent
|
|
171
|
+
if (this.persistentCache) {
|
|
172
|
+
return this.persistentCache.has(key)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return false
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Clear all entries
|
|
180
|
+
*/
|
|
181
|
+
async clear(): Promise<void> {
|
|
182
|
+
await this.memoryCache.clear()
|
|
183
|
+
|
|
184
|
+
if (this.persistentCache) {
|
|
185
|
+
await this.persistentCache.clear()
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get cache statistics (combined from both tiers)
|
|
191
|
+
*/
|
|
192
|
+
getStats(): ProofCacheStats {
|
|
193
|
+
const memoryStats = this.memoryCache.getStats()
|
|
194
|
+
|
|
195
|
+
if (!this.persistentCache) {
|
|
196
|
+
return memoryStats
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const persistentStats = this.persistentCache.getStats()
|
|
200
|
+
|
|
201
|
+
// Combine statistics
|
|
202
|
+
return {
|
|
203
|
+
totalLookups: memoryStats.totalLookups, // Memory handles all lookups
|
|
204
|
+
hits: memoryStats.hits + persistentStats.hits,
|
|
205
|
+
misses: memoryStats.misses - persistentStats.hits, // Adjust for persistent hits
|
|
206
|
+
hitRate:
|
|
207
|
+
memoryStats.totalLookups > 0
|
|
208
|
+
? (memoryStats.hits + persistentStats.hits) / memoryStats.totalLookups
|
|
209
|
+
: 0,
|
|
210
|
+
entryCount: memoryStats.entryCount, // Memory is the authoritative count
|
|
211
|
+
sizeBytes: memoryStats.sizeBytes,
|
|
212
|
+
maxSizeBytes: memoryStats.maxSizeBytes,
|
|
213
|
+
evictions: memoryStats.evictions,
|
|
214
|
+
expirations: memoryStats.expirations + persistentStats.expirations,
|
|
215
|
+
avgLookupTimeMs: memoryStats.avgLookupTimeMs,
|
|
216
|
+
avgEntryAgeMs: memoryStats.avgEntryAgeMs,
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get all keys matching a pattern
|
|
222
|
+
*/
|
|
223
|
+
async keys(pattern?: string): Promise<string[]> {
|
|
224
|
+
const memoryKeys = await this.memoryCache.keys(pattern)
|
|
225
|
+
const persistentKeys = this.persistentCache
|
|
226
|
+
? await this.persistentCache.keys(pattern)
|
|
227
|
+
: []
|
|
228
|
+
|
|
229
|
+
// Combine and deduplicate
|
|
230
|
+
const allKeys = new Set([...memoryKeys, ...persistentKeys])
|
|
231
|
+
return Array.from(allKeys)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
addEventListener(listener: CacheEventListener): void {
|
|
235
|
+
this.listeners.add(listener)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
removeEventListener(listener: CacheEventListener): void {
|
|
239
|
+
this.listeners.delete(listener)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get the memory cache tier
|
|
244
|
+
*/
|
|
245
|
+
getMemoryCache(): ILRUCache<T> {
|
|
246
|
+
return this.memoryCache
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get the persistent cache tier (if available)
|
|
251
|
+
*/
|
|
252
|
+
getPersistentCache(): IPersistentCache<T> | null {
|
|
253
|
+
return this.persistentCache
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Warm the cache with specific keys
|
|
258
|
+
*/
|
|
259
|
+
async warm(keys: CacheKeyComponents[]): Promise<WarmingResult> {
|
|
260
|
+
const startTime = Date.now()
|
|
261
|
+
let warmed = 0
|
|
262
|
+
let failed = 0
|
|
263
|
+
const warmedKeys: string[] = []
|
|
264
|
+
|
|
265
|
+
for (const keyComponents of keys) {
|
|
266
|
+
try {
|
|
267
|
+
if (this.warmingGenerator) {
|
|
268
|
+
const value = await this.warmingGenerator(keyComponents)
|
|
269
|
+
const key = this.componentsToKey(keyComponents)
|
|
270
|
+
|
|
271
|
+
await this.set(key, value)
|
|
272
|
+
warmed++
|
|
273
|
+
warmedKeys.push(key)
|
|
274
|
+
this.emitEvent({ type: 'warm', key, timestamp: Date.now() })
|
|
275
|
+
}
|
|
276
|
+
} catch {
|
|
277
|
+
failed++
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
warmed,
|
|
283
|
+
failed,
|
|
284
|
+
timeMs: Date.now() - startTime,
|
|
285
|
+
keys: warmedKeys,
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Start automatic cache warming
|
|
291
|
+
*/
|
|
292
|
+
startWarming(
|
|
293
|
+
config?: CacheWarmingConfig,
|
|
294
|
+
generator?: (key: CacheKeyComponents) => Promise<T>
|
|
295
|
+
): void {
|
|
296
|
+
this.stopWarming()
|
|
297
|
+
|
|
298
|
+
this.warmingConfig = { ...DEFAULT_WARMING_CONFIG, ...config }
|
|
299
|
+
this.warmingGenerator = generator ?? null
|
|
300
|
+
|
|
301
|
+
if (!this.warmingConfig.enabled || !this.warmingGenerator) {
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Warm on startup
|
|
306
|
+
if (this.warmingConfig.warmOnStartup.length > 0) {
|
|
307
|
+
this.warm(this.warmingConfig.warmOnStartup).catch(() => {})
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Start periodic warming
|
|
311
|
+
this.warmingInterval = setInterval(() => {
|
|
312
|
+
this.performPredictiveWarming().catch(() => {})
|
|
313
|
+
}, this.warmingConfig.warmIntervalMs)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Stop automatic cache warming
|
|
318
|
+
*/
|
|
319
|
+
stopWarming(): void {
|
|
320
|
+
if (this.warmingInterval) {
|
|
321
|
+
clearInterval(this.warmingInterval)
|
|
322
|
+
this.warmingInterval = null
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Apply invalidation rules
|
|
328
|
+
*/
|
|
329
|
+
async invalidate(rules: InvalidationRule[]): Promise<number> {
|
|
330
|
+
// Sort rules by priority
|
|
331
|
+
const sortedRules = [...rules].sort((a, b) => b.priority - a.priority)
|
|
332
|
+
let invalidated = 0
|
|
333
|
+
|
|
334
|
+
for (const rule of sortedRules) {
|
|
335
|
+
switch (rule.strategy) {
|
|
336
|
+
case 'ttl':
|
|
337
|
+
invalidated += await this.invalidateByTTL(rule)
|
|
338
|
+
break
|
|
339
|
+
case 'lru':
|
|
340
|
+
invalidated += await this.invalidateByLRU(rule)
|
|
341
|
+
break
|
|
342
|
+
case 'size':
|
|
343
|
+
invalidated += await this.invalidateBySize(rule)
|
|
344
|
+
break
|
|
345
|
+
case 'manual':
|
|
346
|
+
if (rule.pattern) {
|
|
347
|
+
invalidated += await this.invalidateByPattern(rule.pattern)
|
|
348
|
+
}
|
|
349
|
+
break
|
|
350
|
+
default:
|
|
351
|
+
// FIFO, LFU not implemented yet
|
|
352
|
+
break
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return invalidated
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Dispose of the cache
|
|
361
|
+
*/
|
|
362
|
+
async dispose(): Promise<void> {
|
|
363
|
+
this.stopWarming()
|
|
364
|
+
|
|
365
|
+
if (this.memoryCache instanceof LRUCache) {
|
|
366
|
+
this.memoryCache.dispose()
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (this.persistentCache) {
|
|
370
|
+
await this.persistentCache.close()
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
this.listeners.clear()
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ─── Private Methods ─────────────────────────────────────────────────────────
|
|
377
|
+
|
|
378
|
+
private trackAccess(key: string): void {
|
|
379
|
+
this.accessHistory.push({ key, timestamp: Date.now() })
|
|
380
|
+
|
|
381
|
+
// Trim history
|
|
382
|
+
if (this.accessHistory.length > this.maxHistorySize) {
|
|
383
|
+
this.accessHistory = this.accessHistory.slice(-this.maxHistorySize)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private async performPredictiveWarming(): Promise<void> {
|
|
388
|
+
if (!this.warmingGenerator) return
|
|
389
|
+
|
|
390
|
+
const keysToWarm: CacheKeyComponents[] = []
|
|
391
|
+
const maxEntries = this.warmingConfig.maxEntriesPerWarm
|
|
392
|
+
|
|
393
|
+
switch (this.warmingConfig.predictionModel) {
|
|
394
|
+
case 'recent':
|
|
395
|
+
// Warm recently accessed keys that might have been evicted
|
|
396
|
+
keysToWarm.push(...this.getRecentKeys(maxEntries))
|
|
397
|
+
break
|
|
398
|
+
case 'frequent':
|
|
399
|
+
// Warm frequently accessed keys
|
|
400
|
+
keysToWarm.push(...this.getFrequentKeys(maxEntries))
|
|
401
|
+
break
|
|
402
|
+
case 'pattern':
|
|
403
|
+
// Warm based on access patterns (time-of-day, etc.)
|
|
404
|
+
keysToWarm.push(...this.getPatternBasedKeys(maxEntries))
|
|
405
|
+
break
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (keysToWarm.length > 0) {
|
|
409
|
+
await this.warm(keysToWarm)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private getRecentKeys(limit: number): CacheKeyComponents[] {
|
|
414
|
+
// Get recent unique keys that are not in memory cache
|
|
415
|
+
const recentKeys = new Map<string, CacheKeyComponents>()
|
|
416
|
+
|
|
417
|
+
for (let i = this.accessHistory.length - 1; i >= 0 && recentKeys.size < limit * 2; i--) {
|
|
418
|
+
const access = this.accessHistory[i]
|
|
419
|
+
if (!recentKeys.has(access.key)) {
|
|
420
|
+
recentKeys.set(access.key, this.keyToComponents(access.key))
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return Array.from(recentKeys.values()).slice(0, limit)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
private getFrequentKeys(limit: number): CacheKeyComponents[] {
|
|
428
|
+
// Count frequency of each key
|
|
429
|
+
const frequency = new Map<string, number>()
|
|
430
|
+
|
|
431
|
+
for (const access of this.accessHistory) {
|
|
432
|
+
frequency.set(access.key, (frequency.get(access.key) ?? 0) + 1)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Sort by frequency and return top keys
|
|
436
|
+
const sorted = Array.from(frequency.entries())
|
|
437
|
+
.sort((a, b) => b[1] - a[1])
|
|
438
|
+
.slice(0, limit)
|
|
439
|
+
|
|
440
|
+
return sorted.map(([key]) => this.keyToComponents(key))
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
private getPatternBasedKeys(_limit: number): CacheKeyComponents[] {
|
|
444
|
+
// TODO: Implement time-based patterns (e.g., keys accessed at similar times)
|
|
445
|
+
return []
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
private keyToComponents(key: string): CacheKeyComponents {
|
|
449
|
+
// Parse key back to components (simplified)
|
|
450
|
+
const parts = key.split(':')
|
|
451
|
+
return {
|
|
452
|
+
system: (parts[2] ?? 'noir') as CacheKeyComponents['system'],
|
|
453
|
+
circuitId: parts[3] ?? 'unknown',
|
|
454
|
+
privateInputsHash: parts[4] ?? '',
|
|
455
|
+
publicInputsHash: parts[5] ?? '',
|
|
456
|
+
version: parts[6],
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
private componentsToKey(components: CacheKeyComponents): string {
|
|
461
|
+
const parts = [
|
|
462
|
+
'sip-proof',
|
|
463
|
+
'v1',
|
|
464
|
+
components.system,
|
|
465
|
+
components.circuitId,
|
|
466
|
+
components.privateInputsHash,
|
|
467
|
+
components.publicInputsHash,
|
|
468
|
+
]
|
|
469
|
+
|
|
470
|
+
if (components.version) {
|
|
471
|
+
parts.push(components.version)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return parts.join(':')
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private async invalidateByTTL(rule: InvalidationRule): Promise<number> {
|
|
478
|
+
const now = Date.now()
|
|
479
|
+
const keys = await this.keys(rule.pattern)
|
|
480
|
+
let invalidated = 0
|
|
481
|
+
|
|
482
|
+
for (const key of keys) {
|
|
483
|
+
const result = await this.memoryCache.get(key)
|
|
484
|
+
if (
|
|
485
|
+
result.hit &&
|
|
486
|
+
result.entry &&
|
|
487
|
+
rule.ttlMs &&
|
|
488
|
+
now - result.entry.metadata.createdAt > rule.ttlMs
|
|
489
|
+
) {
|
|
490
|
+
await this.delete(key)
|
|
491
|
+
invalidated++
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return invalidated
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
private async invalidateByLRU(rule: InvalidationRule): Promise<number> {
|
|
499
|
+
if (!(this.memoryCache instanceof LRUCache)) {
|
|
500
|
+
return 0
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const entries = this.memoryCache.getEntriesLRU()
|
|
504
|
+
const matching = rule.pattern
|
|
505
|
+
? entries.filter((e) => this.matchesPattern(e.key.key, rule.pattern!))
|
|
506
|
+
: entries
|
|
507
|
+
|
|
508
|
+
// Evict the least recently used half of matching entries
|
|
509
|
+
const toEvict = Math.floor(matching.length / 2)
|
|
510
|
+
let invalidated = 0
|
|
511
|
+
|
|
512
|
+
for (let i = matching.length - 1; i >= matching.length - toEvict && i >= 0; i--) {
|
|
513
|
+
await this.delete(matching[i].key.key)
|
|
514
|
+
invalidated++
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return invalidated
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
private async invalidateBySize(_rule: InvalidationRule): Promise<number> {
|
|
521
|
+
// Evict until under target size
|
|
522
|
+
const targetSize = Math.floor(this.config.memory.maxSizeBytes * 0.7)
|
|
523
|
+
let invalidated = 0
|
|
524
|
+
|
|
525
|
+
while (this.memoryCache.getSizeBytes() > targetSize) {
|
|
526
|
+
const evicted = this.memoryCache.evict(1)
|
|
527
|
+
if (evicted === 0) break
|
|
528
|
+
invalidated += evicted
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
return invalidated
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
private async invalidateByPattern(pattern: string): Promise<number> {
|
|
535
|
+
const keys = await this.keys(pattern)
|
|
536
|
+
let invalidated = 0
|
|
537
|
+
|
|
538
|
+
for (const key of keys) {
|
|
539
|
+
await this.delete(key)
|
|
540
|
+
invalidated++
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return invalidated
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
private matchesPattern(key: string, pattern: string): boolean {
|
|
547
|
+
const regexPattern = pattern
|
|
548
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
549
|
+
.replace(/\*/g, '.*')
|
|
550
|
+
.replace(/\?/g, '.')
|
|
551
|
+
|
|
552
|
+
const regex = new RegExp(`^${regexPattern}$`)
|
|
553
|
+
return regex.test(key)
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
private emitEvent(event: CacheEvent): void {
|
|
557
|
+
for (const listener of this.listeners) {
|
|
558
|
+
try {
|
|
559
|
+
listener(event)
|
|
560
|
+
} catch {
|
|
561
|
+
// Ignore listener errors
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Create a multi-tier cache instance
|
|
569
|
+
*/
|
|
570
|
+
export function createMultiTierCache<T = SingleProof>(
|
|
571
|
+
config?: Partial<MultiTierCacheConfig>,
|
|
572
|
+
persistentConfig?: Parameters<typeof createPersistentCache>[0]
|
|
573
|
+
): IMultiTierCache<T> {
|
|
574
|
+
return new MultiTierCache<T>(config, persistentConfig)
|
|
575
|
+
}
|