@portel/photon-core 2.19.2 → 2.20.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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +61 -76
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +163 -189
- package/dist/memory.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +5 -0
- package/src/memory.ts +211 -199
package/dist/index.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export { getMimeType } from './mime-types.js';
|
|
|
59
59
|
export { parseRuntimeRequirement, checkRuntimeCompatibility, } from './version-check.js';
|
|
60
60
|
export { PhotonError, ValidationError, type ValidationResult, type Validator, combineResults, isString, isNumber, isBoolean, isObject, isArray, notEmpty, hasLength, matchesPattern, isEmail, isUrl, inRange, isPositive, isInteger, hasArrayLength, arrayOf, hasFields, oneOf, validate, validateOrThrow, pathExists, hasExtension, assertDefined, assertString, assertNumber, assertObject, assertArray, } from './validation.js';
|
|
61
61
|
export { AuditTrail, getAuditTrail, setAuditTrail, generateExecutionId, type ExecutionRecord, type AuditQueryOptions, } from './audit.js';
|
|
62
|
-
export { MemoryProvider, type MemoryScope, } from './memory.js';
|
|
62
|
+
export { MemoryProvider, FileMemoryBackend, setDefaultMemoryBackend, getDefaultMemoryBackend, type MemoryBackend, type MemoryScope, } from './memory.js';
|
|
63
63
|
export { ScheduleProvider, type ScheduleStatus, type ScheduledTask, type CreateScheduleOptions, type UpdateScheduleOptions, } from './schedule.js';
|
|
64
64
|
export { discoverAssets, autoDiscoverAssets, } from './asset-discovery.js';
|
|
65
65
|
export { parseDuration, parseRate } from './utils/duration.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACb,KAAK,aAAa,EAGlB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,UAAU,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,MAAM,EAGN,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAGhB,gBAAgB,EAChB,cAAc,EACd,UAAU,EACV,KAAK,UAAU,EAGf,SAAS,EAGT,YAAY,EACZ,UAAU,EACV,UAAU,EACV,aAAa,EAGb,MAAM,EACN,YAAY,EACZ,SAAS,GACV,MAAM,aAAa,CAAC;AAIrB,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,aAAa,EAGlB,SAAS,EACT,KAAK,gBAAgB,EACrB,QAAQ,EACR,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,EACrB,cAAc,EAGd,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,yBAAyB,EACzB,gBAAgB,EAGhB,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,WAAW,EACX,cAAc,EAGd,MAAM,EACN,OAAO,EACP,MAAM,EACN,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,WAAW,CAAC;AAGxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGnG,OAAO,EACL,WAAW,EACX,SAAS,EACT,sBAAsB,EACtB,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,4BAA4B,EAC5B,eAAe,EACf,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAC;AAG5B,cAAc,YAAY,CAAC;AAG3B,OAAO,EAEL,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,WAAW,EAGX,wBAAwB,EACxB,gBAAgB,EAGhB,gBAAgB,EAGhB,WAAW,EAGX,uBAAuB,EACvB,eAAe,EAGf,eAAe,EAGf,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,MAAM,EAGX,KAAK,YAAY,EACjB,KAAK,kBAAkB,EAGvB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAG5B,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAGrB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,eAAe,EAGpB,KAAK,eAAe,EAGpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAGlB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAC5B,KAAK,YAAY,GAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,wBAAwB,EACxB,aAAa,EACb,oBAAoB,EACpB,QAAQ,EACR,UAAU,EACV,SAAS,EACT,WAAW,EACX,KAAK,eAAe,IAAI,uBAAuB,EAC/C,KAAK,aAAa,IAAI,qBAAqB,EAC3C,iBAAiB,IAAI,yBAAyB,EAC9C,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,KAAK,UAAU,EACf,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,aAAa,EACb,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAIxC,cAAc,0BAA0B,CAAC;AAGzC,cAAc,sBAAsB,CAAC;AAIrC,cAAc,gBAAgB,CAAC;AAI/B,cAAc,qBAAqB,CAAC;AAIpC,OAAO,EACL,QAAQ,EACR,cAAc,EACd,cAAc,EACd,KAAK,WAAW,GACjB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EACpB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAIvB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAIrB,OAAO,EACL,OAAO,EACP,UAAU,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,0BAA0B,EAC1B,0BAA0B,EAC1B,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIhD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAI9C,OAAO,EACL,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EACL,WAAW,EACX,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,cAAc,EACd,OAAO,EACP,KAAK,EACL,OAAO,EACP,UAAU,EACV,SAAS,EACT,cAAc,EACd,OAAO,EACP,SAAS,EACT,KAAK,EACL,QAAQ,EACR,eAAe,EACf,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,YAAY,CAAC;AAKpB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AAIrB,OAAO,EACL,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,GAC3B,MAAM,eAAe,CAAC;AAIvB,OAAO,EACL,cAAc,EACd,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAI/D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,MAAM,GACZ,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAIzG,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIxE,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAI/E,OAAO,EAEL,KAAK,EAAG,uBAAuB;AAC/B,GAAG,EAAK,qBAAqB;AAC7B,GAAG,EAAK,qBAAqB;AAE7B,aAAa,EACb,WAAW,EACX,WAAW,EACX,KAAK,OAAO,EAEZ,UAAU,EACV,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAEL,YAAY,EACZ,cAAc,EAGd,KAAK,EACL,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,aAAa,EAGlB,KAAK,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,EACL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAGjB,KAAK,EACL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,EACL,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,QAAQ,EACR,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,eAAe,EAGpB,IAAI,EACJ,KAAK,SAAS,EACd,KAAK,SAAS,IAAI,aAAa,EAC/B,KAAK,WAAW,GACjB,MAAM,qBAAqB,CAAC;AAI7B,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -136,7 +136,8 @@ export { PhotonError, ValidationError, combineResults, isString, isNumber, isBoo
|
|
|
136
136
|
export { AuditTrail, getAuditTrail, setAuditTrail, generateExecutionId, } from './audit.js';
|
|
137
137
|
// ===== SCOPED MEMORY =====
|
|
138
138
|
// Framework-level key-value storage (this.memory on Photon base class)
|
|
139
|
-
|
|
139
|
+
// MemoryBackend is the pluggable interface; FileMemoryBackend is the default.
|
|
140
|
+
export { MemoryProvider, FileMemoryBackend, setDefaultMemoryBackend, getDefaultMemoryBackend, } from './memory.js';
|
|
140
141
|
// ===== RUNTIME SCHEDULING =====
|
|
141
142
|
// Programmatic task scheduling (this.schedule on Photon base class)
|
|
142
143
|
export { ScheduleProvider, } from './schedule.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/memory.d.ts
CHANGED
|
@@ -4,106 +4,91 @@
|
|
|
4
4
|
* Framework-level key-value storage for photons that eliminates
|
|
5
5
|
* boilerplate file I/O. Available as `this.memory` on Photon.
|
|
6
6
|
*
|
|
7
|
+
* Architecture: MemoryProvider delegates to a pluggable MemoryBackend.
|
|
8
|
+
* The default backend is FileMemoryBackend (JSON files on disk).
|
|
9
|
+
* Enterprise deployments can swap in Redis, Postgres, or SQLite.
|
|
10
|
+
*
|
|
7
11
|
* Three scopes:
|
|
8
|
-
* | Scope | Meaning |
|
|
9
|
-
*
|
|
10
|
-
* | photon | Private to this photon (default) |
|
|
11
|
-
* | session | Per-user session (Beam sessions) |
|
|
12
|
-
* | global | Shared across all photons |
|
|
12
|
+
* | Scope | Meaning |
|
|
13
|
+
* |----------|----------------------------------|
|
|
14
|
+
* | photon | Private to this photon (default) |
|
|
15
|
+
* | session | Per-user session (Beam sessions) |
|
|
16
|
+
* | global | Shared across all photons |
|
|
17
|
+
*/
|
|
18
|
+
export type MemoryScope = 'photon' | 'session' | 'global';
|
|
19
|
+
/**
|
|
20
|
+
* Pluggable storage backend for MemoryProvider.
|
|
21
|
+
*
|
|
22
|
+
* Implementations handle the actual persistence. All methods receive
|
|
23
|
+
* a resolved namespace (scope + photonId + sessionId already baked in)
|
|
24
|
+
* so the backend doesn't need to know about scoping rules.
|
|
25
|
+
*/
|
|
26
|
+
export interface MemoryBackend {
|
|
27
|
+
get(namespace: string, key: string): Promise<any | null>;
|
|
28
|
+
set(namespace: string, key: string, value: any): Promise<void>;
|
|
29
|
+
delete(namespace: string, key: string): Promise<boolean>;
|
|
30
|
+
has(namespace: string, key: string): Promise<boolean>;
|
|
31
|
+
keys(namespace: string): Promise<string[]>;
|
|
32
|
+
clear(namespace: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Atomic read-modify-write. Backends with native transactions (Redis WATCH,
|
|
35
|
+
* Postgres FOR UPDATE) should use them here. The default file backend
|
|
36
|
+
* uses a per-key promise chain.
|
|
37
|
+
*/
|
|
38
|
+
update(namespace: string, key: string, updater: (current: any | null) => any): Promise<any>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* File-based memory backend. Each key is a JSON file on disk.
|
|
42
|
+
* Uses per-key promise chains and temp+rename for safe concurrent access.
|
|
43
|
+
*/
|
|
44
|
+
export declare class FileMemoryBackend implements MemoryBackend {
|
|
45
|
+
private _locks;
|
|
46
|
+
private withLock;
|
|
47
|
+
get(namespace: string, key: string): Promise<any | null>;
|
|
48
|
+
set(namespace: string, key: string, value: any): Promise<void>;
|
|
49
|
+
delete(namespace: string, key: string): Promise<boolean>;
|
|
50
|
+
has(namespace: string, key: string): Promise<boolean>;
|
|
51
|
+
keys(namespace: string): Promise<string[]>;
|
|
52
|
+
clear(namespace: string): Promise<void>;
|
|
53
|
+
update(namespace: string, key: string, updater: (current: any | null) => any): Promise<any>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Set the global default memory backend.
|
|
57
|
+
* Call before any photons are loaded to switch storage layer.
|
|
13
58
|
*
|
|
14
59
|
* @example
|
|
15
60
|
* ```typescript
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* items.push({ id: crypto.randomUUID(), text });
|
|
20
|
-
* await this.memory.set('items', items);
|
|
21
|
-
* return items;
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
61
|
+
* import { setDefaultMemoryBackend } from '@portel/photon-core';
|
|
62
|
+
* import { RedisMemoryBackend } from '@portel/photon-redis';
|
|
63
|
+
* setDefaultMemoryBackend(new RedisMemoryBackend({ url: 'redis://...' }));
|
|
24
64
|
* ```
|
|
25
65
|
*/
|
|
26
|
-
export
|
|
66
|
+
export declare function setDefaultMemoryBackend(backend: MemoryBackend): void;
|
|
67
|
+
export declare function getDefaultMemoryBackend(): MemoryBackend;
|
|
27
68
|
/**
|
|
28
69
|
* Scoped Memory Provider
|
|
29
70
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
71
|
+
* The public API surface for `this.memory` on photon instances.
|
|
72
|
+
* Delegates all operations to the configured MemoryBackend.
|
|
32
73
|
*/
|
|
33
74
|
export declare class MemoryProvider {
|
|
34
75
|
private _photonId;
|
|
35
76
|
private _namespace;
|
|
36
77
|
private _sessionId?;
|
|
37
78
|
private _baseDir?;
|
|
38
|
-
private
|
|
39
|
-
constructor(photonId: string, sessionId?: string, namespace?: string, baseDir?: string);
|
|
40
|
-
/**
|
|
41
|
-
* Serialize file operations per key to prevent concurrent write corruption.
|
|
42
|
-
* Reads also go through the lock to avoid reading a partially-written file.
|
|
43
|
-
*/
|
|
44
|
-
private withKeyLock;
|
|
45
|
-
/**
|
|
46
|
-
* Current session ID (can be updated by the runtime)
|
|
47
|
-
*/
|
|
79
|
+
private _backend;
|
|
80
|
+
constructor(photonId: string, sessionId?: string, namespace?: string, baseDir?: string, backend?: MemoryBackend);
|
|
48
81
|
get sessionId(): string | undefined;
|
|
49
82
|
set sessionId(id: string | undefined);
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
*
|
|
53
|
-
* @param key The key to retrieve
|
|
54
|
-
* @param scope Storage scope (default: 'photon')
|
|
55
|
-
* @returns The stored value, or null if not found
|
|
56
|
-
*/
|
|
83
|
+
/** Resolve the storage namespace (directory for file backend, prefix for Redis, etc.) */
|
|
84
|
+
private ns;
|
|
57
85
|
get<T = any>(key: string, scope?: MemoryScope): Promise<T | null>;
|
|
58
|
-
/**
|
|
59
|
-
* Set a value in memory
|
|
60
|
-
*
|
|
61
|
-
* @param key The key to store
|
|
62
|
-
* @param value The value (must be JSON-serializable)
|
|
63
|
-
* @param scope Storage scope (default: 'photon')
|
|
64
|
-
*/
|
|
65
86
|
set<T = any>(key: string, value: T, scope?: MemoryScope): Promise<void>;
|
|
66
|
-
/**
|
|
67
|
-
* Delete a key from memory
|
|
68
|
-
*
|
|
69
|
-
* @param key The key to delete
|
|
70
|
-
* @param scope Storage scope (default: 'photon')
|
|
71
|
-
* @returns true if the key existed and was deleted
|
|
72
|
-
*/
|
|
73
87
|
delete(key: string, scope?: MemoryScope): Promise<boolean>;
|
|
74
|
-
/**
|
|
75
|
-
* Check if a key exists in memory
|
|
76
|
-
*
|
|
77
|
-
* @param key The key to check
|
|
78
|
-
* @param scope Storage scope (default: 'photon')
|
|
79
|
-
*/
|
|
80
88
|
has(key: string, scope?: MemoryScope): Promise<boolean>;
|
|
81
|
-
/**
|
|
82
|
-
* List all keys in memory for a scope
|
|
83
|
-
*
|
|
84
|
-
* @param scope Storage scope (default: 'photon')
|
|
85
|
-
*/
|
|
86
89
|
keys(scope?: MemoryScope): Promise<string[]>;
|
|
87
|
-
/**
|
|
88
|
-
* Clear all keys in a scope
|
|
89
|
-
*
|
|
90
|
-
* @param scope Storage scope (default: 'photon')
|
|
91
|
-
*/
|
|
92
90
|
clear(scope?: MemoryScope): Promise<void>;
|
|
93
|
-
/**
|
|
94
|
-
* Get all key-value pairs in a scope
|
|
95
|
-
*
|
|
96
|
-
* @param scope Storage scope (default: 'photon')
|
|
97
|
-
*/
|
|
98
91
|
getAll<T = any>(scope?: MemoryScope): Promise<Record<string, T>>;
|
|
99
|
-
/**
|
|
100
|
-
* Atomic read-modify-write for a key.
|
|
101
|
-
* Serialized per key so concurrent updates don't corrupt data.
|
|
102
|
-
*
|
|
103
|
-
* @param key The key to update
|
|
104
|
-
* @param updater Function that receives current value and returns new value
|
|
105
|
-
* @param scope Storage scope (default: 'photon')
|
|
106
|
-
*/
|
|
107
92
|
update<T = any>(key: string, updater: (current: T | null) => T, scope?: MemoryScope): Promise<T>;
|
|
108
93
|
}
|
|
109
94
|
//# sourceMappingURL=memory.d.ts.map
|
package/dist/memory.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
|
package/dist/memory.js
CHANGED
|
@@ -4,80 +4,28 @@
|
|
|
4
4
|
* Framework-level key-value storage for photons that eliminates
|
|
5
5
|
* boilerplate file I/O. Available as `this.memory` on Photon.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* | photon | Private to this photon (default) | .data/{namespace}/{photonName}/memory/ |
|
|
11
|
-
* | session | Per-user session (Beam sessions) | .data/_sessions/{sessionId}/{ns}/{photon}/ |
|
|
12
|
-
* | global | Shared across all photons | .data/_global/ |
|
|
7
|
+
* Architecture: MemoryProvider delegates to a pluggable MemoryBackend.
|
|
8
|
+
* The default backend is FileMemoryBackend (JSON files on disk).
|
|
9
|
+
* Enterprise deployments can swap in Redis, Postgres, or SQLite.
|
|
13
10
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* await this.memory.set('items', items);
|
|
21
|
-
* return items;
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
11
|
+
* Three scopes:
|
|
12
|
+
* | Scope | Meaning |
|
|
13
|
+
* |----------|----------------------------------|
|
|
14
|
+
* | photon | Private to this photon (default) |
|
|
15
|
+
* | session | Per-user session (Beam sessions) |
|
|
16
|
+
* | global | Shared across all photons |
|
|
25
17
|
*/
|
|
26
18
|
import * as fs from 'fs/promises';
|
|
27
19
|
import * as fsSync from 'fs';
|
|
28
20
|
import * as path from 'path';
|
|
29
21
|
import { getPhotonMemoryDir, getGlobalMemoryDir, getSessionMemoryDir, getLegacyMemoryDir, getLegacyGlobalMemoryDir, getLegacySessionMemoryDir, } from './data-paths.js';
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*/
|
|
34
|
-
function resolveDir(photonId, namespace, scope, sessionId, baseDir) {
|
|
35
|
-
switch (scope) {
|
|
36
|
-
case 'photon': {
|
|
37
|
-
const newDir = getPhotonMemoryDir(namespace, photonId, baseDir);
|
|
38
|
-
// Fallback: check legacy path if new path has no data yet
|
|
39
|
-
if (!fsSync.existsSync(newDir)) {
|
|
40
|
-
const legacyDir = getLegacyMemoryDir(photonId, baseDir);
|
|
41
|
-
if (fsSync.existsSync(legacyDir))
|
|
42
|
-
return legacyDir;
|
|
43
|
-
}
|
|
44
|
-
return newDir;
|
|
45
|
-
}
|
|
46
|
-
case 'session': {
|
|
47
|
-
if (!sessionId) {
|
|
48
|
-
throw new Error('Session ID required for session-scoped memory. Set via memory.sessionId.');
|
|
49
|
-
}
|
|
50
|
-
const newDir = getSessionMemoryDir(sessionId, namespace, photonId, baseDir);
|
|
51
|
-
if (!fsSync.existsSync(newDir)) {
|
|
52
|
-
const legacyDir = getLegacySessionMemoryDir(sessionId, photonId, baseDir);
|
|
53
|
-
if (fsSync.existsSync(legacyDir))
|
|
54
|
-
return legacyDir;
|
|
55
|
-
}
|
|
56
|
-
return newDir;
|
|
57
|
-
}
|
|
58
|
-
case 'global': {
|
|
59
|
-
const newDir = getGlobalMemoryDir(baseDir);
|
|
60
|
-
if (!fsSync.existsSync(newDir)) {
|
|
61
|
-
const legacyDir = getLegacyGlobalMemoryDir(baseDir);
|
|
62
|
-
if (fsSync.existsSync(legacyDir))
|
|
63
|
-
return legacyDir;
|
|
64
|
-
}
|
|
65
|
-
return newDir;
|
|
66
|
-
}
|
|
67
|
-
default:
|
|
68
|
-
throw new Error(`Unknown memory scope: ${scope}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Get the file path for a key within a directory
|
|
73
|
-
*/
|
|
22
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
23
|
+
// FILE BACKEND (default)
|
|
24
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
74
25
|
function keyPath(dir, key) {
|
|
75
26
|
const safeKey = key.replace(/[^a-zA-Z0-9_.-]/g, '_');
|
|
76
27
|
return path.join(dir, `${safeKey}.json`);
|
|
77
28
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Check if a path exists (async)
|
|
80
|
-
*/
|
|
81
29
|
async function pathExists(p) {
|
|
82
30
|
try {
|
|
83
31
|
await fs.access(p);
|
|
@@ -88,29 +36,13 @@ async function pathExists(p) {
|
|
|
88
36
|
}
|
|
89
37
|
}
|
|
90
38
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* Provides key-value storage with automatic JSON serialization.
|
|
94
|
-
* Each key is stored as a separate file for atomic operations.
|
|
39
|
+
* File-based memory backend. Each key is a JSON file on disk.
|
|
40
|
+
* Uses per-key promise chains and temp+rename for safe concurrent access.
|
|
95
41
|
*/
|
|
96
|
-
export class
|
|
97
|
-
_photonId;
|
|
98
|
-
_namespace;
|
|
99
|
-
_sessionId;
|
|
100
|
-
_baseDir;
|
|
42
|
+
export class FileMemoryBackend {
|
|
101
43
|
_locks = new Map();
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this._namespace = namespace || 'local';
|
|
105
|
-
this._sessionId = sessionId;
|
|
106
|
-
this._baseDir = baseDir;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Serialize file operations per key to prevent concurrent write corruption.
|
|
110
|
-
* Reads also go through the lock to avoid reading a partially-written file.
|
|
111
|
-
*/
|
|
112
|
-
async withKeyLock(key, scope, fn) {
|
|
113
|
-
const lockKey = `${scope}:${key}`;
|
|
44
|
+
async withLock(namespace, key, fn) {
|
|
45
|
+
const lockKey = `${namespace}:${key}`;
|
|
114
46
|
const prev = this._locks.get(lockKey) ?? Promise.resolve();
|
|
115
47
|
let resolve;
|
|
116
48
|
const next = new Promise(r => { resolve = r; });
|
|
@@ -126,26 +58,9 @@ export class MemoryProvider {
|
|
|
126
58
|
}
|
|
127
59
|
}
|
|
128
60
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
get sessionId() {
|
|
133
|
-
return this._sessionId;
|
|
134
|
-
}
|
|
135
|
-
set sessionId(id) {
|
|
136
|
-
this._sessionId = id;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Get a value from memory
|
|
140
|
-
*
|
|
141
|
-
* @param key The key to retrieve
|
|
142
|
-
* @param scope Storage scope (default: 'photon')
|
|
143
|
-
* @returns The stored value, or null if not found
|
|
144
|
-
*/
|
|
145
|
-
async get(key, scope = 'photon') {
|
|
146
|
-
return this.withKeyLock(key, scope, async () => {
|
|
147
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
148
|
-
const filePath = keyPath(dir, key);
|
|
61
|
+
async get(namespace, key) {
|
|
62
|
+
return this.withLock(namespace, key, async () => {
|
|
63
|
+
const filePath = keyPath(namespace, key);
|
|
149
64
|
try {
|
|
150
65
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
151
66
|
return JSON.parse(content);
|
|
@@ -157,37 +72,20 @@ export class MemoryProvider {
|
|
|
157
72
|
}
|
|
158
73
|
});
|
|
159
74
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
* @param value The value (must be JSON-serializable)
|
|
165
|
-
* @param scope Storage scope (default: 'photon')
|
|
166
|
-
*/
|
|
167
|
-
async set(key, value, scope = 'photon') {
|
|
168
|
-
return this.withKeyLock(key, scope, async () => {
|
|
169
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
170
|
-
if (!await pathExists(dir)) {
|
|
171
|
-
await fs.mkdir(dir, { recursive: true });
|
|
75
|
+
async set(namespace, key, value) {
|
|
76
|
+
return this.withLock(namespace, key, async () => {
|
|
77
|
+
if (!await pathExists(namespace)) {
|
|
78
|
+
await fs.mkdir(namespace, { recursive: true });
|
|
172
79
|
}
|
|
173
|
-
const filePath = keyPath(
|
|
174
|
-
// Write to temp file then rename for atomic replacement
|
|
80
|
+
const filePath = keyPath(namespace, key);
|
|
175
81
|
const tmpPath = filePath + '.tmp';
|
|
176
82
|
await fs.writeFile(tmpPath, JSON.stringify(value, null, 2));
|
|
177
83
|
await fs.rename(tmpPath, filePath);
|
|
178
84
|
});
|
|
179
85
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
* @param key The key to delete
|
|
184
|
-
* @param scope Storage scope (default: 'photon')
|
|
185
|
-
* @returns true if the key existed and was deleted
|
|
186
|
-
*/
|
|
187
|
-
async delete(key, scope = 'photon') {
|
|
188
|
-
return this.withKeyLock(key, scope, async () => {
|
|
189
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
190
|
-
const filePath = keyPath(dir, key);
|
|
86
|
+
async delete(namespace, key) {
|
|
87
|
+
return this.withLock(namespace, key, async () => {
|
|
88
|
+
const filePath = keyPath(namespace, key);
|
|
191
89
|
try {
|
|
192
90
|
await fs.unlink(filePath);
|
|
193
91
|
return true;
|
|
@@ -199,28 +97,13 @@ export class MemoryProvider {
|
|
|
199
97
|
}
|
|
200
98
|
});
|
|
201
99
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
*
|
|
205
|
-
* @param key The key to check
|
|
206
|
-
* @param scope Storage scope (default: 'photon')
|
|
207
|
-
*/
|
|
208
|
-
async has(key, scope = 'photon') {
|
|
209
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
210
|
-
return pathExists(keyPath(dir, key));
|
|
100
|
+
async has(namespace, key) {
|
|
101
|
+
return pathExists(keyPath(namespace, key));
|
|
211
102
|
}
|
|
212
|
-
|
|
213
|
-
* List all keys in memory for a scope
|
|
214
|
-
*
|
|
215
|
-
* @param scope Storage scope (default: 'photon')
|
|
216
|
-
*/
|
|
217
|
-
async keys(scope = 'photon') {
|
|
218
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
103
|
+
async keys(namespace) {
|
|
219
104
|
try {
|
|
220
|
-
const files = await fs.readdir(
|
|
221
|
-
return files
|
|
222
|
-
.filter(f => f.endsWith('.json'))
|
|
223
|
-
.map(f => f.slice(0, -5));
|
|
105
|
+
const files = await fs.readdir(namespace);
|
|
106
|
+
return files.filter(f => f.endsWith('.json') && !f.endsWith('.tmp')).map(f => f.slice(0, -5));
|
|
224
107
|
}
|
|
225
108
|
catch (error) {
|
|
226
109
|
if (error.code === 'ENOENT')
|
|
@@ -228,17 +111,11 @@ export class MemoryProvider {
|
|
|
228
111
|
throw error;
|
|
229
112
|
}
|
|
230
113
|
}
|
|
231
|
-
|
|
232
|
-
* Clear all keys in a scope
|
|
233
|
-
*
|
|
234
|
-
* @param scope Storage scope (default: 'photon')
|
|
235
|
-
*/
|
|
236
|
-
async clear(scope = 'photon') {
|
|
237
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
114
|
+
async clear(namespace) {
|
|
238
115
|
try {
|
|
239
|
-
const files = await fs.readdir(
|
|
116
|
+
const files = await fs.readdir(namespace);
|
|
240
117
|
const jsonFiles = files.filter(f => f.endsWith('.json'));
|
|
241
|
-
await Promise.all(jsonFiles.map(file => fs.unlink(path.join(
|
|
118
|
+
await Promise.all(jsonFiles.map(file => fs.unlink(path.join(namespace, file))));
|
|
242
119
|
}
|
|
243
120
|
catch (error) {
|
|
244
121
|
if (error.code === 'ENOENT')
|
|
@@ -246,34 +123,9 @@ export class MemoryProvider {
|
|
|
246
123
|
throw error;
|
|
247
124
|
}
|
|
248
125
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
* @param scope Storage scope (default: 'photon')
|
|
253
|
-
*/
|
|
254
|
-
async getAll(scope = 'photon') {
|
|
255
|
-
const allKeys = await this.keys(scope);
|
|
256
|
-
const result = {};
|
|
257
|
-
for (const key of allKeys) {
|
|
258
|
-
const value = await this.get(key, scope);
|
|
259
|
-
if (value !== null) {
|
|
260
|
-
result[key] = value;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return result;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Atomic read-modify-write for a key.
|
|
267
|
-
* Serialized per key so concurrent updates don't corrupt data.
|
|
268
|
-
*
|
|
269
|
-
* @param key The key to update
|
|
270
|
-
* @param updater Function that receives current value and returns new value
|
|
271
|
-
* @param scope Storage scope (default: 'photon')
|
|
272
|
-
*/
|
|
273
|
-
async update(key, updater, scope = 'photon') {
|
|
274
|
-
return this.withKeyLock(key, scope, async () => {
|
|
275
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
276
|
-
const filePath = keyPath(dir, key);
|
|
126
|
+
async update(namespace, key, updater) {
|
|
127
|
+
return this.withLock(namespace, key, async () => {
|
|
128
|
+
const filePath = keyPath(namespace, key);
|
|
277
129
|
let current = null;
|
|
278
130
|
try {
|
|
279
131
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
@@ -284,8 +136,8 @@ export class MemoryProvider {
|
|
|
284
136
|
throw error;
|
|
285
137
|
}
|
|
286
138
|
const updated = updater(current);
|
|
287
|
-
if (!await pathExists(
|
|
288
|
-
await fs.mkdir(
|
|
139
|
+
if (!await pathExists(namespace)) {
|
|
140
|
+
await fs.mkdir(namespace, { recursive: true });
|
|
289
141
|
}
|
|
290
142
|
const tmpPath = filePath + '.tmp';
|
|
291
143
|
await fs.writeFile(tmpPath, JSON.stringify(updated, null, 2));
|
|
@@ -294,4 +146,126 @@ export class MemoryProvider {
|
|
|
294
146
|
});
|
|
295
147
|
}
|
|
296
148
|
}
|
|
149
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
150
|
+
// SCOPE RESOLUTION
|
|
151
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
152
|
+
function resolveDir(photonId, namespace, scope, sessionId, baseDir) {
|
|
153
|
+
switch (scope) {
|
|
154
|
+
case 'photon': {
|
|
155
|
+
const newDir = getPhotonMemoryDir(namespace, photonId, baseDir);
|
|
156
|
+
if (!fsSync.existsSync(newDir)) {
|
|
157
|
+
const legacyDir = getLegacyMemoryDir(photonId, baseDir);
|
|
158
|
+
if (fsSync.existsSync(legacyDir))
|
|
159
|
+
return legacyDir;
|
|
160
|
+
}
|
|
161
|
+
return newDir;
|
|
162
|
+
}
|
|
163
|
+
case 'session': {
|
|
164
|
+
if (!sessionId) {
|
|
165
|
+
throw new Error('Session ID required for session-scoped memory. Set via memory.sessionId.');
|
|
166
|
+
}
|
|
167
|
+
const newDir = getSessionMemoryDir(sessionId, namespace, photonId, baseDir);
|
|
168
|
+
if (!fsSync.existsSync(newDir)) {
|
|
169
|
+
const legacyDir = getLegacySessionMemoryDir(sessionId, photonId, baseDir);
|
|
170
|
+
if (fsSync.existsSync(legacyDir))
|
|
171
|
+
return legacyDir;
|
|
172
|
+
}
|
|
173
|
+
return newDir;
|
|
174
|
+
}
|
|
175
|
+
case 'global': {
|
|
176
|
+
const newDir = getGlobalMemoryDir(baseDir);
|
|
177
|
+
if (!fsSync.existsSync(newDir)) {
|
|
178
|
+
const legacyDir = getLegacyGlobalMemoryDir(baseDir);
|
|
179
|
+
if (fsSync.existsSync(legacyDir))
|
|
180
|
+
return legacyDir;
|
|
181
|
+
}
|
|
182
|
+
return newDir;
|
|
183
|
+
}
|
|
184
|
+
default:
|
|
185
|
+
throw new Error(`Unknown memory scope: ${scope}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
189
|
+
// MEMORY PROVIDER (public API — delegates to backend)
|
|
190
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
191
|
+
/** Default shared backend instance (file-based) */
|
|
192
|
+
let defaultBackend = new FileMemoryBackend();
|
|
193
|
+
/**
|
|
194
|
+
* Set the global default memory backend.
|
|
195
|
+
* Call before any photons are loaded to switch storage layer.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```typescript
|
|
199
|
+
* import { setDefaultMemoryBackend } from '@portel/photon-core';
|
|
200
|
+
* import { RedisMemoryBackend } from '@portel/photon-redis';
|
|
201
|
+
* setDefaultMemoryBackend(new RedisMemoryBackend({ url: 'redis://...' }));
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export function setDefaultMemoryBackend(backend) {
|
|
205
|
+
defaultBackend = backend;
|
|
206
|
+
}
|
|
207
|
+
export function getDefaultMemoryBackend() {
|
|
208
|
+
return defaultBackend;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Scoped Memory Provider
|
|
212
|
+
*
|
|
213
|
+
* The public API surface for `this.memory` on photon instances.
|
|
214
|
+
* Delegates all operations to the configured MemoryBackend.
|
|
215
|
+
*/
|
|
216
|
+
export class MemoryProvider {
|
|
217
|
+
_photonId;
|
|
218
|
+
_namespace;
|
|
219
|
+
_sessionId;
|
|
220
|
+
_baseDir;
|
|
221
|
+
_backend;
|
|
222
|
+
constructor(photonId, sessionId, namespace, baseDir, backend) {
|
|
223
|
+
this._photonId = photonId;
|
|
224
|
+
this._namespace = namespace || 'local';
|
|
225
|
+
this._sessionId = sessionId;
|
|
226
|
+
this._baseDir = baseDir;
|
|
227
|
+
this._backend = backend ?? defaultBackend;
|
|
228
|
+
}
|
|
229
|
+
get sessionId() {
|
|
230
|
+
return this._sessionId;
|
|
231
|
+
}
|
|
232
|
+
set sessionId(id) {
|
|
233
|
+
this._sessionId = id;
|
|
234
|
+
}
|
|
235
|
+
/** Resolve the storage namespace (directory for file backend, prefix for Redis, etc.) */
|
|
236
|
+
ns(scope) {
|
|
237
|
+
return resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
238
|
+
}
|
|
239
|
+
async get(key, scope = 'photon') {
|
|
240
|
+
return this._backend.get(this.ns(scope), key);
|
|
241
|
+
}
|
|
242
|
+
async set(key, value, scope = 'photon') {
|
|
243
|
+
return this._backend.set(this.ns(scope), key, value);
|
|
244
|
+
}
|
|
245
|
+
async delete(key, scope = 'photon') {
|
|
246
|
+
return this._backend.delete(this.ns(scope), key);
|
|
247
|
+
}
|
|
248
|
+
async has(key, scope = 'photon') {
|
|
249
|
+
return this._backend.has(this.ns(scope), key);
|
|
250
|
+
}
|
|
251
|
+
async keys(scope = 'photon') {
|
|
252
|
+
return this._backend.keys(this.ns(scope));
|
|
253
|
+
}
|
|
254
|
+
async clear(scope = 'photon') {
|
|
255
|
+
return this._backend.clear(this.ns(scope));
|
|
256
|
+
}
|
|
257
|
+
async getAll(scope = 'photon') {
|
|
258
|
+
const allKeys = await this.keys(scope);
|
|
259
|
+
const result = {};
|
|
260
|
+
for (const key of allKeys) {
|
|
261
|
+
const value = await this.get(key, scope);
|
|
262
|
+
if (value !== null)
|
|
263
|
+
result[key] = value;
|
|
264
|
+
}
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
267
|
+
async update(key, updater, scope = 'photon') {
|
|
268
|
+
return this._backend.update(this.ns(scope), key, updater);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
297
271
|
//# sourceMappingURL=memory.js.map
|
package/dist/memory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,MAAM,MAAM,IAAI,CAAC;AAC7B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AA8BzB,mFAAmF;AACnF,yBAAyB;AACzB,mFAAmF;AAEnF,SAAS,OAAO,CAAC,GAAW,EAAE,GAAW;IACvC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,CAAS;IACjC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,iBAAiB;IACpB,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE1C,KAAK,CAAC,QAAQ,CAAI,SAAiB,EAAE,GAAW,EAAE,EAAoB;QAC5E,MAAM,OAAO,GAAG,GAAG,SAAS,IAAI,GAAG,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3D,IAAI,OAAoB,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC;YACX,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;YACV,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;gBACtC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB,EAAE,GAAW;QACtC,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACzC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACrD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;oBAAE,OAAO,IAAI,CAAC;gBACzC,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB,EAAE,GAAW,EAAE,KAAU;QAClD,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE;YAC9C,IAAI,CAAC,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACjD,CAAC;YACD,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;YAClC,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,GAAW;QACzC,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACzC,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC1B,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;oBAAE,OAAO,KAAK,CAAC;gBAC1C,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB,EAAE,GAAW;QACtC,OAAO,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,SAAiB;QAC1B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAChG,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,EAAE,CAAC;YACvC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,SAAiB;QAC3B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YACzD,MAAM,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAClF,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO;YACpC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,GAAW,EAAE,OAAqC;QAChF,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAEzC,IAAI,OAAO,GAAQ,IAAI,CAAC;YACxB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACrD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;oBAAE,MAAM,KAAK,CAAC;YAC3C,CAAC;YAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YAEjC,IAAI,CAAC,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACjD,CAAC;YACD,MAAM,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;YAClC,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC9D,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACnC,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,mFAAmF;AACnF,mBAAmB;AACnB,mFAAmF;AAEnF,SAAS,UAAU,CACjB,QAAgB,EAChB,SAAiB,EACjB,KAAkB,EAClB,SAAkB,EAClB,OAAgB;IAEhB,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;YAChE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,MAAM,SAAS,GAAG,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACxD,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC;oBAAE,OAAO,SAAS,CAAC;YACrD,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;YAC9F,CAAC;YACD,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC5E,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,MAAM,SAAS,GAAG,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAC1E,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC;oBAAE,OAAO,SAAS,CAAC;YACrD,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,MAAM,SAAS,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC;gBACpD,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC;oBAAE,OAAO,SAAS,CAAC;YACrD,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD;YACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,sDAAsD;AACtD,mFAAmF;AAEnF,mDAAmD;AACnD,IAAI,cAAc,GAAkB,IAAI,iBAAiB,EAAE,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAsB;IAC5D,cAAc,GAAG,OAAO,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACjB,SAAS,CAAS;IAClB,UAAU,CAAS;IACnB,UAAU,CAAU;IACpB,QAAQ,CAAU;IAClB,QAAQ,CAAgB;IAEhC,YACE,QAAgB,EAChB,SAAkB,EAClB,SAAkB,EAClB,OAAgB,EAChB,OAAuB;QAEvB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,SAAS,IAAI,OAAO,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,OAAO,IAAI,cAAc,CAAC;IAC5C,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,IAAI,SAAS,CAAC,EAAsB;QAClC,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;IACvB,CAAC;IAED,yFAAyF;IACjF,EAAE,CAAC,KAAkB;QAC3B,OAAO,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5F,CAAC;IAED,KAAK,CAAC,GAAG,CAAU,GAAW,EAAE,QAAqB,QAAQ;QAC3D,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,GAAG,CAAU,GAAW,EAAE,KAAQ,EAAE,QAAqB,QAAQ;QACrE,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,QAAqB,QAAQ;QACrD,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,QAAqB,QAAQ;QAClD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAqB,QAAQ;QACtC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,QAAqB,QAAQ;QACvC,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,MAAM,CAAU,QAAqB,QAAQ;QACjD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAI,GAAG,EAAE,KAAK,CAAC,CAAC;YAC5C,IAAI,KAAK,KAAK,IAAI;gBAAE,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC1C,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,MAAM,CACV,GAAW,EACX,OAAiC,EACjC,QAAqB,QAAQ;QAE7B,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portel/photon-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.0",
|
|
4
4
|
"description": "Core library for parsing, loading, and managing .photon.ts files - runtime-agnostic foundation for building custom Photon runtimes",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
package/src/index.ts
CHANGED
|
@@ -443,8 +443,13 @@ export {
|
|
|
443
443
|
|
|
444
444
|
// ===== SCOPED MEMORY =====
|
|
445
445
|
// Framework-level key-value storage (this.memory on Photon base class)
|
|
446
|
+
// MemoryBackend is the pluggable interface; FileMemoryBackend is the default.
|
|
446
447
|
export {
|
|
447
448
|
MemoryProvider,
|
|
449
|
+
FileMemoryBackend,
|
|
450
|
+
setDefaultMemoryBackend,
|
|
451
|
+
getDefaultMemoryBackend,
|
|
452
|
+
type MemoryBackend,
|
|
448
453
|
type MemoryScope,
|
|
449
454
|
} from './memory.js';
|
|
450
455
|
|
package/src/memory.ts
CHANGED
|
@@ -4,24 +4,16 @@
|
|
|
4
4
|
* Framework-level key-value storage for photons that eliminates
|
|
5
5
|
* boilerplate file I/O. Available as `this.memory` on Photon.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* | photon | Private to this photon (default) | .data/{namespace}/{photonName}/memory/ |
|
|
11
|
-
* | session | Per-user session (Beam sessions) | .data/_sessions/{sessionId}/{ns}/{photon}/ |
|
|
12
|
-
* | global | Shared across all photons | .data/_global/ |
|
|
7
|
+
* Architecture: MemoryProvider delegates to a pluggable MemoryBackend.
|
|
8
|
+
* The default backend is FileMemoryBackend (JSON files on disk).
|
|
9
|
+
* Enterprise deployments can swap in Redis, Postgres, or SQLite.
|
|
13
10
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* await this.memory.set('items', items);
|
|
21
|
-
* return items;
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
11
|
+
* Three scopes:
|
|
12
|
+
* | Scope | Meaning |
|
|
13
|
+
* |----------|----------------------------------|
|
|
14
|
+
* | photon | Private to this photon (default) |
|
|
15
|
+
* | session | Per-user session (Beam sessions) |
|
|
16
|
+
* | global | Shared across all photons |
|
|
25
17
|
*/
|
|
26
18
|
|
|
27
19
|
import * as fs from 'fs/promises';
|
|
@@ -39,10 +31,166 @@ import {
|
|
|
39
31
|
|
|
40
32
|
export type MemoryScope = 'photon' | 'session' | 'global';
|
|
41
33
|
|
|
34
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
35
|
+
// BACKEND INTERFACE
|
|
36
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pluggable storage backend for MemoryProvider.
|
|
40
|
+
*
|
|
41
|
+
* Implementations handle the actual persistence. All methods receive
|
|
42
|
+
* a resolved namespace (scope + photonId + sessionId already baked in)
|
|
43
|
+
* so the backend doesn't need to know about scoping rules.
|
|
44
|
+
*/
|
|
45
|
+
export interface MemoryBackend {
|
|
46
|
+
get(namespace: string, key: string): Promise<any | null>;
|
|
47
|
+
set(namespace: string, key: string, value: any): Promise<void>;
|
|
48
|
+
delete(namespace: string, key: string): Promise<boolean>;
|
|
49
|
+
has(namespace: string, key: string): Promise<boolean>;
|
|
50
|
+
keys(namespace: string): Promise<string[]>;
|
|
51
|
+
clear(namespace: string): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Atomic read-modify-write. Backends with native transactions (Redis WATCH,
|
|
54
|
+
* Postgres FOR UPDATE) should use them here. The default file backend
|
|
55
|
+
* uses a per-key promise chain.
|
|
56
|
+
*/
|
|
57
|
+
update(namespace: string, key: string, updater: (current: any | null) => any): Promise<any>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
61
|
+
// FILE BACKEND (default)
|
|
62
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
63
|
+
|
|
64
|
+
function keyPath(dir: string, key: string): string {
|
|
65
|
+
const safeKey = key.replace(/[^a-zA-Z0-9_.-]/g, '_');
|
|
66
|
+
return path.join(dir, `${safeKey}.json`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function pathExists(p: string): Promise<boolean> {
|
|
70
|
+
try {
|
|
71
|
+
await fs.access(p);
|
|
72
|
+
return true;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
42
78
|
/**
|
|
43
|
-
*
|
|
44
|
-
* Uses
|
|
79
|
+
* File-based memory backend. Each key is a JSON file on disk.
|
|
80
|
+
* Uses per-key promise chains and temp+rename for safe concurrent access.
|
|
45
81
|
*/
|
|
82
|
+
export class FileMemoryBackend implements MemoryBackend {
|
|
83
|
+
private _locks = new Map<string, Promise<void>>();
|
|
84
|
+
|
|
85
|
+
private async withLock<T>(namespace: string, key: string, fn: () => Promise<T>): Promise<T> {
|
|
86
|
+
const lockKey = `${namespace}:${key}`;
|
|
87
|
+
const prev = this._locks.get(lockKey) ?? Promise.resolve();
|
|
88
|
+
let resolve!: () => void;
|
|
89
|
+
const next = new Promise<void>(r => { resolve = r; });
|
|
90
|
+
this._locks.set(lockKey, next);
|
|
91
|
+
try {
|
|
92
|
+
await prev;
|
|
93
|
+
return await fn();
|
|
94
|
+
} finally {
|
|
95
|
+
resolve();
|
|
96
|
+
if (this._locks.get(lockKey) === next) {
|
|
97
|
+
this._locks.delete(lockKey);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async get(namespace: string, key: string): Promise<any | null> {
|
|
103
|
+
return this.withLock(namespace, key, async () => {
|
|
104
|
+
const filePath = keyPath(namespace, key);
|
|
105
|
+
try {
|
|
106
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
107
|
+
return JSON.parse(content);
|
|
108
|
+
} catch (error: any) {
|
|
109
|
+
if (error.code === 'ENOENT') return null;
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async set(namespace: string, key: string, value: any): Promise<void> {
|
|
116
|
+
return this.withLock(namespace, key, async () => {
|
|
117
|
+
if (!await pathExists(namespace)) {
|
|
118
|
+
await fs.mkdir(namespace, { recursive: true });
|
|
119
|
+
}
|
|
120
|
+
const filePath = keyPath(namespace, key);
|
|
121
|
+
const tmpPath = filePath + '.tmp';
|
|
122
|
+
await fs.writeFile(tmpPath, JSON.stringify(value, null, 2));
|
|
123
|
+
await fs.rename(tmpPath, filePath);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async delete(namespace: string, key: string): Promise<boolean> {
|
|
128
|
+
return this.withLock(namespace, key, async () => {
|
|
129
|
+
const filePath = keyPath(namespace, key);
|
|
130
|
+
try {
|
|
131
|
+
await fs.unlink(filePath);
|
|
132
|
+
return true;
|
|
133
|
+
} catch (error: any) {
|
|
134
|
+
if (error.code === 'ENOENT') return false;
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async has(namespace: string, key: string): Promise<boolean> {
|
|
141
|
+
return pathExists(keyPath(namespace, key));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async keys(namespace: string): Promise<string[]> {
|
|
145
|
+
try {
|
|
146
|
+
const files = await fs.readdir(namespace);
|
|
147
|
+
return files.filter(f => f.endsWith('.json') && !f.endsWith('.tmp')).map(f => f.slice(0, -5));
|
|
148
|
+
} catch (error: any) {
|
|
149
|
+
if (error.code === 'ENOENT') return [];
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async clear(namespace: string): Promise<void> {
|
|
155
|
+
try {
|
|
156
|
+
const files = await fs.readdir(namespace);
|
|
157
|
+
const jsonFiles = files.filter(f => f.endsWith('.json'));
|
|
158
|
+
await Promise.all(jsonFiles.map(file => fs.unlink(path.join(namespace, file))));
|
|
159
|
+
} catch (error: any) {
|
|
160
|
+
if (error.code === 'ENOENT') return;
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async update(namespace: string, key: string, updater: (current: any | null) => any): Promise<any> {
|
|
166
|
+
return this.withLock(namespace, key, async () => {
|
|
167
|
+
const filePath = keyPath(namespace, key);
|
|
168
|
+
|
|
169
|
+
let current: any = null;
|
|
170
|
+
try {
|
|
171
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
172
|
+
current = JSON.parse(content);
|
|
173
|
+
} catch (error: any) {
|
|
174
|
+
if (error.code !== 'ENOENT') throw error;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const updated = updater(current);
|
|
178
|
+
|
|
179
|
+
if (!await pathExists(namespace)) {
|
|
180
|
+
await fs.mkdir(namespace, { recursive: true });
|
|
181
|
+
}
|
|
182
|
+
const tmpPath = filePath + '.tmp';
|
|
183
|
+
await fs.writeFile(tmpPath, JSON.stringify(updated, null, 2));
|
|
184
|
+
await fs.rename(tmpPath, filePath);
|
|
185
|
+
return updated;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
191
|
+
// SCOPE RESOLUTION
|
|
192
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
193
|
+
|
|
46
194
|
function resolveDir(
|
|
47
195
|
photonId: string,
|
|
48
196
|
namespace: string,
|
|
@@ -53,7 +201,6 @@ function resolveDir(
|
|
|
53
201
|
switch (scope) {
|
|
54
202
|
case 'photon': {
|
|
55
203
|
const newDir = getPhotonMemoryDir(namespace, photonId, baseDir);
|
|
56
|
-
// Fallback: check legacy path if new path has no data yet
|
|
57
204
|
if (!fsSync.existsSync(newDir)) {
|
|
58
205
|
const legacyDir = getLegacyMemoryDir(photonId, baseDir);
|
|
59
206
|
if (fsSync.existsSync(legacyDir)) return legacyDir;
|
|
@@ -84,70 +231,59 @@ function resolveDir(
|
|
|
84
231
|
}
|
|
85
232
|
}
|
|
86
233
|
|
|
234
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
235
|
+
// MEMORY PROVIDER (public API — delegates to backend)
|
|
236
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
237
|
+
|
|
238
|
+
/** Default shared backend instance (file-based) */
|
|
239
|
+
let defaultBackend: MemoryBackend = new FileMemoryBackend();
|
|
240
|
+
|
|
87
241
|
/**
|
|
88
|
-
*
|
|
242
|
+
* Set the global default memory backend.
|
|
243
|
+
* Call before any photons are loaded to switch storage layer.
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* import { setDefaultMemoryBackend } from '@portel/photon-core';
|
|
248
|
+
* import { RedisMemoryBackend } from '@portel/photon-redis';
|
|
249
|
+
* setDefaultMemoryBackend(new RedisMemoryBackend({ url: 'redis://...' }));
|
|
250
|
+
* ```
|
|
89
251
|
*/
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
return path.join(dir, `${safeKey}.json`);
|
|
252
|
+
export function setDefaultMemoryBackend(backend: MemoryBackend): void {
|
|
253
|
+
defaultBackend = backend;
|
|
93
254
|
}
|
|
94
255
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
*/
|
|
98
|
-
async function pathExists(p: string): Promise<boolean> {
|
|
99
|
-
try {
|
|
100
|
-
await fs.access(p);
|
|
101
|
-
return true;
|
|
102
|
-
} catch {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
256
|
+
export function getDefaultMemoryBackend(): MemoryBackend {
|
|
257
|
+
return defaultBackend;
|
|
105
258
|
}
|
|
106
259
|
|
|
107
260
|
/**
|
|
108
261
|
* Scoped Memory Provider
|
|
109
262
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
263
|
+
* The public API surface for `this.memory` on photon instances.
|
|
264
|
+
* Delegates all operations to the configured MemoryBackend.
|
|
112
265
|
*/
|
|
113
266
|
export class MemoryProvider {
|
|
114
267
|
private _photonId: string;
|
|
115
268
|
private _namespace: string;
|
|
116
269
|
private _sessionId?: string;
|
|
117
270
|
private _baseDir?: string;
|
|
118
|
-
private
|
|
271
|
+
private _backend: MemoryBackend;
|
|
119
272
|
|
|
120
|
-
constructor(
|
|
273
|
+
constructor(
|
|
274
|
+
photonId: string,
|
|
275
|
+
sessionId?: string,
|
|
276
|
+
namespace?: string,
|
|
277
|
+
baseDir?: string,
|
|
278
|
+
backend?: MemoryBackend
|
|
279
|
+
) {
|
|
121
280
|
this._photonId = photonId;
|
|
122
281
|
this._namespace = namespace || 'local';
|
|
123
282
|
this._sessionId = sessionId;
|
|
124
283
|
this._baseDir = baseDir;
|
|
284
|
+
this._backend = backend ?? defaultBackend;
|
|
125
285
|
}
|
|
126
286
|
|
|
127
|
-
/**
|
|
128
|
-
* Serialize file operations per key to prevent concurrent write corruption.
|
|
129
|
-
* Reads also go through the lock to avoid reading a partially-written file.
|
|
130
|
-
*/
|
|
131
|
-
private async withKeyLock<T>(key: string, scope: MemoryScope, fn: () => Promise<T>): Promise<T> {
|
|
132
|
-
const lockKey = `${scope}:${key}`;
|
|
133
|
-
const prev = this._locks.get(lockKey) ?? Promise.resolve();
|
|
134
|
-
let resolve!: () => void;
|
|
135
|
-
const next = new Promise<void>(r => { resolve = r; });
|
|
136
|
-
this._locks.set(lockKey, next);
|
|
137
|
-
try {
|
|
138
|
-
await prev;
|
|
139
|
-
return await fn();
|
|
140
|
-
} finally {
|
|
141
|
-
resolve();
|
|
142
|
-
if (this._locks.get(lockKey) === next) {
|
|
143
|
-
this._locks.delete(lockKey);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Current session ID (can be updated by the runtime)
|
|
150
|
-
*/
|
|
151
287
|
get sessionId(): string | undefined {
|
|
152
288
|
return this._sessionId;
|
|
153
289
|
}
|
|
@@ -156,174 +292,50 @@ export class MemoryProvider {
|
|
|
156
292
|
this._sessionId = id;
|
|
157
293
|
}
|
|
158
294
|
|
|
159
|
-
/**
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
* @param scope Storage scope (default: 'photon')
|
|
164
|
-
* @returns The stored value, or null if not found
|
|
165
|
-
*/
|
|
166
|
-
async get<T = any>(key: string, scope: MemoryScope = 'photon'): Promise<T | null> {
|
|
167
|
-
return this.withKeyLock(key, scope, async () => {
|
|
168
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
169
|
-
const filePath = keyPath(dir, key);
|
|
295
|
+
/** Resolve the storage namespace (directory for file backend, prefix for Redis, etc.) */
|
|
296
|
+
private ns(scope: MemoryScope): string {
|
|
297
|
+
return resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
298
|
+
}
|
|
170
299
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return JSON.parse(content) as T;
|
|
174
|
-
} catch (error: any) {
|
|
175
|
-
if (error.code === 'ENOENT') return null;
|
|
176
|
-
throw error;
|
|
177
|
-
}
|
|
178
|
-
});
|
|
300
|
+
async get<T = any>(key: string, scope: MemoryScope = 'photon'): Promise<T | null> {
|
|
301
|
+
return this._backend.get(this.ns(scope), key);
|
|
179
302
|
}
|
|
180
303
|
|
|
181
|
-
/**
|
|
182
|
-
* Set a value in memory
|
|
183
|
-
*
|
|
184
|
-
* @param key The key to store
|
|
185
|
-
* @param value The value (must be JSON-serializable)
|
|
186
|
-
* @param scope Storage scope (default: 'photon')
|
|
187
|
-
*/
|
|
188
304
|
async set<T = any>(key: string, value: T, scope: MemoryScope = 'photon'): Promise<void> {
|
|
189
|
-
return this.
|
|
190
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
191
|
-
|
|
192
|
-
if (!await pathExists(dir)) {
|
|
193
|
-
await fs.mkdir(dir, { recursive: true });
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const filePath = keyPath(dir, key);
|
|
197
|
-
// Write to temp file then rename for atomic replacement
|
|
198
|
-
const tmpPath = filePath + '.tmp';
|
|
199
|
-
await fs.writeFile(tmpPath, JSON.stringify(value, null, 2));
|
|
200
|
-
await fs.rename(tmpPath, filePath);
|
|
201
|
-
});
|
|
305
|
+
return this._backend.set(this.ns(scope), key, value);
|
|
202
306
|
}
|
|
203
307
|
|
|
204
|
-
/**
|
|
205
|
-
* Delete a key from memory
|
|
206
|
-
*
|
|
207
|
-
* @param key The key to delete
|
|
208
|
-
* @param scope Storage scope (default: 'photon')
|
|
209
|
-
* @returns true if the key existed and was deleted
|
|
210
|
-
*/
|
|
211
308
|
async delete(key: string, scope: MemoryScope = 'photon'): Promise<boolean> {
|
|
212
|
-
return this.
|
|
213
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
214
|
-
const filePath = keyPath(dir, key);
|
|
215
|
-
|
|
216
|
-
try {
|
|
217
|
-
await fs.unlink(filePath);
|
|
218
|
-
return true;
|
|
219
|
-
} catch (error: any) {
|
|
220
|
-
if (error.code === 'ENOENT') return false;
|
|
221
|
-
throw error;
|
|
222
|
-
}
|
|
223
|
-
});
|
|
309
|
+
return this._backend.delete(this.ns(scope), key);
|
|
224
310
|
}
|
|
225
311
|
|
|
226
|
-
/**
|
|
227
|
-
* Check if a key exists in memory
|
|
228
|
-
*
|
|
229
|
-
* @param key The key to check
|
|
230
|
-
* @param scope Storage scope (default: 'photon')
|
|
231
|
-
*/
|
|
232
312
|
async has(key: string, scope: MemoryScope = 'photon'): Promise<boolean> {
|
|
233
|
-
|
|
234
|
-
return pathExists(keyPath(dir, key));
|
|
313
|
+
return this._backend.has(this.ns(scope), key);
|
|
235
314
|
}
|
|
236
315
|
|
|
237
|
-
/**
|
|
238
|
-
* List all keys in memory for a scope
|
|
239
|
-
*
|
|
240
|
-
* @param scope Storage scope (default: 'photon')
|
|
241
|
-
*/
|
|
242
316
|
async keys(scope: MemoryScope = 'photon'): Promise<string[]> {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
const files = await fs.readdir(dir);
|
|
247
|
-
return files
|
|
248
|
-
.filter(f => f.endsWith('.json'))
|
|
249
|
-
.map(f => f.slice(0, -5));
|
|
250
|
-
} catch (error: any) {
|
|
251
|
-
if (error.code === 'ENOENT') return [];
|
|
252
|
-
throw error;
|
|
253
|
-
}
|
|
317
|
+
return this._backend.keys(this.ns(scope));
|
|
254
318
|
}
|
|
255
319
|
|
|
256
|
-
/**
|
|
257
|
-
* Clear all keys in a scope
|
|
258
|
-
*
|
|
259
|
-
* @param scope Storage scope (default: 'photon')
|
|
260
|
-
*/
|
|
261
320
|
async clear(scope: MemoryScope = 'photon'): Promise<void> {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
try {
|
|
265
|
-
const files = await fs.readdir(dir);
|
|
266
|
-
const jsonFiles = files.filter(f => f.endsWith('.json'));
|
|
267
|
-
await Promise.all(jsonFiles.map(file => fs.unlink(path.join(dir, file))));
|
|
268
|
-
} catch (error: any) {
|
|
269
|
-
if (error.code === 'ENOENT') return;
|
|
270
|
-
throw error;
|
|
271
|
-
}
|
|
321
|
+
return this._backend.clear(this.ns(scope));
|
|
272
322
|
}
|
|
273
323
|
|
|
274
|
-
/**
|
|
275
|
-
* Get all key-value pairs in a scope
|
|
276
|
-
*
|
|
277
|
-
* @param scope Storage scope (default: 'photon')
|
|
278
|
-
*/
|
|
279
324
|
async getAll<T = any>(scope: MemoryScope = 'photon'): Promise<Record<string, T>> {
|
|
280
325
|
const allKeys = await this.keys(scope);
|
|
281
326
|
const result: Record<string, T> = {};
|
|
282
|
-
|
|
283
327
|
for (const key of allKeys) {
|
|
284
328
|
const value = await this.get<T>(key, scope);
|
|
285
|
-
if (value !== null)
|
|
286
|
-
result[key] = value;
|
|
287
|
-
}
|
|
329
|
+
if (value !== null) result[key] = value;
|
|
288
330
|
}
|
|
289
|
-
|
|
290
331
|
return result;
|
|
291
332
|
}
|
|
292
333
|
|
|
293
|
-
/**
|
|
294
|
-
* Atomic read-modify-write for a key.
|
|
295
|
-
* Serialized per key so concurrent updates don't corrupt data.
|
|
296
|
-
*
|
|
297
|
-
* @param key The key to update
|
|
298
|
-
* @param updater Function that receives current value and returns new value
|
|
299
|
-
* @param scope Storage scope (default: 'photon')
|
|
300
|
-
*/
|
|
301
334
|
async update<T = any>(
|
|
302
335
|
key: string,
|
|
303
336
|
updater: (current: T | null) => T,
|
|
304
337
|
scope: MemoryScope = 'photon'
|
|
305
338
|
): Promise<T> {
|
|
306
|
-
return this.
|
|
307
|
-
const dir = resolveDir(this._photonId, this._namespace, scope, this._sessionId, this._baseDir);
|
|
308
|
-
const filePath = keyPath(dir, key);
|
|
309
|
-
|
|
310
|
-
let current: T | null = null;
|
|
311
|
-
try {
|
|
312
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
313
|
-
current = JSON.parse(content) as T;
|
|
314
|
-
} catch (error: any) {
|
|
315
|
-
if (error.code !== 'ENOENT') throw error;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const updated = updater(current);
|
|
319
|
-
|
|
320
|
-
if (!await pathExists(dir)) {
|
|
321
|
-
await fs.mkdir(dir, { recursive: true });
|
|
322
|
-
}
|
|
323
|
-
const tmpPath = filePath + '.tmp';
|
|
324
|
-
await fs.writeFile(tmpPath, JSON.stringify(updated, null, 2));
|
|
325
|
-
await fs.rename(tmpPath, filePath);
|
|
326
|
-
return updated;
|
|
327
|
-
});
|
|
339
|
+
return this._backend.update(this.ns(scope), key, updater);
|
|
328
340
|
}
|
|
329
341
|
}
|