@zendfi/sdk 0.8.4 → 1.0.1

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.
@@ -1,366 +0,0 @@
1
- // src/helpers/cache.ts
2
- var SessionKeyCache = class {
3
- memoryCache = /* @__PURE__ */ new Map();
4
- config;
5
- refreshTimers = /* @__PURE__ */ new Map();
6
- constructor(config = {}) {
7
- this.config = {
8
- storage: config.storage || "memory",
9
- ttl: config.ttl || 30 * 60 * 1e3,
10
- // 30 minutes default
11
- autoRefresh: config.autoRefresh || false,
12
- namespace: config.namespace || "zendfi_cache",
13
- debug: config.debug || false
14
- };
15
- }
16
- /**
17
- * Get cached keypair or decrypt and cache
18
- */
19
- async getCached(sessionKeyId, decryptFn, options) {
20
- this.log(`getCached: ${sessionKeyId}`);
21
- const memoryCached = this.memoryCache.get(sessionKeyId);
22
- if (memoryCached && Date.now() < memoryCached.expiry) {
23
- this.log(`Memory cache HIT: ${sessionKeyId}`);
24
- return memoryCached.keypair;
25
- }
26
- if (this.config.storage !== "memory") {
27
- const persistentCached = await this.getFromStorage(sessionKeyId);
28
- if (persistentCached && Date.now() < persistentCached.expiry) {
29
- if (options?.deviceFingerprint && persistentCached.deviceFingerprint) {
30
- if (options.deviceFingerprint !== persistentCached.deviceFingerprint) {
31
- this.log(`Device fingerprint mismatch for ${sessionKeyId}`);
32
- await this.invalidate(sessionKeyId);
33
- return await this.decryptAndCache(sessionKeyId, decryptFn, options);
34
- }
35
- }
36
- this.log(`Persistent cache HIT: ${sessionKeyId}`);
37
- this.memoryCache.set(sessionKeyId, persistentCached);
38
- return persistentCached.keypair;
39
- }
40
- }
41
- this.log(`Cache MISS: ${sessionKeyId}`);
42
- return await this.decryptAndCache(sessionKeyId, decryptFn, options);
43
- }
44
- /**
45
- * Decrypt keypair and cache it
46
- */
47
- async decryptAndCache(sessionKeyId, decryptFn, options) {
48
- const keypair = await decryptFn();
49
- const expiry = Date.now() + this.config.ttl;
50
- const cached = {
51
- keypair,
52
- expiry,
53
- sessionKeyId,
54
- deviceFingerprint: options?.deviceFingerprint
55
- };
56
- this.memoryCache.set(sessionKeyId, cached);
57
- if (this.config.storage !== "memory") {
58
- await this.setInStorage(sessionKeyId, cached);
59
- }
60
- if (this.config.autoRefresh) {
61
- this.setupAutoRefresh(sessionKeyId, decryptFn, options);
62
- }
63
- this.log(`Cached: ${sessionKeyId}, expires in ${this.config.ttl}ms`);
64
- return keypair;
65
- }
66
- /**
67
- * Invalidate cached keypair
68
- */
69
- async invalidate(sessionKeyId) {
70
- this.log(`Invalidating: ${sessionKeyId}`);
71
- this.memoryCache.delete(sessionKeyId);
72
- const timer = this.refreshTimers.get(sessionKeyId);
73
- if (timer) {
74
- clearTimeout(timer);
75
- this.refreshTimers.delete(sessionKeyId);
76
- }
77
- if (this.config.storage !== "memory") {
78
- await this.removeFromStorage(sessionKeyId);
79
- }
80
- }
81
- /**
82
- * Clear all cached keypairs
83
- */
84
- async clear() {
85
- this.log("Clearing all cache");
86
- this.memoryCache.clear();
87
- for (const timer of this.refreshTimers.values()) {
88
- clearTimeout(timer);
89
- }
90
- this.refreshTimers.clear();
91
- if (this.config.storage !== "memory") {
92
- await this.clearStorage();
93
- }
94
- }
95
- /**
96
- * Get cache statistics
97
- */
98
- getStats() {
99
- const entries = Array.from(this.memoryCache.entries()).map(([id, cached]) => ({
100
- sessionKeyId: id,
101
- expiresIn: Math.max(0, cached.expiry - Date.now())
102
- }));
103
- return { size: this.memoryCache.size, entries };
104
- }
105
- /**
106
- * Check if a session key is cached and valid
107
- */
108
- isCached(sessionKeyId) {
109
- const cached = this.memoryCache.get(sessionKeyId);
110
- return cached ? Date.now() < cached.expiry : false;
111
- }
112
- /**
113
- * Update TTL for a cached session key
114
- */
115
- async extendTTL(sessionKeyId, additionalMs) {
116
- const cached = this.memoryCache.get(sessionKeyId);
117
- if (!cached) return false;
118
- cached.expiry += additionalMs;
119
- this.memoryCache.set(sessionKeyId, cached);
120
- if (this.config.storage !== "memory") {
121
- await this.setInStorage(sessionKeyId, cached);
122
- }
123
- this.log(`Extended TTL for ${sessionKeyId} by ${additionalMs}ms`);
124
- return true;
125
- }
126
- // ============================================
127
- // Storage Backend Implementations
128
- // ============================================
129
- async getFromStorage(sessionKeyId) {
130
- try {
131
- const key = this.getStorageKey(sessionKeyId);
132
- if (this.config.storage === "localStorage") {
133
- const data = localStorage.getItem(key);
134
- if (!data) return null;
135
- const parsed = JSON.parse(data);
136
- return {
137
- ...parsed,
138
- keypair: this.deserializeKeypair(parsed.keypair)
139
- };
140
- }
141
- if (this.config.storage === "indexedDB") {
142
- return await this.getFromIndexedDB(key);
143
- }
144
- if (typeof this.config.storage === "object") {
145
- const data = await this.config.storage.get(key);
146
- if (!data) return null;
147
- const parsed = JSON.parse(data);
148
- return {
149
- ...parsed,
150
- keypair: this.deserializeKeypair(parsed.keypair)
151
- };
152
- }
153
- } catch (error) {
154
- this.log(`Error reading from storage: ${error}`);
155
- }
156
- return null;
157
- }
158
- async setInStorage(sessionKeyId, cached) {
159
- try {
160
- const key = this.getStorageKey(sessionKeyId);
161
- const serialized = {
162
- ...cached,
163
- keypair: this.serializeKeypair(cached.keypair)
164
- };
165
- if (this.config.storage === "localStorage") {
166
- localStorage.setItem(key, JSON.stringify(serialized));
167
- return;
168
- }
169
- if (this.config.storage === "indexedDB") {
170
- await this.setInIndexedDB(key, serialized);
171
- return;
172
- }
173
- if (typeof this.config.storage === "object") {
174
- await this.config.storage.set(key, JSON.stringify(serialized));
175
- }
176
- } catch (error) {
177
- this.log(`Error writing to storage: ${error}`);
178
- }
179
- }
180
- async removeFromStorage(sessionKeyId) {
181
- try {
182
- const key = this.getStorageKey(sessionKeyId);
183
- if (this.config.storage === "localStorage") {
184
- localStorage.removeItem(key);
185
- return;
186
- }
187
- if (this.config.storage === "indexedDB") {
188
- await this.removeFromIndexedDB(key);
189
- return;
190
- }
191
- if (typeof this.config.storage === "object") {
192
- await this.config.storage.remove(key);
193
- }
194
- } catch (error) {
195
- this.log(`Error removing from storage: ${error}`);
196
- }
197
- }
198
- async clearStorage() {
199
- try {
200
- if (this.config.storage === "localStorage") {
201
- const keysToRemove = [];
202
- for (let i = 0; i < localStorage.length; i++) {
203
- const key = localStorage.key(i);
204
- if (key?.startsWith(this.config.namespace)) {
205
- keysToRemove.push(key);
206
- }
207
- }
208
- keysToRemove.forEach((key) => localStorage.removeItem(key));
209
- return;
210
- }
211
- if (this.config.storage === "indexedDB") {
212
- await this.clearIndexedDB();
213
- return;
214
- }
215
- if (typeof this.config.storage === "object") {
216
- await this.config.storage.clear();
217
- }
218
- } catch (error) {
219
- this.log(`Error clearing storage: ${error}`);
220
- }
221
- }
222
- // ============================================
223
- // IndexedDB Helpers
224
- // ============================================
225
- async getFromIndexedDB(key) {
226
- return new Promise((resolve) => {
227
- const request = indexedDB.open(this.config.namespace, 1);
228
- request.onerror = () => resolve(null);
229
- request.onupgradeneeded = (event) => {
230
- const db = event.target.result;
231
- if (!db.objectStoreNames.contains("cache")) {
232
- db.createObjectStore("cache");
233
- }
234
- };
235
- request.onsuccess = (event) => {
236
- const db = event.target.result;
237
- const transaction = db.transaction(["cache"], "readonly");
238
- const store = transaction.objectStore("cache");
239
- const getRequest = store.get(key);
240
- getRequest.onsuccess = () => {
241
- resolve(getRequest.result || null);
242
- };
243
- getRequest.onerror = () => resolve(null);
244
- };
245
- });
246
- }
247
- async setInIndexedDB(key, value) {
248
- return new Promise((resolve, reject) => {
249
- const request = indexedDB.open(this.config.namespace, 1);
250
- request.onerror = () => reject(new Error("IndexedDB error"));
251
- request.onupgradeneeded = (event) => {
252
- const db = event.target.result;
253
- if (!db.objectStoreNames.contains("cache")) {
254
- db.createObjectStore("cache");
255
- }
256
- };
257
- request.onsuccess = (event) => {
258
- const db = event.target.result;
259
- const transaction = db.transaction(["cache"], "readwrite");
260
- const store = transaction.objectStore("cache");
261
- store.put(value, key);
262
- transaction.oncomplete = () => resolve();
263
- transaction.onerror = () => reject(new Error("IndexedDB transaction error"));
264
- };
265
- });
266
- }
267
- async removeFromIndexedDB(key) {
268
- return new Promise((resolve) => {
269
- const request = indexedDB.open(this.config.namespace, 1);
270
- request.onsuccess = (event) => {
271
- const db = event.target.result;
272
- const transaction = db.transaction(["cache"], "readwrite");
273
- const store = transaction.objectStore("cache");
274
- store.delete(key);
275
- transaction.oncomplete = () => resolve();
276
- };
277
- request.onerror = () => resolve();
278
- });
279
- }
280
- async clearIndexedDB() {
281
- return new Promise((resolve) => {
282
- const request = indexedDB.open(this.config.namespace, 1);
283
- request.onsuccess = (event) => {
284
- const db = event.target.result;
285
- const transaction = db.transaction(["cache"], "readwrite");
286
- const store = transaction.objectStore("cache");
287
- store.clear();
288
- transaction.oncomplete = () => resolve();
289
- };
290
- request.onerror = () => resolve();
291
- });
292
- }
293
- // ============================================
294
- // Serialization
295
- // ============================================
296
- serializeKeypair(keypair) {
297
- if (keypair && typeof keypair === "object" && "secretKey" in keypair) {
298
- return {
299
- type: "solana",
300
- secretKey: Array.from(keypair.secretKey)
301
- };
302
- }
303
- if (keypair instanceof Uint8Array) {
304
- return {
305
- type: "uint8array",
306
- data: Array.from(keypair)
307
- };
308
- }
309
- return keypair;
310
- }
311
- deserializeKeypair(data) {
312
- if (!data || typeof data !== "object") return data;
313
- if (data.type === "solana" && data.secretKey) {
314
- return new Uint8Array(data.secretKey);
315
- }
316
- if (data.type === "uint8array" && data.data) {
317
- return new Uint8Array(data.data);
318
- }
319
- return data;
320
- }
321
- // ============================================
322
- // Auto-Refresh
323
- // ============================================
324
- setupAutoRefresh(sessionKeyId, decryptFn, options) {
325
- const existingTimer = this.refreshTimers.get(sessionKeyId);
326
- if (existingTimer) {
327
- clearTimeout(existingTimer);
328
- }
329
- const refreshIn = Math.max(0, this.config.ttl - 5 * 60 * 1e3);
330
- const timer = setTimeout(async () => {
331
- this.log(`Auto-refreshing: ${sessionKeyId}`);
332
- try {
333
- await this.decryptAndCache(sessionKeyId, decryptFn, options);
334
- } catch (error) {
335
- this.log(`Auto-refresh failed: ${error}`);
336
- }
337
- }, refreshIn);
338
- this.refreshTimers.set(sessionKeyId, timer);
339
- }
340
- // ============================================
341
- // Utilities
342
- // ============================================
343
- getStorageKey(sessionKeyId) {
344
- return `${this.config.namespace}:${sessionKeyId}`;
345
- }
346
- log(message) {
347
- if (this.config.debug) {
348
- console.log(`[SessionKeyCache] ${message}`);
349
- }
350
- }
351
- };
352
- var QuickCaches = {
353
- /** Memory-only cache (30 minutes) */
354
- memory: () => new SessionKeyCache({ storage: "memory", ttl: 30 * 60 * 1e3 }),
355
- /** Persistent cache (1 hour, survives reload) */
356
- persistent: () => new SessionKeyCache({ storage: "localStorage", ttl: 60 * 60 * 1e3 }),
357
- /** Long-term cache (24 hours, IndexedDB) */
358
- longTerm: () => new SessionKeyCache({ storage: "indexedDB", ttl: 24 * 60 * 60 * 1e3, autoRefresh: true }),
359
- /** Secure cache (5 minutes, memory-only) */
360
- secure: () => new SessionKeyCache({ storage: "memory", ttl: 5 * 60 * 1e3 })
361
- };
362
-
363
- export {
364
- SessionKeyCache,
365
- QuickCaches
366
- };