flamecache 0.0.2 → 1.0.0
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 +23 -0
- package/dist/index.js +27 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,6 +45,7 @@ const cache = createCache({
|
|
|
45
45
|
databaseURL: 'https://your-project.firebaseio.com',
|
|
46
46
|
projectId: 'your-project-id',
|
|
47
47
|
},
|
|
48
|
+
rootPath: 'my-cache', // Root path in Firebase (default: 'flamecache')
|
|
48
49
|
ttl: 3600, // Default TTL: 1 hour
|
|
49
50
|
});
|
|
50
51
|
|
|
@@ -400,6 +401,28 @@ async function getAnalytics(pageIds: string[]) {
|
|
|
400
401
|
}
|
|
401
402
|
```
|
|
402
403
|
|
|
404
|
+
## 📊 Performance
|
|
405
|
+
|
|
406
|
+
Here are the benchmark results running against a real Firebase Realtime Database instance (50 iterations per operation):
|
|
407
|
+
|
|
408
|
+
| Operation | Avg Latency | Throughput |
|
|
409
|
+
| :--------------------- | :--------------- | :---------------- |
|
|
410
|
+
| **GET** (Cache Hit) | ~110ms | 9 ops/sec |
|
|
411
|
+
| **SET** (Write) | ~120ms | 8 ops/sec |
|
|
412
|
+
| **INCR** (Atomic) | ~230ms | 4 ops/sec |
|
|
413
|
+
| **MSET** (Batch Write) | **~2.4ms / key** | **415+ keys/sec** |
|
|
414
|
+
| **MGET** (Batch Read) | **~3.6ms / key** | **275+ keys/sec** |
|
|
415
|
+
|
|
416
|
+
> All benchmarks include real-world network latency to Firebase. Batch operations leverage parallelization and atomic multi-path updates for maximum efficiency.
|
|
417
|
+
|
|
418
|
+
You can run these benchmarks yourself:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
npm run example benchmark
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
See the [benchmark script](https://github.com/iamanishroy/flamecache/blob/main/examples/benchmark.ts) for details.
|
|
425
|
+
|
|
403
426
|
## 🔧 Configuration
|
|
404
427
|
|
|
405
428
|
```typescript
|
package/dist/index.js
CHANGED
|
@@ -81,12 +81,35 @@ var FirebaseCache = class {
|
|
|
81
81
|
return Promise.all(keys.map((k) => this.get(k)));
|
|
82
82
|
}
|
|
83
83
|
async mset(entries, ttl) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
try {
|
|
85
|
+
const seconds = ttl !== void 0 ? ttl : this.ttl;
|
|
86
|
+
const exp = seconds > 0 ? Date.now() + seconds * 1e3 : null;
|
|
87
|
+
const updates = {};
|
|
88
|
+
for (const [key, data] of Object.entries(entries)) {
|
|
89
|
+
updates[key] = {
|
|
90
|
+
data,
|
|
91
|
+
exp
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
await database.update(database.ref(this.db, this.root), updates);
|
|
95
|
+
this.log("mset:", Object.keys(entries).length, "keys");
|
|
96
|
+
} catch (err) {
|
|
97
|
+
this.log("error mset:", err);
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
87
100
|
}
|
|
88
101
|
async mdel(keys) {
|
|
89
|
-
|
|
102
|
+
try {
|
|
103
|
+
const updates = {};
|
|
104
|
+
for (const key of keys) {
|
|
105
|
+
updates[key] = null;
|
|
106
|
+
}
|
|
107
|
+
await database.update(database.ref(this.db, this.root), updates);
|
|
108
|
+
this.log("mdel:", keys.length, "keys");
|
|
109
|
+
} catch (err) {
|
|
110
|
+
this.log("error mdel:", err);
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
90
113
|
}
|
|
91
114
|
async clear() {
|
|
92
115
|
try {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cache.ts"],"names":["app","getApps","initializeApp","getDatabase","get","ref","set","remove","goOffline","update","increment"],"mappings":"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","file":"index.js","sourcesContent":["import { initializeApp, getApps } from 'firebase/app';\nimport { \n getDatabase, \n ref, \n get, \n set, \n remove, \n goOffline,\n update,\n increment,\n Database \n} from 'firebase/database';\nimport { CacheConfig, CacheEntry } from './types';\n\nexport class FirebaseCache {\n private db: Database;\n private root: string;\n private ttl: number;\n private debug: boolean;\n\n constructor(config: CacheConfig) {\n let app;\n const existingApp = getApps().find(a => a.name === (config.rootPath || '[DEFAULT]'));\n if (existingApp) {\n app = existingApp;\n } else {\n app = initializeApp(config.firebase, config.rootPath || '[DEFAULT]');\n }\n \n this.db = getDatabase(app);\n this.root = config.rootPath || 'flamecache';\n this.ttl = config.ttl || 3600;\n this.debug = config.debug || false;\n }\n\n private path(key: string): string {\n return `${this.root}/${key}`;\n }\n\n private log(...args: any[]): void {\n if (this.debug) console.log('[Flamecache]', ...args);\n }\n\n async get<T = any>(key: string): Promise<T | null> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) {\n this.log('miss:', key);\n return null;\n }\n\n const entry: CacheEntry<T> = snapshot.val();\n \n if (entry.exp && Date.now() > entry.exp) {\n this.log('expired:', key);\n await this.del(key);\n return null;\n }\n\n this.log('hit:', key);\n return entry.data;\n } catch (err) {\n this.log('error get:', key, err);\n return null;\n }\n }\n\n async set<T = any>(key: string, data: T, ttl?: number): Promise<void> {\n try {\n const seconds = ttl !== undefined ? ttl : this.ttl;\n const entry: CacheEntry<T> = {\n data,\n exp: seconds > 0 ? Date.now() + (seconds * 1000) : null\n };\n \n await set(ref(this.db, this.path(key)), entry);\n this.log('set:', key, `(${seconds}s)`);\n } catch (err) {\n this.log('error set:', key, err);\n throw err;\n }\n }\n\n async del(key: string): Promise<void> {\n try {\n await remove(ref(this.db, this.path(key)));\n this.log('del:', key);\n } catch (err) {\n this.log('error del:', key, err);\n }\n }\n\n async has(key: string): Promise<boolean> {\n return (await this.get(key)) !== null;\n }\n\n async wrap<T = any>(\n key: string,\n fetchFn: () => Promise<T>,\n ttl?: number\n ): Promise<T> {\n const cached = await this.get<T>(key);\n if (cached !== null) return cached;\n\n this.log('fetch:', key);\n const data = await fetchFn();\n await this.set(key, data, ttl);\n return data;\n }\n\n async mget<T = any>(keys: string[]): Promise<(T | null)[]> {\n return Promise.all(keys.map(k => this.get<T>(k)));\n }\n\n async mset(entries: Record<string, any>, ttl?: number): Promise<void> {\n await Promise.all(\n Object.entries(entries).map(([k, v]) => this.set(k, v, ttl))\n );\n }\n\n async mdel(keys: string[]): Promise<void> {\n await Promise.all(keys.map(k => this.del(k)));\n }\n\n async clear(): Promise<void> {\n try {\n await remove(ref(this.db, this.root));\n this.log('cleared all');\n } catch (err) {\n this.log('error clear:', err);\n throw err;\n }\n }\n\n async disconnect(): Promise<void> {\n await goOffline(this.db);\n this.log('disconnected');\n }\n\n async touch(key: string, ttl?: number): Promise<boolean> {\n const data = await this.get(key);\n if (data === null) return false;\n await this.set(key, data, ttl);\n return true;\n }\n\n async pull<T = any>(key: string): Promise<T | null> {\n const data = await this.get<T>(key);\n if (data !== null) await this.del(key);\n return data;\n }\n\n async incr(key: string, by: number = 1): Promise<number> {\n const op = by >= 0 ? 'incr' : 'decr';\n try {\n const path = this.path(key);\n const dbRef = ref(this.db, path);\n \n await update(dbRef, {\n 'data': increment(by),\n 'exp': this.ttl > 0 ? Date.now() + (this.ttl * 1000) : null\n });\n\n const newValue = await this.get<number>(key);\n const sign = by >= 0 ? '+' : '';\n this.log(`${op}:`, key, `${sign}${by} (atomic)`);\n return newValue ?? 0;\n } catch (err) {\n this.log(`error ${op}:`, key, err);\n throw err;\n }\n }\n\n async decr(key: string, by: number = 1): Promise<number> {\n return this.incr(key, -by);\n }\n\n async expire(key: string, ttl: number): Promise<boolean> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) {\n this.log('expire failed - key not found:', key);\n return false;\n }\n\n const entry: CacheEntry<any> = snapshot.val();\n entry.exp = ttl > 0 ? Date.now() + (ttl * 1000) : null;\n \n await set(ref(this.db, this.path(key)), entry);\n this.log('expire:', key, `(${ttl}s)`);\n return true;\n } catch (err) {\n this.log('error expire:', key, err);\n return false;\n }\n }\n\n async getTtl(key: string): Promise<number> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) return 0;\n\n const entry: CacheEntry<any> = snapshot.val();\n \n if (!entry.exp) return -1;\n \n const remaining = Math.max(0, Math.floor((entry.exp - Date.now()) / 1000));\n return remaining;\n } catch (err) {\n this.log('error ttl:', key, err);\n return 0;\n }\n }\n}\n\nexport function createCache(config: CacheConfig): FirebaseCache {\n return new FirebaseCache(config);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/cache.ts"],"names":["app","getApps","initializeApp","getDatabase","get","ref","set","remove","update","goOffline","increment"],"mappings":";;;;;;AAcO,IAAM,gBAAN,MAAoB;AAAA,EAMzB,YAAY,MAAA,EAAqB;AAC/B,IAAA,IAAIA,KAAA;AACJ,IAAA,MAAM,WAAA,GAAcC,aAAQ,CAAE,IAAA,CAAK,OAAK,CAAA,CAAE,IAAA,MAAU,MAAA,CAAO,QAAA,IAAY,WAAA,CAAY,CAAA;AACnF,IAAA,IAAI,WAAA,EAAa;AACf,MAAAD,KAAA,GAAM,WAAA;AAAA,IACR,CAAA,MAAO;AACL,MAAAA,KAAA,GAAME,iBAAA,CAAc,MAAA,CAAO,QAAA,EAAU,MAAA,CAAO,YAAY,WAAW,CAAA;AAAA,IACrE;AAEA,IAAA,IAAA,CAAK,EAAA,GAAKC,qBAAYH,KAAG,CAAA;AACzB,IAAA,IAAA,CAAK,IAAA,GAAO,OAAO,QAAA,IAAY,YAAA;AAC/B,IAAA,IAAA,CAAK,GAAA,GAAM,OAAO,GAAA,IAAO,IAAA;AACzB,IAAA,IAAA,CAAK,KAAA,GAAQ,OAAO,KAAA,IAAS,KAAA;AAAA,EAC/B;AAAA,EAEQ,KAAK,GAAA,EAAqB;AAChC,IAAA,OAAO,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA;AAAA,EAC5B;AAAA,EAEQ,OAAO,IAAA,EAAmB;AAChC,IAAA,IAAI,KAAK,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,cAAA,EAAgB,GAAG,IAAI,CAAA;AAAA,EACrD;AAAA,EAEA,MAAM,IAAa,GAAA,EAAgC;AACjD,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAMI,YAAA,CAAIC,YAAA,CAAI,IAAA,CAAK,IAAI,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAC,CAAA;AACvD,MAAA,IAAI,CAAC,QAAA,CAAS,MAAA,EAAO,EAAG;AACtB,QAAA,IAAA,CAAK,GAAA,CAAI,SAAS,GAAG,CAAA;AACrB,QAAA,OAAO,IAAA;AAAA,MACT;AAEA,MAAA,MAAM,KAAA,GAAuB,SAAS,GAAA,EAAI;AAE1C,MAAA,IAAI,MAAM,GAAA,IAAO,IAAA,CAAK,GAAA,EAAI,GAAI,MAAM,GAAA,EAAK;AACvC,QAAA,IAAA,CAAK,GAAA,CAAI,YAAY,GAAG,CAAA;AACxB,QAAA,MAAM,IAAA,CAAK,IAAI,GAAG,CAAA;AAClB,QAAA,OAAO,IAAA;AAAA,MACT;AAEA,MAAA,IAAA,CAAK,GAAA,CAAI,QAAQ,GAAG,CAAA;AACpB,MAAA,OAAO,KAAA,CAAM,IAAA;AAAA,IACf,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,YAAA,EAAc,GAAA,EAAK,GAAG,CAAA;AAC/B,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,GAAA,CAAa,GAAA,EAAa,IAAA,EAAS,GAAA,EAA6B;AACpE,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAU,GAAA,KAAQ,KAAA,CAAA,GAAY,GAAA,GAAM,IAAA,CAAK,GAAA;AAC/C,MAAA,MAAM,KAAA,GAAuB;AAAA,QAC3B,IAAA;AAAA,QACA,KAAK,OAAA,GAAU,CAAA,GAAI,KAAK,GAAA,EAAI,GAAK,UAAU,GAAA,GAAQ;AAAA,OACrD;AAEA,MAAA,MAAMC,YAAA,CAAID,aAAI,IAAA,CAAK,EAAA,EAAI,KAAK,IAAA,CAAK,GAAG,CAAC,CAAA,EAAG,KAAK,CAAA;AAC7C,MAAA,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,GAAA,EAAK,CAAA,CAAA,EAAI,OAAO,CAAA,EAAA,CAAI,CAAA;AAAA,IACvC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,YAAA,EAAc,GAAA,EAAK,GAAG,CAAA;AAC/B,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,GAAA,EAA4B;AACpC,IAAA,IAAI;AACF,MAAA,MAAME,eAAA,CAAOF,aAAI,IAAA,CAAK,EAAA,EAAI,KAAK,IAAA,CAAK,GAAG,CAAC,CAAC,CAAA;AACzC,MAAA,IAAA,CAAK,GAAA,CAAI,QAAQ,GAAG,CAAA;AAAA,IACtB,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,YAAA,EAAc,GAAA,EAAK,GAAG,CAAA;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,GAAA,EAA+B;AACvC,IAAA,OAAQ,MAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,KAAO,IAAA;AAAA,EACnC;AAAA,EAEA,MAAM,IAAA,CACJ,GAAA,EACA,OAAA,EACA,GAAA,EACY;AACZ,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,GAAA,CAAO,GAAG,CAAA;AACpC,IAAA,IAAI,MAAA,KAAW,MAAM,OAAO,MAAA;AAE5B,IAAA,IAAA,CAAK,GAAA,CAAI,UAAU,GAAG,CAAA;AACtB,IAAA,MAAM,IAAA,GAAO,MAAM,OAAA,EAAQ;AAC3B,IAAA,MAAM,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,EAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,MAAM,KAAc,IAAA,EAAuC;AACzD,IAAA,OAAO,OAAA,CAAQ,IAAI,IAAA,CAAK,GAAA,CAAI,OAAK,IAAA,CAAK,GAAA,CAAO,CAAC,CAAC,CAAC,CAAA;AAAA,EAClD;AAAA,EAEA,MAAM,IAAA,CAAK,OAAA,EAA8B,GAAA,EAA6B;AACpE,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAU,GAAA,KAAQ,KAAA,CAAA,GAAY,GAAA,GAAM,IAAA,CAAK,GAAA;AAC/C,MAAA,MAAM,MAAM,OAAA,GAAU,CAAA,GAAI,KAAK,GAAA,EAAI,GAAK,UAAU,GAAA,GAAQ,IAAA;AAC1D,MAAA,MAAM,UAA2C,EAAC;AAElD,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AACjD,QAAA,OAAA,CAAQ,GAAG,CAAA,GAAI;AAAA,UACb,IAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAEA,MAAA,MAAMG,gBAAOH,YAAA,CAAI,IAAA,CAAK,IAAI,IAAA,CAAK,IAAI,GAAG,OAAO,CAAA;AAC7C,MAAA,IAAA,CAAK,IAAI,OAAA,EAAS,MAAA,CAAO,KAAK,OAAO,CAAA,CAAE,QAAQ,MAAM,CAAA;AAAA,IACvD,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,eAAe,GAAG,CAAA;AAC3B,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,IAAA,EAA+B;AACxC,IAAA,IAAI;AACF,MAAA,MAAM,UAAgC,EAAC;AACvC,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,OAAA,CAAQ,GAAG,CAAA,GAAI,IAAA;AAAA,MACjB;AAEA,MAAA,MAAMG,gBAAOH,YAAA,CAAI,IAAA,CAAK,IAAI,IAAA,CAAK,IAAI,GAAG,OAAO,CAAA;AAC7C,MAAA,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,IAAA,CAAK,MAAA,EAAQ,MAAM,CAAA;AAAA,IACvC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,eAAe,GAAG,CAAA;AAC3B,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,IAAI;AACF,MAAA,MAAME,gBAAOF,YAAA,CAAI,IAAA,CAAK,EAAA,EAAI,IAAA,CAAK,IAAI,CAAC,CAAA;AACpC,MAAA,IAAA,CAAK,IAAI,aAAa,CAAA;AAAA,IACxB,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,gBAAgB,GAAG,CAAA;AAC5B,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,UAAA,GAA4B;AAChC,IAAA,MAAMI,kBAAA,CAAU,KAAK,EAAE,CAAA;AACvB,IAAA,IAAA,CAAK,IAAI,cAAc,CAAA;AAAA,EACzB;AAAA,EAEA,MAAM,KAAA,CAAM,GAAA,EAAa,GAAA,EAAgC;AACvD,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAC/B,IAAA,IAAI,IAAA,KAAS,MAAM,OAAO,KAAA;AAC1B,IAAA,MAAM,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,EAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,MAAM,KAAc,GAAA,EAAgC;AAClD,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,GAAA,CAAO,GAAG,CAAA;AAClC,IAAA,IAAI,IAAA,KAAS,IAAA,EAAM,MAAM,IAAA,CAAK,IAAI,GAAG,CAAA;AACrC,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,MAAM,IAAA,CAAK,GAAA,EAAa,EAAA,GAAa,CAAA,EAAoB;AACvD,IAAA,MAAM,EAAA,GAAK,EAAA,IAAM,CAAA,GAAI,MAAA,GAAS,MAAA;AAC9B,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA;AAC1B,MAAA,MAAM,KAAA,GAAQJ,YAAA,CAAI,IAAA,CAAK,EAAA,EAAI,IAAI,CAAA;AAE/B,MAAA,MAAMG,gBAAO,KAAA,EAAO;AAAA,QAClB,MAAA,EAAQE,mBAAU,EAAE,CAAA;AAAA,QACpB,KAAA,EAAO,KAAK,GAAA,GAAM,CAAA,GAAI,KAAK,GAAA,EAAI,GAAK,IAAA,CAAK,GAAA,GAAM,GAAA,GAAQ;AAAA,OACxD,CAAA;AAED,MAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,GAAA,CAAY,GAAG,CAAA;AAC3C,MAAA,MAAM,IAAA,GAAO,EAAA,IAAM,CAAA,GAAI,GAAA,GAAM,EAAA;AAC7B,MAAA,IAAA,CAAK,GAAA,CAAI,GAAG,EAAE,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA,EAAG,IAAI,CAAA,EAAG,EAAE,CAAA,SAAA,CAAW,CAAA;AAC/C,MAAA,OAAO,QAAA,IAAY,CAAA;AAAA,IACrB,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,CAAA,MAAA,EAAS,EAAE,CAAA,CAAA,CAAA,EAAK,KAAK,GAAG,CAAA;AACjC,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,IAAA,CAAK,GAAA,EAAa,EAAA,GAAa,CAAA,EAAoB;AACvD,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,GAAA,EAAK,CAAC,EAAE,CAAA;AAAA,EAC3B;AAAA,EAEA,MAAM,MAAA,CAAO,GAAA,EAAa,GAAA,EAA+B;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAMN,YAAA,CAAIC,YAAA,CAAI,IAAA,CAAK,IAAI,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAC,CAAA;AACvD,MAAA,IAAI,CAAC,QAAA,CAAS,MAAA,EAAO,EAAG;AACtB,QAAA,IAAA,CAAK,GAAA,CAAI,kCAAkC,GAAG,CAAA;AAC9C,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,MAAM,KAAA,GAAyB,SAAS,GAAA,EAAI;AAC5C,MAAA,KAAA,CAAM,MAAM,GAAA,GAAM,CAAA,GAAI,KAAK,GAAA,EAAI,GAAK,MAAM,GAAA,GAAQ,IAAA;AAElD,MAAA,MAAMC,YAAA,CAAID,aAAI,IAAA,CAAK,EAAA,EAAI,KAAK,IAAA,CAAK,GAAG,CAAC,CAAA,EAAG,KAAK,CAAA;AAC7C,MAAA,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,GAAA,EAAK,CAAA,CAAA,EAAI,GAAG,CAAA,EAAA,CAAI,CAAA;AACpC,MAAA,OAAO,IAAA;AAAA,IACT,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,eAAA,EAAiB,GAAA,EAAK,GAAG,CAAA;AAClC,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,GAAA,EAA8B;AACzC,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAMD,YAAA,CAAIC,YAAA,CAAI,IAAA,CAAK,IAAI,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAC,CAAA;AACvD,MAAA,IAAI,CAAC,QAAA,CAAS,MAAA,EAAO,EAAG,OAAO,CAAA;AAE/B,MAAA,MAAM,KAAA,GAAyB,SAAS,GAAA,EAAI;AAE5C,MAAA,IAAI,CAAC,KAAA,CAAM,GAAA,EAAK,OAAO,CAAA,CAAA;AAEvB,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,KAAA,CAAA,CAAO,KAAA,CAAM,GAAA,GAAM,IAAA,CAAK,GAAA,EAAI,IAAK,GAAI,CAAC,CAAA;AACzE,MAAA,OAAO,SAAA;AAAA,IACT,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,CAAI,YAAA,EAAc,GAAA,EAAK,GAAG,CAAA;AAC/B,MAAA,OAAO,CAAA;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,YAAY,MAAA,EAAoC;AAC9D,EAAA,OAAO,IAAI,cAAc,MAAM,CAAA;AACjC","file":"index.js","sourcesContent":["import { initializeApp, getApps } from 'firebase/app';\nimport { \n getDatabase, \n ref, \n get, \n set, \n remove, \n goOffline,\n update,\n increment,\n Database \n} from 'firebase/database';\nimport { CacheConfig, CacheEntry } from './types';\n\nexport class FirebaseCache {\n private db: Database;\n private root: string;\n private ttl: number;\n private debug: boolean;\n\n constructor(config: CacheConfig) {\n let app;\n const existingApp = getApps().find(a => a.name === (config.rootPath || '[DEFAULT]'));\n if (existingApp) {\n app = existingApp;\n } else {\n app = initializeApp(config.firebase, config.rootPath || '[DEFAULT]');\n }\n \n this.db = getDatabase(app);\n this.root = config.rootPath || 'flamecache';\n this.ttl = config.ttl || 3600;\n this.debug = config.debug || false;\n }\n\n private path(key: string): string {\n return `${this.root}/${key}`;\n }\n\n private log(...args: any[]): void {\n if (this.debug) console.log('[Flamecache]', ...args);\n }\n\n async get<T = any>(key: string): Promise<T | null> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) {\n this.log('miss:', key);\n return null;\n }\n\n const entry: CacheEntry<T> = snapshot.val();\n \n if (entry.exp && Date.now() > entry.exp) {\n this.log('expired:', key);\n await this.del(key);\n return null;\n }\n\n this.log('hit:', key);\n return entry.data;\n } catch (err) {\n this.log('error get:', key, err);\n return null;\n }\n }\n\n async set<T = any>(key: string, data: T, ttl?: number): Promise<void> {\n try {\n const seconds = ttl !== undefined ? ttl : this.ttl;\n const entry: CacheEntry<T> = {\n data,\n exp: seconds > 0 ? Date.now() + (seconds * 1000) : null\n };\n \n await set(ref(this.db, this.path(key)), entry);\n this.log('set:', key, `(${seconds}s)`);\n } catch (err) {\n this.log('error set:', key, err);\n throw err;\n }\n }\n\n async del(key: string): Promise<void> {\n try {\n await remove(ref(this.db, this.path(key)));\n this.log('del:', key);\n } catch (err) {\n this.log('error del:', key, err);\n }\n }\n\n async has(key: string): Promise<boolean> {\n return (await this.get(key)) !== null;\n }\n\n async wrap<T = any>(\n key: string,\n fetchFn: () => Promise<T>,\n ttl?: number\n ): Promise<T> {\n const cached = await this.get<T>(key);\n if (cached !== null) return cached;\n\n this.log('fetch:', key);\n const data = await fetchFn();\n await this.set(key, data, ttl);\n return data;\n }\n\n async mget<T = any>(keys: string[]): Promise<(T | null)[]> {\n return Promise.all(keys.map(k => this.get<T>(k)));\n }\n\n async mset(entries: Record<string, any>, ttl?: number): Promise<void> {\n try {\n const seconds = ttl !== undefined ? ttl : this.ttl;\n const exp = seconds > 0 ? Date.now() + (seconds * 1000) : null;\n const updates: Record<string, CacheEntry<any>> = {};\n \n for (const [key, data] of Object.entries(entries)) {\n updates[key] = {\n data,\n exp\n };\n }\n \n await update(ref(this.db, this.root), updates);\n this.log('mset:', Object.keys(entries).length, 'keys');\n } catch (err) {\n this.log('error mset:', err);\n throw err;\n }\n }\n\n async mdel(keys: string[]): Promise<void> {\n try {\n const updates: Record<string, null> = {};\n for (const key of keys) {\n updates[key] = null;\n }\n \n await update(ref(this.db, this.root), updates);\n this.log('mdel:', keys.length, 'keys');\n } catch (err) {\n this.log('error mdel:', err);\n throw err;\n }\n }\n\n async clear(): Promise<void> {\n try {\n await remove(ref(this.db, this.root));\n this.log('cleared all');\n } catch (err) {\n this.log('error clear:', err);\n throw err;\n }\n }\n\n async disconnect(): Promise<void> {\n await goOffline(this.db);\n this.log('disconnected');\n }\n\n async touch(key: string, ttl?: number): Promise<boolean> {\n const data = await this.get(key);\n if (data === null) return false;\n await this.set(key, data, ttl);\n return true;\n }\n\n async pull<T = any>(key: string): Promise<T | null> {\n const data = await this.get<T>(key);\n if (data !== null) await this.del(key);\n return data;\n }\n\n async incr(key: string, by: number = 1): Promise<number> {\n const op = by >= 0 ? 'incr' : 'decr';\n try {\n const path = this.path(key);\n const dbRef = ref(this.db, path);\n \n await update(dbRef, {\n 'data': increment(by),\n 'exp': this.ttl > 0 ? Date.now() + (this.ttl * 1000) : null\n });\n\n const newValue = await this.get<number>(key);\n const sign = by >= 0 ? '+' : '';\n this.log(`${op}:`, key, `${sign}${by} (atomic)`);\n return newValue ?? 0;\n } catch (err) {\n this.log(`error ${op}:`, key, err);\n throw err;\n }\n }\n\n async decr(key: string, by: number = 1): Promise<number> {\n return this.incr(key, -by);\n }\n\n async expire(key: string, ttl: number): Promise<boolean> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) {\n this.log('expire failed - key not found:', key);\n return false;\n }\n\n const entry: CacheEntry<any> = snapshot.val();\n entry.exp = ttl > 0 ? Date.now() + (ttl * 1000) : null;\n \n await set(ref(this.db, this.path(key)), entry);\n this.log('expire:', key, `(${ttl}s)`);\n return true;\n } catch (err) {\n this.log('error expire:', key, err);\n return false;\n }\n }\n\n async getTtl(key: string): Promise<number> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) return 0;\n\n const entry: CacheEntry<any> = snapshot.val();\n \n if (!entry.exp) return -1;\n \n const remaining = Math.max(0, Math.floor((entry.exp - Date.now()) / 1000));\n return remaining;\n } catch (err) {\n this.log('error ttl:', key, err);\n return 0;\n }\n }\n}\n\nexport function createCache(config: CacheConfig): FirebaseCache {\n return new FirebaseCache(config);\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getApps, initializeApp } from 'firebase/app';
|
|
2
|
-
import { getDatabase, get, ref, set, remove,
|
|
2
|
+
import { getDatabase, get, ref, set, remove, update, goOffline, increment } from 'firebase/database';
|
|
3
3
|
|
|
4
4
|
// src/cache.ts
|
|
5
5
|
var FirebaseCache = class {
|
|
@@ -79,12 +79,35 @@ var FirebaseCache = class {
|
|
|
79
79
|
return Promise.all(keys.map((k) => this.get(k)));
|
|
80
80
|
}
|
|
81
81
|
async mset(entries, ttl) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
try {
|
|
83
|
+
const seconds = ttl !== void 0 ? ttl : this.ttl;
|
|
84
|
+
const exp = seconds > 0 ? Date.now() + seconds * 1e3 : null;
|
|
85
|
+
const updates = {};
|
|
86
|
+
for (const [key, data] of Object.entries(entries)) {
|
|
87
|
+
updates[key] = {
|
|
88
|
+
data,
|
|
89
|
+
exp
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
await update(ref(this.db, this.root), updates);
|
|
93
|
+
this.log("mset:", Object.keys(entries).length, "keys");
|
|
94
|
+
} catch (err) {
|
|
95
|
+
this.log("error mset:", err);
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
85
98
|
}
|
|
86
99
|
async mdel(keys) {
|
|
87
|
-
|
|
100
|
+
try {
|
|
101
|
+
const updates = {};
|
|
102
|
+
for (const key of keys) {
|
|
103
|
+
updates[key] = null;
|
|
104
|
+
}
|
|
105
|
+
await update(ref(this.db, this.root), updates);
|
|
106
|
+
this.log("mdel:", keys.length, "keys");
|
|
107
|
+
} catch (err) {
|
|
108
|
+
this.log("error mdel:", err);
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
88
111
|
}
|
|
89
112
|
async clear() {
|
|
90
113
|
try {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cache.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { initializeApp, getApps } from 'firebase/app';\nimport { \n getDatabase, \n ref, \n get, \n set, \n remove, \n goOffline,\n update,\n increment,\n Database \n} from 'firebase/database';\nimport { CacheConfig, CacheEntry } from './types';\n\nexport class FirebaseCache {\n private db: Database;\n private root: string;\n private ttl: number;\n private debug: boolean;\n\n constructor(config: CacheConfig) {\n let app;\n const existingApp = getApps().find(a => a.name === (config.rootPath || '[DEFAULT]'));\n if (existingApp) {\n app = existingApp;\n } else {\n app = initializeApp(config.firebase, config.rootPath || '[DEFAULT]');\n }\n \n this.db = getDatabase(app);\n this.root = config.rootPath || 'flamecache';\n this.ttl = config.ttl || 3600;\n this.debug = config.debug || false;\n }\n\n private path(key: string): string {\n return `${this.root}/${key}`;\n }\n\n private log(...args: any[]): void {\n if (this.debug) console.log('[Flamecache]', ...args);\n }\n\n async get<T = any>(key: string): Promise<T | null> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) {\n this.log('miss:', key);\n return null;\n }\n\n const entry: CacheEntry<T> = snapshot.val();\n \n if (entry.exp && Date.now() > entry.exp) {\n this.log('expired:', key);\n await this.del(key);\n return null;\n }\n\n this.log('hit:', key);\n return entry.data;\n } catch (err) {\n this.log('error get:', key, err);\n return null;\n }\n }\n\n async set<T = any>(key: string, data: T, ttl?: number): Promise<void> {\n try {\n const seconds = ttl !== undefined ? ttl : this.ttl;\n const entry: CacheEntry<T> = {\n data,\n exp: seconds > 0 ? Date.now() + (seconds * 1000) : null\n };\n \n await set(ref(this.db, this.path(key)), entry);\n this.log('set:', key, `(${seconds}s)`);\n } catch (err) {\n this.log('error set:', key, err);\n throw err;\n }\n }\n\n async del(key: string): Promise<void> {\n try {\n await remove(ref(this.db, this.path(key)));\n this.log('del:', key);\n } catch (err) {\n this.log('error del:', key, err);\n }\n }\n\n async has(key: string): Promise<boolean> {\n return (await this.get(key)) !== null;\n }\n\n async wrap<T = any>(\n key: string,\n fetchFn: () => Promise<T>,\n ttl?: number\n ): Promise<T> {\n const cached = await this.get<T>(key);\n if (cached !== null) return cached;\n\n this.log('fetch:', key);\n const data = await fetchFn();\n await this.set(key, data, ttl);\n return data;\n }\n\n async mget<T = any>(keys: string[]): Promise<(T | null)[]> {\n return Promise.all(keys.map(k => this.get<T>(k)));\n }\n\n async mset(entries: Record<string, any>, ttl?: number): Promise<void> {\n await Promise.all(\n Object.entries(entries).map(([k, v]) => this.set(k, v, ttl))\n );\n }\n\n async mdel(keys: string[]): Promise<void> {\n await Promise.all(keys.map(k => this.del(k)));\n }\n\n async clear(): Promise<void> {\n try {\n await remove(ref(this.db, this.root));\n this.log('cleared all');\n } catch (err) {\n this.log('error clear:', err);\n throw err;\n }\n }\n\n async disconnect(): Promise<void> {\n await goOffline(this.db);\n this.log('disconnected');\n }\n\n async touch(key: string, ttl?: number): Promise<boolean> {\n const data = await this.get(key);\n if (data === null) return false;\n await this.set(key, data, ttl);\n return true;\n }\n\n async pull<T = any>(key: string): Promise<T | null> {\n const data = await this.get<T>(key);\n if (data !== null) await this.del(key);\n return data;\n }\n\n async incr(key: string, by: number = 1): Promise<number> {\n const op = by >= 0 ? 'incr' : 'decr';\n try {\n const path = this.path(key);\n const dbRef = ref(this.db, path);\n \n await update(dbRef, {\n 'data': increment(by),\n 'exp': this.ttl > 0 ? Date.now() + (this.ttl * 1000) : null\n });\n\n const newValue = await this.get<number>(key);\n const sign = by >= 0 ? '+' : '';\n this.log(`${op}:`, key, `${sign}${by} (atomic)`);\n return newValue ?? 0;\n } catch (err) {\n this.log(`error ${op}:`, key, err);\n throw err;\n }\n }\n\n async decr(key: string, by: number = 1): Promise<number> {\n return this.incr(key, -by);\n }\n\n async expire(key: string, ttl: number): Promise<boolean> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) {\n this.log('expire failed - key not found:', key);\n return false;\n }\n\n const entry: CacheEntry<any> = snapshot.val();\n entry.exp = ttl > 0 ? Date.now() + (ttl * 1000) : null;\n \n await set(ref(this.db, this.path(key)), entry);\n this.log('expire:', key, `(${ttl}s)`);\n return true;\n } catch (err) {\n this.log('error expire:', key, err);\n return false;\n }\n }\n\n async getTtl(key: string): Promise<number> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) return 0;\n\n const entry: CacheEntry<any> = snapshot.val();\n \n if (!entry.exp) return -1;\n \n const remaining = Math.max(0, Math.floor((entry.exp - Date.now()) / 1000));\n return remaining;\n } catch (err) {\n this.log('error ttl:', key, err);\n return 0;\n }\n }\n}\n\nexport function createCache(config: CacheConfig): FirebaseCache {\n return new FirebaseCache(config);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/cache.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { initializeApp, getApps } from 'firebase/app';\nimport { \n getDatabase, \n ref, \n get, \n set, \n remove, \n goOffline,\n update,\n increment,\n Database \n} from 'firebase/database';\nimport { CacheConfig, CacheEntry } from './types';\n\nexport class FirebaseCache {\n private db: Database;\n private root: string;\n private ttl: number;\n private debug: boolean;\n\n constructor(config: CacheConfig) {\n let app;\n const existingApp = getApps().find(a => a.name === (config.rootPath || '[DEFAULT]'));\n if (existingApp) {\n app = existingApp;\n } else {\n app = initializeApp(config.firebase, config.rootPath || '[DEFAULT]');\n }\n \n this.db = getDatabase(app);\n this.root = config.rootPath || 'flamecache';\n this.ttl = config.ttl || 3600;\n this.debug = config.debug || false;\n }\n\n private path(key: string): string {\n return `${this.root}/${key}`;\n }\n\n private log(...args: any[]): void {\n if (this.debug) console.log('[Flamecache]', ...args);\n }\n\n async get<T = any>(key: string): Promise<T | null> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) {\n this.log('miss:', key);\n return null;\n }\n\n const entry: CacheEntry<T> = snapshot.val();\n \n if (entry.exp && Date.now() > entry.exp) {\n this.log('expired:', key);\n await this.del(key);\n return null;\n }\n\n this.log('hit:', key);\n return entry.data;\n } catch (err) {\n this.log('error get:', key, err);\n return null;\n }\n }\n\n async set<T = any>(key: string, data: T, ttl?: number): Promise<void> {\n try {\n const seconds = ttl !== undefined ? ttl : this.ttl;\n const entry: CacheEntry<T> = {\n data,\n exp: seconds > 0 ? Date.now() + (seconds * 1000) : null\n };\n \n await set(ref(this.db, this.path(key)), entry);\n this.log('set:', key, `(${seconds}s)`);\n } catch (err) {\n this.log('error set:', key, err);\n throw err;\n }\n }\n\n async del(key: string): Promise<void> {\n try {\n await remove(ref(this.db, this.path(key)));\n this.log('del:', key);\n } catch (err) {\n this.log('error del:', key, err);\n }\n }\n\n async has(key: string): Promise<boolean> {\n return (await this.get(key)) !== null;\n }\n\n async wrap<T = any>(\n key: string,\n fetchFn: () => Promise<T>,\n ttl?: number\n ): Promise<T> {\n const cached = await this.get<T>(key);\n if (cached !== null) return cached;\n\n this.log('fetch:', key);\n const data = await fetchFn();\n await this.set(key, data, ttl);\n return data;\n }\n\n async mget<T = any>(keys: string[]): Promise<(T | null)[]> {\n return Promise.all(keys.map(k => this.get<T>(k)));\n }\n\n async mset(entries: Record<string, any>, ttl?: number): Promise<void> {\n try {\n const seconds = ttl !== undefined ? ttl : this.ttl;\n const exp = seconds > 0 ? Date.now() + (seconds * 1000) : null;\n const updates: Record<string, CacheEntry<any>> = {};\n \n for (const [key, data] of Object.entries(entries)) {\n updates[key] = {\n data,\n exp\n };\n }\n \n await update(ref(this.db, this.root), updates);\n this.log('mset:', Object.keys(entries).length, 'keys');\n } catch (err) {\n this.log('error mset:', err);\n throw err;\n }\n }\n\n async mdel(keys: string[]): Promise<void> {\n try {\n const updates: Record<string, null> = {};\n for (const key of keys) {\n updates[key] = null;\n }\n \n await update(ref(this.db, this.root), updates);\n this.log('mdel:', keys.length, 'keys');\n } catch (err) {\n this.log('error mdel:', err);\n throw err;\n }\n }\n\n async clear(): Promise<void> {\n try {\n await remove(ref(this.db, this.root));\n this.log('cleared all');\n } catch (err) {\n this.log('error clear:', err);\n throw err;\n }\n }\n\n async disconnect(): Promise<void> {\n await goOffline(this.db);\n this.log('disconnected');\n }\n\n async touch(key: string, ttl?: number): Promise<boolean> {\n const data = await this.get(key);\n if (data === null) return false;\n await this.set(key, data, ttl);\n return true;\n }\n\n async pull<T = any>(key: string): Promise<T | null> {\n const data = await this.get<T>(key);\n if (data !== null) await this.del(key);\n return data;\n }\n\n async incr(key: string, by: number = 1): Promise<number> {\n const op = by >= 0 ? 'incr' : 'decr';\n try {\n const path = this.path(key);\n const dbRef = ref(this.db, path);\n \n await update(dbRef, {\n 'data': increment(by),\n 'exp': this.ttl > 0 ? Date.now() + (this.ttl * 1000) : null\n });\n\n const newValue = await this.get<number>(key);\n const sign = by >= 0 ? '+' : '';\n this.log(`${op}:`, key, `${sign}${by} (atomic)`);\n return newValue ?? 0;\n } catch (err) {\n this.log(`error ${op}:`, key, err);\n throw err;\n }\n }\n\n async decr(key: string, by: number = 1): Promise<number> {\n return this.incr(key, -by);\n }\n\n async expire(key: string, ttl: number): Promise<boolean> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) {\n this.log('expire failed - key not found:', key);\n return false;\n }\n\n const entry: CacheEntry<any> = snapshot.val();\n entry.exp = ttl > 0 ? Date.now() + (ttl * 1000) : null;\n \n await set(ref(this.db, this.path(key)), entry);\n this.log('expire:', key, `(${ttl}s)`);\n return true;\n } catch (err) {\n this.log('error expire:', key, err);\n return false;\n }\n }\n\n async getTtl(key: string): Promise<number> {\n try {\n const snapshot = await get(ref(this.db, this.path(key)));\n if (!snapshot.exists()) return 0;\n\n const entry: CacheEntry<any> = snapshot.val();\n \n if (!entry.exp) return -1;\n \n const remaining = Math.max(0, Math.floor((entry.exp - Date.now()) / 1000));\n return remaining;\n } catch (err) {\n this.log('error ttl:', key, err);\n return 0;\n }\n }\n}\n\nexport function createCache(config: CacheConfig): FirebaseCache {\n return new FirebaseCache(config);\n}\n"]}
|