@mindees/data 0.4.0 → 0.5.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 +3 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/persist.d.ts +37 -13
- package/dist/persist.d.ts.map +1 -1
- package/dist/persist.js +82 -1
- package/dist/persist.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { DataError, DataErrorCode } from "./errors.js";
|
|
|
3
3
|
import { Clock, ClockOptions, Hlc, compareHlc, createClock, decodeHlc, encodeHlc } from "./hlc.js";
|
|
4
4
|
import { LwwMap, LwwRegister, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, mergeLwwMap, mergeRegister } from "./lww.js";
|
|
5
5
|
import { OrSet, emptyOrSet, mergeOrSet, orAdd, orHas, orRemove, orValues } from "./or-set.js";
|
|
6
|
-
import { Persistence, createMemoryPersistence } from "./persist.js";
|
|
7
6
|
import { Cursor, MutationLog, Op, SyncEngine, SyncEngineOptions, SyncSnapshot, SyncTransport, createMemoryHub, createMutationLog, createSyncEngine } from "./sync.js";
|
|
7
|
+
import { Persistence, PersistentEngineOptions, WebStorageLike, createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine } from "./persist.js";
|
|
8
8
|
import { VersionVector, vvDominates, vvEquals, vvGet, vvMerge, vvObserve } from "./version-vector.js";
|
|
9
9
|
import { Maturity, NotImplementedError, PackageInfo, notImplemented } from "@mindees/core";
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ import { Maturity, NotImplementedError, PackageInfo, notImplemented } from "@min
|
|
|
12
12
|
/** The npm package name. */
|
|
13
13
|
declare const name = "@mindees/data";
|
|
14
14
|
/** The package version. All `@mindees/*` packages share one locked version line. */
|
|
15
|
-
declare const VERSION = "0.
|
|
15
|
+
declare const VERSION = "0.5.0";
|
|
16
16
|
/** Current maturity of this package. See the repository `STATUS.md`. */
|
|
17
17
|
declare const maturity: Maturity;
|
|
18
18
|
/**
|
|
@@ -22,5 +22,5 @@ declare const maturity: Maturity;
|
|
|
22
22
|
*/
|
|
23
23
|
declare const info: PackageInfo;
|
|
24
24
|
//#endregion
|
|
25
|
-
export { type Clock, type ClockOptions, type Collection, type CollectionOptions, type Cursor, DataError, type DataErrorCode, type Hlc, type Id, type LwwMap, type LwwRegister, type Maturity, type MutationLog, NotImplementedError, type Op, type OptimisticChange, type OrSet, type PackageInfo, type Persistence, type SyncEngine, type SyncEngineOptions, type SyncSnapshot, type SyncTransport, VERSION, type VersionVector, compareHlc, createClock, createCollection, createMemoryHub, createMemoryPersistence, createMutationLog, createSyncEngine, decodeHlc, emptyOrSet, encodeHlc, info, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, maturity, mergeLwwMap, mergeOrSet, mergeRegister, name, notImplemented, orAdd, orHas, orRemove, orValues, vvDominates, vvEquals, vvGet, vvMerge, vvObserve };
|
|
25
|
+
export { type Clock, type ClockOptions, type Collection, type CollectionOptions, type Cursor, DataError, type DataErrorCode, type Hlc, type Id, type LwwMap, type LwwRegister, type Maturity, type MutationLog, NotImplementedError, type Op, type OptimisticChange, type OrSet, type PackageInfo, type Persistence, type PersistentEngineOptions, type SyncEngine, type SyncEngineOptions, type SyncSnapshot, type SyncTransport, VERSION, type VersionVector, type WebStorageLike, compareHlc, createClock, createCollection, createMemoryHub, createMemoryPersistence, createMutationLog, createPersistentEngine, createSyncEngine, createWebStoragePersistence, decodeHlc, emptyOrSet, encodeHlc, info, loadSnapshot, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, maturity, mergeLwwMap, mergeOrSet, mergeRegister, name, notImplemented, orAdd, orHas, orRemove, orValues, persistEngine, vvDominates, vvEquals, vvGet, vvMerge, vvObserve };
|
|
26
26
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -3,15 +3,15 @@ import { createCollection } from "./collection.js";
|
|
|
3
3
|
import { compareHlc, createClock, decodeHlc, encodeHlc } from "./hlc.js";
|
|
4
4
|
import { lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, mergeLwwMap, mergeRegister } from "./lww.js";
|
|
5
5
|
import { emptyOrSet, mergeOrSet, orAdd, orHas, orRemove, orValues } from "./or-set.js";
|
|
6
|
-
import { createMemoryPersistence } from "./persist.js";
|
|
7
6
|
import { createMemoryHub, createMutationLog, createSyncEngine } from "./sync.js";
|
|
7
|
+
import { createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine } from "./persist.js";
|
|
8
8
|
import { vvDominates, vvEquals, vvGet, vvMerge, vvObserve } from "./version-vector.js";
|
|
9
9
|
import { NotImplementedError, notImplemented } from "@mindees/core";
|
|
10
10
|
//#region src/index.ts
|
|
11
11
|
/** The npm package name. */
|
|
12
12
|
const name = "@mindees/data";
|
|
13
13
|
/** The package version. All `@mindees/*` packages share one locked version line. */
|
|
14
|
-
const VERSION = "0.
|
|
14
|
+
const VERSION = "0.5.0";
|
|
15
15
|
/** Current maturity of this package. See the repository `STATUS.md`. */
|
|
16
16
|
const maturity = "experimental";
|
|
17
17
|
/**
|
|
@@ -25,6 +25,6 @@ const info = Object.freeze({
|
|
|
25
25
|
maturity
|
|
26
26
|
});
|
|
27
27
|
//#endregion
|
|
28
|
-
export { DataError, NotImplementedError, VERSION, compareHlc, createClock, createCollection, createMemoryHub, createMemoryPersistence, createMutationLog, createSyncEngine, decodeHlc, emptyOrSet, encodeHlc, info, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, maturity, mergeLwwMap, mergeOrSet, mergeRegister, name, notImplemented, orAdd, orHas, orRemove, orValues, vvDominates, vvEquals, vvGet, vvMerge, vvObserve };
|
|
28
|
+
export { DataError, NotImplementedError, VERSION, compareHlc, createClock, createCollection, createMemoryHub, createMemoryPersistence, createMutationLog, createPersistentEngine, createSyncEngine, createWebStoragePersistence, decodeHlc, emptyOrSet, encodeHlc, info, loadSnapshot, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, maturity, mergeLwwMap, mergeOrSet, mergeRegister, name, notImplemented, orAdd, orHas, orRemove, orValues, persistEngine, vvDominates, vvEquals, vvGet, vvMerge, vvObserve };
|
|
29
29
|
|
|
30
30
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@mindees/data` (Continuum) — local-first reactive store + sync.\n *\n * Phase 10 ships the **reactive document store**: {@link createCollection}, a\n * signals-native, in-memory collection with fine-grained reactive reads\n * (`get`/`has`/`all`/`where`/`size`), atomic mutations (`insert`/`upsert`/`update`/\n * `delete`/`clear`/`tx`), and {@link Collection.optimistic optimistic} changes that can\n * be rolled back. Built on `@mindees/core` signals only. Hybrid-logical-clock causality,\n * CRDT conflict resolution, the local-first sync engine, a reference sync server on the\n * `@mindees/data/server` subpath, and a persistence contract/export/restore path build\n * on this. Native durable adapters, production sync hardening, and CRDT-library/rich-text\n * interop remain research tracks.\n *\n * @module\n */\n\nimport type { Maturity, PackageInfo } from '@mindees/core'\nimport { NotImplementedError, notImplemented } from '@mindees/core'\n\n/** The npm package name. */\nexport const name = '@mindees/data'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@mindees/data` (Continuum) — local-first reactive store + sync.\n *\n * Phase 10 ships the **reactive document store**: {@link createCollection}, a\n * signals-native, in-memory collection with fine-grained reactive reads\n * (`get`/`has`/`all`/`where`/`size`), atomic mutations (`insert`/`upsert`/`update`/\n * `delete`/`clear`/`tx`), and {@link Collection.optimistic optimistic} changes that can\n * be rolled back. Built on `@mindees/core` signals only. Hybrid-logical-clock causality,\n * CRDT conflict resolution, the local-first sync engine, a reference sync server on the\n * `@mindees/data/server` subpath, and a persistence contract/export/restore path build\n * on this. Native durable adapters, production sync hardening, and CRDT-library/rich-text\n * interop remain research tracks.\n *\n * @module\n */\n\nimport type { Maturity, PackageInfo } from '@mindees/core'\nimport { NotImplementedError, notImplemented } from '@mindees/core'\n\n/** The npm package name. */\nexport const name = '@mindees/data'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.5.0'\n\n/** Current maturity of this package. See the repository `STATUS.md`. */\nexport const maturity: Maturity = 'experimental'\n\n/**\n * Static identity + maturity metadata for this package. Frozen so the\n * self-reported identity tooling introspects cannot be mutated at runtime,\n * matching the `readonly` fields of {@link PackageInfo}.\n */\nexport const info: PackageInfo = Object.freeze({ name, version: VERSION, maturity })\n\nexport {\n type Collection,\n type CollectionOptions,\n createCollection,\n type Id,\n type OptimisticChange,\n} from './collection'\nexport { DataError, type DataErrorCode } from './errors'\nexport {\n type Clock,\n type ClockOptions,\n compareHlc,\n createClock,\n decodeHlc,\n encodeHlc,\n type Hlc,\n} from './hlc'\nexport {\n type LwwMap,\n type LwwRegister,\n lwwDelete,\n lwwGet,\n lwwHas,\n lwwKeys,\n lwwSet,\n mergeLwwMap,\n mergeRegister,\n} from './lww'\nexport {\n emptyOrSet,\n mergeOrSet,\n type OrSet,\n orAdd,\n orHas,\n orRemove,\n orValues,\n} from './or-set'\nexport {\n createMemoryPersistence,\n createPersistentEngine,\n createWebStoragePersistence,\n loadSnapshot,\n type Persistence,\n type PersistentEngineOptions,\n persistEngine,\n type WebStorageLike,\n} from './persist'\nexport {\n type Cursor,\n createMemoryHub,\n createMutationLog,\n createSyncEngine,\n type MutationLog,\n type Op,\n type SyncEngine,\n type SyncEngineOptions,\n type SyncSnapshot,\n type SyncTransport,\n} from './sync'\nexport {\n type VersionVector,\n vvDominates,\n vvEquals,\n vvGet,\n vvMerge,\n vvObserve,\n} from './version-vector'\n\nexport type { Maturity, PackageInfo }\nexport { NotImplementedError, notImplemented }\n"],"mappings":";;;;;;;;;;;AAoBA,MAAa,OAAO;;AAGpB,MAAa,UAAU;;AAGvB,MAAa,WAAqB;;;;;;AAOlC,MAAa,OAAoB,OAAO,OAAO;CAAE;CAAM,SAAS;CAAS;AAAS,CAAC"}
|
package/dist/persist.d.ts
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
|
+
import { SyncEngine, SyncEngineOptions, SyncSnapshot } from "./sync.js";
|
|
2
|
+
|
|
1
3
|
//#region src/persist.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Persistence (10F) — a minimal async key/value capability so a Continuum replica
|
|
4
|
-
* survives restart (mirrors the CLI's `FileSystem` / Pulse's `UpdateStorage`). Persist a
|
|
5
|
-
* sync engine's {@link "./sync".SyncEngine.export snapshot} through any `Persistence`
|
|
6
|
-
* and restore it on next launch, so `seq` survives and op ids never collide.
|
|
7
|
-
*
|
|
8
|
-
* `createMemoryPersistence` is the reference; `localStorage`/IndexedDB (web) and native
|
|
9
|
-
* SQLite are research-track adapters (see STATUS). See
|
|
10
|
-
* `docs/adr/0016-continuum-server-persistence.md`.
|
|
11
|
-
*
|
|
12
|
-
* @module
|
|
13
|
-
*/
|
|
14
4
|
/** A minimal async key/value store for persisting Continuum state. */
|
|
15
5
|
interface Persistence {
|
|
16
6
|
/** Read a value, or `null` if absent. */
|
|
@@ -20,6 +10,40 @@ interface Persistence {
|
|
|
20
10
|
}
|
|
21
11
|
/** An in-memory reference {@link Persistence} for tests and as a contract example. */
|
|
22
12
|
declare function createMemoryPersistence(): Persistence;
|
|
13
|
+
/** The synchronous Web Storage shape (`localStorage`/`sessionStorage`), injected so this stays DOM-free. */
|
|
14
|
+
interface WebStorageLike {
|
|
15
|
+
getItem(key: string): string | null;
|
|
16
|
+
setItem(key: string, value: string): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Adapt a Web Storage (`localStorage`/`sessionStorage`) to {@link Persistence}. Inject the storage
|
|
20
|
+
* (`createWebStoragePersistence(localStorage)`) rather than reaching for a global, so it runs in any
|
|
21
|
+
* environment and tests. Storage is synchronous; the async contract is satisfied trivially.
|
|
22
|
+
*/
|
|
23
|
+
declare function createWebStoragePersistence(storage: WebStorageLike): Persistence;
|
|
24
|
+
/** Load + parse a persisted {@link SyncSnapshot}, or `undefined` if absent / unparseable. */
|
|
25
|
+
declare function loadSnapshot<T>(persistence: Persistence, key: string): Promise<SyncSnapshot<T> | undefined>;
|
|
26
|
+
/**
|
|
27
|
+
* Wrap a {@link SyncEngine} so every mutation (`set`/`delete`) and `sync()` auto-saves its snapshot
|
|
28
|
+
* to `persistence` under `key`. Saves are SERIALIZED (chained) so a burst of edits can't write an
|
|
29
|
+
* older snapshot last, and failures are swallowed (best-effort durability never breaks a mutation).
|
|
30
|
+
* To RESTORE on next launch, pass `snapshot: await loadSnapshot(...)` into the engine first —
|
|
31
|
+
* {@link createPersistentEngine} does both.
|
|
32
|
+
*/
|
|
33
|
+
declare function persistEngine<T>(engine: SyncEngine<T>, persistence: Persistence, key: string): SyncEngine<T>;
|
|
34
|
+
/** Options for {@link createPersistentEngine}: a {@link SyncEngineOptions} minus `snapshot` (loaded here). */
|
|
35
|
+
interface PersistentEngineOptions<T> extends Omit<SyncEngineOptions<T>, 'snapshot'> {
|
|
36
|
+
/** Where to persist. */
|
|
37
|
+
readonly persistence: Persistence;
|
|
38
|
+
/** The storage key for this replica's snapshot. */
|
|
39
|
+
readonly key: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a durable {@link SyncEngine}: restore the persisted snapshot (so `seq`/HLC survive and op
|
|
43
|
+
* ids never collide across restarts), then auto-save on every change. One call for a replica that
|
|
44
|
+
* survives restart.
|
|
45
|
+
*/
|
|
46
|
+
declare function createPersistentEngine<T>(options: PersistentEngineOptions<T>): Promise<SyncEngine<T>>;
|
|
23
47
|
//#endregion
|
|
24
|
-
export { Persistence, createMemoryPersistence };
|
|
48
|
+
export { Persistence, PersistentEngineOptions, WebStorageLike, createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine };
|
|
25
49
|
//# sourceMappingURL=persist.d.ts.map
|
package/dist/persist.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.d.ts","names":[],"sources":["../src/persist.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"persist.d.ts","names":[],"sources":["../src/persist.ts"],"mappings":";;;;UAqBiB,WAAA;EAI0B;EAFzC,IAAA,CAAK,GAAA,WAAc,OAAA;EAMkB;EAJrC,IAAA,CAAK,GAAA,UAAa,KAAA,WAAgB,OAAO;AAAA;AAIW;AAAA,iBAAtC,uBAAA,IAA2B,WAAW;;UAYrC,cAAA;EACf,OAAA,CAAQ,GAAA;EACR,OAAA,CAAQ,GAAA,UAAa,KAAA;AAAA;;;;;AAAa;iBAQpB,2BAAA,CAA4B,OAAA,EAAS,cAAA,GAAiB,WAAW;;iBAW3D,YAAA,IACpB,WAAA,EAAa,WAAA,EACb,GAAA,WACC,OAAA,CAAQ,YAAA,CAAa,CAAA;;;;;;AAdyD;AAWjF;iBAqBgB,aAAA,IACd,MAAA,EAAQ,UAAA,CAAW,CAAA,GACnB,WAAA,EAAa,WAAA,EACb,GAAA,WACC,UAAA,CAAW,CAAA;;UA+BG,uBAAA,YAAmC,IAAA,CAAK,iBAAA,CAAkB,CAAA;EArDnD;EAAA,SAuDb,WAAA,EAAa,WAAA;EAvDrB;EAAA,SAyDQ,GAAA;AAAA;;;;;;iBAQW,sBAAA,IACpB,OAAA,EAAS,uBAAA,CAAwB,CAAA,IAChC,OAAA,CAAQ,UAAA,CAAW,CAAA"}
|
package/dist/persist.js
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
+
import { createSyncEngine } from "./sync.js";
|
|
1
2
|
//#region src/persist.ts
|
|
3
|
+
/**
|
|
4
|
+
* Persistence (10F) — a minimal async key/value capability so a Continuum replica
|
|
5
|
+
* survives restart (mirrors the CLI's `FileSystem` / Pulse's `UpdateStorage`). Persist a
|
|
6
|
+
* sync engine's {@link "./sync".SyncEngine.export snapshot} through any `Persistence`
|
|
7
|
+
* and restore it on next launch, so `seq` survives and op ids never collide.
|
|
8
|
+
*
|
|
9
|
+
* `createMemoryPersistence` is the reference; `createWebStoragePersistence` adapts a Web Storage
|
|
10
|
+
* (`localStorage`/`sessionStorage`); {@link persistEngine} wires auto-save + restore so a replica is
|
|
11
|
+
* durable with one call. See `docs/adr/0016-continuum-server-persistence.md`.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
2
15
|
/** An in-memory reference {@link Persistence} for tests and as a contract example. */
|
|
3
16
|
function createMemoryPersistence() {
|
|
4
17
|
const store = /* @__PURE__ */ new Map();
|
|
@@ -10,7 +23,75 @@ function createMemoryPersistence() {
|
|
|
10
23
|
}
|
|
11
24
|
};
|
|
12
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Adapt a Web Storage (`localStorage`/`sessionStorage`) to {@link Persistence}. Inject the storage
|
|
28
|
+
* (`createWebStoragePersistence(localStorage)`) rather than reaching for a global, so it runs in any
|
|
29
|
+
* environment and tests. Storage is synchronous; the async contract is satisfied trivially.
|
|
30
|
+
*/
|
|
31
|
+
function createWebStoragePersistence(storage) {
|
|
32
|
+
return {
|
|
33
|
+
load: (key) => Promise.resolve(storage.getItem(key)),
|
|
34
|
+
save: (key, value) => {
|
|
35
|
+
storage.setItem(key, value);
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Load + parse a persisted {@link SyncSnapshot}, or `undefined` if absent / unparseable. */
|
|
41
|
+
async function loadSnapshot(persistence, key) {
|
|
42
|
+
const raw = await persistence.load(key);
|
|
43
|
+
if (raw === null) return void 0;
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(raw);
|
|
46
|
+
} catch {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Wrap a {@link SyncEngine} so every mutation (`set`/`delete`) and `sync()` auto-saves its snapshot
|
|
52
|
+
* to `persistence` under `key`. Saves are SERIALIZED (chained) so a burst of edits can't write an
|
|
53
|
+
* older snapshot last, and failures are swallowed (best-effort durability never breaks a mutation).
|
|
54
|
+
* To RESTORE on next launch, pass `snapshot: await loadSnapshot(...)` into the engine first —
|
|
55
|
+
* {@link createPersistentEngine} does both.
|
|
56
|
+
*/
|
|
57
|
+
function persistEngine(engine, persistence, key) {
|
|
58
|
+
let chain = Promise.resolve();
|
|
59
|
+
const save = () => {
|
|
60
|
+
const snapshot = JSON.stringify(engine.export());
|
|
61
|
+
chain = chain.then(() => persistence.save(key, snapshot)).then(() => void 0, () => void 0);
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
...engine,
|
|
65
|
+
set(collection, recordId, value) {
|
|
66
|
+
const op = engine.set(collection, recordId, value);
|
|
67
|
+
save();
|
|
68
|
+
return op;
|
|
69
|
+
},
|
|
70
|
+
delete(collection, recordId) {
|
|
71
|
+
const op = engine.delete(collection, recordId);
|
|
72
|
+
save();
|
|
73
|
+
return op;
|
|
74
|
+
},
|
|
75
|
+
async sync(signal) {
|
|
76
|
+
await engine.sync(signal);
|
|
77
|
+
save();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a durable {@link SyncEngine}: restore the persisted snapshot (so `seq`/HLC survive and op
|
|
83
|
+
* ids never collide across restarts), then auto-save on every change. One call for a replica that
|
|
84
|
+
* survives restart.
|
|
85
|
+
*/
|
|
86
|
+
async function createPersistentEngine(options) {
|
|
87
|
+
const { persistence, key, ...syncOptions } = options;
|
|
88
|
+
const snapshot = await loadSnapshot(persistence, key);
|
|
89
|
+
return persistEngine(createSyncEngine(snapshot ? {
|
|
90
|
+
...syncOptions,
|
|
91
|
+
snapshot
|
|
92
|
+
} : syncOptions), persistence, key);
|
|
93
|
+
}
|
|
13
94
|
//#endregion
|
|
14
|
-
export { createMemoryPersistence };
|
|
95
|
+
export { createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine };
|
|
15
96
|
|
|
16
97
|
//# sourceMappingURL=persist.js.map
|
package/dist/persist.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.js","names":[],"sources":["../src/persist.ts"],"sourcesContent":["/**\n * Persistence (10F) — a minimal async key/value capability so a Continuum replica\n * survives restart (mirrors the CLI's `FileSystem` / Pulse's `UpdateStorage`). Persist a\n * sync engine's {@link \"./sync\".SyncEngine.export snapshot} through any `Persistence`\n * and restore it on next launch, so `seq` survives and op ids never collide.\n *\n * `createMemoryPersistence` is the reference; `
|
|
1
|
+
{"version":3,"file":"persist.js","names":[],"sources":["../src/persist.ts"],"sourcesContent":["/**\n * Persistence (10F) — a minimal async key/value capability so a Continuum replica\n * survives restart (mirrors the CLI's `FileSystem` / Pulse's `UpdateStorage`). Persist a\n * sync engine's {@link \"./sync\".SyncEngine.export snapshot} through any `Persistence`\n * and restore it on next launch, so `seq` survives and op ids never collide.\n *\n * `createMemoryPersistence` is the reference; `createWebStoragePersistence` adapts a Web Storage\n * (`localStorage`/`sessionStorage`); {@link persistEngine} wires auto-save + restore so a replica is\n * durable with one call. See `docs/adr/0016-continuum-server-persistence.md`.\n *\n * @module\n */\n\nimport {\n createSyncEngine,\n type SyncEngine,\n type SyncEngineOptions,\n type SyncSnapshot,\n} from './sync'\n\n/** A minimal async key/value store for persisting Continuum state. */\nexport interface Persistence {\n /** Read a value, or `null` if absent. */\n load(key: string): Promise<string | null>\n /** Write a value. */\n save(key: string, value: string): Promise<void>\n}\n\n/** An in-memory reference {@link Persistence} for tests and as a contract example. */\nexport function createMemoryPersistence(): Persistence {\n const store = new Map<string, string>()\n return {\n load: (key) => Promise.resolve(store.get(key) ?? null),\n save: (key, value) => {\n store.set(key, value)\n return Promise.resolve()\n },\n }\n}\n\n/** The synchronous Web Storage shape (`localStorage`/`sessionStorage`), injected so this stays DOM-free. */\nexport interface WebStorageLike {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n}\n\n/**\n * Adapt a Web Storage (`localStorage`/`sessionStorage`) to {@link Persistence}. Inject the storage\n * (`createWebStoragePersistence(localStorage)`) rather than reaching for a global, so it runs in any\n * environment and tests. Storage is synchronous; the async contract is satisfied trivially.\n */\nexport function createWebStoragePersistence(storage: WebStorageLike): Persistence {\n return {\n load: (key) => Promise.resolve(storage.getItem(key)),\n save: (key, value) => {\n storage.setItem(key, value)\n return Promise.resolve()\n },\n }\n}\n\n/** Load + parse a persisted {@link SyncSnapshot}, or `undefined` if absent / unparseable. */\nexport async function loadSnapshot<T>(\n persistence: Persistence,\n key: string,\n): Promise<SyncSnapshot<T> | undefined> {\n const raw = await persistence.load(key)\n if (raw === null) return undefined\n try {\n return JSON.parse(raw) as SyncSnapshot<T>\n } catch {\n // A corrupt/partial blob must not wedge startup — start fresh rather than throw.\n return undefined\n }\n}\n\n/**\n * Wrap a {@link SyncEngine} so every mutation (`set`/`delete`) and `sync()` auto-saves its snapshot\n * to `persistence` under `key`. Saves are SERIALIZED (chained) so a burst of edits can't write an\n * older snapshot last, and failures are swallowed (best-effort durability never breaks a mutation).\n * To RESTORE on next launch, pass `snapshot: await loadSnapshot(...)` into the engine first —\n * {@link createPersistentEngine} does both.\n */\nexport function persistEngine<T>(\n engine: SyncEngine<T>,\n persistence: Persistence,\n key: string,\n): SyncEngine<T> {\n let chain: Promise<void> = Promise.resolve()\n const save = (): void => {\n const snapshot = JSON.stringify(engine.export())\n chain = chain\n .then(() => persistence.save(key, snapshot))\n .then(\n () => undefined,\n () => undefined,\n )\n }\n return {\n ...engine,\n set(collection, recordId, value) {\n const op = engine.set(collection, recordId, value)\n save()\n return op\n },\n delete(collection, recordId) {\n const op = engine.delete(collection, recordId)\n save()\n return op\n },\n async sync(signal) {\n await engine.sync(signal)\n save()\n },\n }\n}\n\n/** Options for {@link createPersistentEngine}: a {@link SyncEngineOptions} minus `snapshot` (loaded here). */\nexport interface PersistentEngineOptions<T> extends Omit<SyncEngineOptions<T>, 'snapshot'> {\n /** Where to persist. */\n readonly persistence: Persistence\n /** The storage key for this replica's snapshot. */\n readonly key: string\n}\n\n/**\n * Create a durable {@link SyncEngine}: restore the persisted snapshot (so `seq`/HLC survive and op\n * ids never collide across restarts), then auto-save on every change. One call for a replica that\n * survives restart.\n */\nexport async function createPersistentEngine<T>(\n options: PersistentEngineOptions<T>,\n): Promise<SyncEngine<T>> {\n const { persistence, key, ...syncOptions } = options\n const snapshot = await loadSnapshot<T>(persistence, key)\n const engine = createSyncEngine<T>(snapshot ? { ...syncOptions, snapshot } : syncOptions)\n return persistEngine(engine, persistence, key)\n}\n"],"mappings":";;;;;;;;;;;;;;;AA6BA,SAAgB,0BAAuC;CACrD,MAAM,wBAAQ,IAAI,IAAoB;CACtC,OAAO;EACL,OAAO,QAAQ,QAAQ,QAAQ,MAAM,IAAI,GAAG,KAAK,IAAI;EACrD,OAAO,KAAK,UAAU;GACpB,MAAM,IAAI,KAAK,KAAK;GACpB,OAAO,QAAQ,QAAQ;EACzB;CACF;AACF;;;;;;AAaA,SAAgB,4BAA4B,SAAsC;CAChF,OAAO;EACL,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,GAAG,CAAC;EACnD,OAAO,KAAK,UAAU;GACpB,QAAQ,QAAQ,KAAK,KAAK;GAC1B,OAAO,QAAQ,QAAQ;EACzB;CACF;AACF;;AAGA,eAAsB,aACpB,aACA,KACsC;CACtC,MAAM,MAAM,MAAM,YAAY,KAAK,GAAG;CACtC,IAAI,QAAQ,MAAM,OAAO,KAAA;CACzB,IAAI;EACF,OAAO,KAAK,MAAM,GAAG;CACvB,QAAQ;EAEN;CACF;AACF;;;;;;;;AASA,SAAgB,cACd,QACA,aACA,KACe;CACf,IAAI,QAAuB,QAAQ,QAAQ;CAC3C,MAAM,aAAmB;EACvB,MAAM,WAAW,KAAK,UAAU,OAAO,OAAO,CAAC;EAC/C,QAAQ,MACL,WAAW,YAAY,KAAK,KAAK,QAAQ,CAAC,EAC1C,WACO,KAAA,SACA,KAAA,CACR;CACJ;CACA,OAAO;EACL,GAAG;EACH,IAAI,YAAY,UAAU,OAAO;GAC/B,MAAM,KAAK,OAAO,IAAI,YAAY,UAAU,KAAK;GACjD,KAAK;GACL,OAAO;EACT;EACA,OAAO,YAAY,UAAU;GAC3B,MAAM,KAAK,OAAO,OAAO,YAAY,QAAQ;GAC7C,KAAK;GACL,OAAO;EACT;EACA,MAAM,KAAK,QAAQ;GACjB,MAAM,OAAO,KAAK,MAAM;GACxB,KAAK;EACP;CACF;AACF;;;;;;AAeA,eAAsB,uBACpB,SACwB;CACxB,MAAM,EAAE,aAAa,KAAK,GAAG,gBAAgB;CAC7C,MAAM,WAAW,MAAM,aAAgB,aAAa,GAAG;CAEvD,OAAO,cADQ,iBAAoB,WAAW;EAAE,GAAG;EAAa;CAAS,IAAI,WACnD,GAAG,aAAa,GAAG;AAC/C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindees/data",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MindeesNative Continuum - local-first reactive store and sync: a signals-native document store with fine-grained reactive queries, optimistic updates, CRDT conflict resolution, and delta sync.",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"directory": "packages/data"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@mindees/core": "0.
|
|
30
|
+
"@mindees/core": "0.5.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"fast-check": "4.8.0"
|