@mindees/data 0.20.0 → 0.22.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 +44 -1
- package/dist/persist.d.ts.map +1 -1
- package/dist/persist.js +35 -1
- package/dist/persist.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Clock, ClockOptions, Hlc, compareHlc, createClock, decodeHlc, encodeHlc
|
|
|
5
5
|
import { LwwMap, LwwRegister, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, mergeLwwMap, mergeRegister } from "./lww.js";
|
|
6
6
|
import { OrSet, emptyOrSet, mergeOrSet, orAdd, orHas, orRemove, orValues } from "./or-set.js";
|
|
7
7
|
import { Cursor, MutationLog, Op, SyncEngine, SyncEngineOptions, SyncSnapshot, SyncTransport, createMemoryHub, createMutationLog, createSyncEngine } from "./sync.js";
|
|
8
|
-
import { Persistence, PersistentEngineOptions, WebStorageLike, createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine } from "./persist.js";
|
|
8
|
+
import { IndexedDbFactoryLike, IndexedDbPersistenceOptions, Persistence, PersistentEngineOptions, WebStorageLike, createIndexedDbPersistence, createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine } from "./persist.js";
|
|
9
9
|
import { VersionVector, vvDominates, vvEquals, vvGet, vvMerge, vvObserve } from "./version-vector.js";
|
|
10
10
|
import { Maturity, NotImplementedError, PackageInfo, notImplemented } from "@mindees/core";
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ import { Maturity, NotImplementedError, PackageInfo, notImplemented } from "@min
|
|
|
13
13
|
/** The npm package name. */
|
|
14
14
|
declare const name = "@mindees/data";
|
|
15
15
|
/** The package version. All `@mindees/*` packages share one locked version line. */
|
|
16
|
-
declare const VERSION = "0.
|
|
16
|
+
declare const VERSION = "0.22.0";
|
|
17
17
|
/** Current maturity of this package. See the repository `STATUS.md`. */
|
|
18
18
|
declare const maturity: Maturity;
|
|
19
19
|
/**
|
|
@@ -23,5 +23,5 @@ declare const maturity: Maturity;
|
|
|
23
23
|
*/
|
|
24
24
|
declare const info: PackageInfo;
|
|
25
25
|
//#endregion
|
|
26
|
-
export { type Clock, type ClockOptions, type Collection, type CollectionOptions, type Counter, 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, counterDec, counterInc, counterValue, createClock, createCollection, createMemoryHub, createMemoryPersistence, createMutationLog, createPersistentEngine, createSyncEngine, createWebStoragePersistence, decodeHlc, emptyCounter, emptyOrSet, encodeHlc, info, loadSnapshot, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, maturity, mergeCounter, mergeLwwMap, mergeOrSet, mergeRegister, name, notImplemented, orAdd, orHas, orRemove, orValues, persistEngine, vvDominates, vvEquals, vvGet, vvMerge, vvObserve };
|
|
26
|
+
export { type Clock, type ClockOptions, type Collection, type CollectionOptions, type Counter, type Cursor, DataError, type DataErrorCode, type Hlc, type Id, type IndexedDbFactoryLike, type IndexedDbPersistenceOptions, 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, counterDec, counterInc, counterValue, createClock, createCollection, createIndexedDbPersistence, createMemoryHub, createMemoryPersistence, createMutationLog, createPersistentEngine, createSyncEngine, createWebStoragePersistence, decodeHlc, emptyCounter, emptyOrSet, encodeHlc, info, loadSnapshot, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, maturity, mergeCounter, mergeLwwMap, mergeOrSet, mergeRegister, name, notImplemented, orAdd, orHas, orRemove, orValues, persistEngine, vvDominates, vvEquals, vvGet, vvMerge, vvObserve };
|
|
27
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -5,14 +5,14 @@ import { compareHlc, createClock, decodeHlc, encodeHlc } from "./hlc.js";
|
|
|
5
5
|
import { lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, mergeLwwMap, mergeRegister } from "./lww.js";
|
|
6
6
|
import { emptyOrSet, mergeOrSet, orAdd, orHas, orRemove, orValues } from "./or-set.js";
|
|
7
7
|
import { createMemoryHub, createMutationLog, createSyncEngine } from "./sync.js";
|
|
8
|
-
import { createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine } from "./persist.js";
|
|
8
|
+
import { createIndexedDbPersistence, createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine } from "./persist.js";
|
|
9
9
|
import { vvDominates, vvEquals, vvGet, vvMerge, vvObserve } from "./version-vector.js";
|
|
10
10
|
import { NotImplementedError, notImplemented } from "@mindees/core";
|
|
11
11
|
//#region src/index.ts
|
|
12
12
|
/** The npm package name. */
|
|
13
13
|
const name = "@mindees/data";
|
|
14
14
|
/** The package version. All `@mindees/*` packages share one locked version line. */
|
|
15
|
-
const VERSION = "0.
|
|
15
|
+
const VERSION = "0.22.0";
|
|
16
16
|
/** Current maturity of this package. See the repository `STATUS.md`. */
|
|
17
17
|
const maturity = "experimental";
|
|
18
18
|
/**
|
|
@@ -26,6 +26,6 @@ const info = Object.freeze({
|
|
|
26
26
|
maturity
|
|
27
27
|
});
|
|
28
28
|
//#endregion
|
|
29
|
-
export { DataError, NotImplementedError, VERSION, compareHlc, counterDec, counterInc, counterValue, createClock, createCollection, createMemoryHub, createMemoryPersistence, createMutationLog, createPersistentEngine, createSyncEngine, createWebStoragePersistence, decodeHlc, emptyCounter, emptyOrSet, encodeHlc, info, loadSnapshot, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, maturity, mergeCounter, mergeLwwMap, mergeOrSet, mergeRegister, name, notImplemented, orAdd, orHas, orRemove, orValues, persistEngine, vvDominates, vvEquals, vvGet, vvMerge, vvObserve };
|
|
29
|
+
export { DataError, NotImplementedError, VERSION, compareHlc, counterDec, counterInc, counterValue, createClock, createCollection, createIndexedDbPersistence, createMemoryHub, createMemoryPersistence, createMutationLog, createPersistentEngine, createSyncEngine, createWebStoragePersistence, decodeHlc, emptyCounter, emptyOrSet, encodeHlc, info, loadSnapshot, lwwDelete, lwwGet, lwwHas, lwwKeys, lwwSet, maturity, mergeCounter, mergeLwwMap, mergeOrSet, mergeRegister, name, notImplemented, orAdd, orHas, orRemove, orValues, persistEngine, vvDominates, vvEquals, vvGet, vvMerge, vvObserve };
|
|
30
30
|
|
|
31
31
|
//# 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.22.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 {\n type Counter,\n counterDec,\n counterInc,\n counterValue,\n emptyCounter,\n mergeCounter,\n} from './counter'\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 createIndexedDbPersistence,\n createMemoryPersistence,\n createPersistentEngine,\n createWebStoragePersistence,\n type IndexedDbFactoryLike,\n type IndexedDbPersistenceOptions,\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
|
@@ -44,6 +44,49 @@ interface PersistentEngineOptions<T> extends Omit<SyncEngineOptions<T>, 'snapsho
|
|
|
44
44
|
* survives restart.
|
|
45
45
|
*/
|
|
46
46
|
declare function createPersistentEngine<T>(options: PersistentEngineOptions<T>): Promise<SyncEngine<T>>;
|
|
47
|
+
interface IdbRequestLike<T> {
|
|
48
|
+
result: T;
|
|
49
|
+
error: unknown;
|
|
50
|
+
onsuccess: (() => void) | null;
|
|
51
|
+
onerror: (() => void) | null;
|
|
52
|
+
}
|
|
53
|
+
interface IdbOpenRequestLike extends IdbRequestLike<IdbDatabaseLike> {
|
|
54
|
+
onupgradeneeded: (() => void) | null;
|
|
55
|
+
}
|
|
56
|
+
interface IdbObjectStoreLike {
|
|
57
|
+
get(key: string): IdbRequestLike<unknown>;
|
|
58
|
+
put(value: string, key: string): IdbRequestLike<unknown>;
|
|
59
|
+
}
|
|
60
|
+
interface IdbTransactionLike {
|
|
61
|
+
objectStore(name: string): IdbObjectStoreLike;
|
|
62
|
+
}
|
|
63
|
+
interface IdbDatabaseLike {
|
|
64
|
+
objectStoreNames: {
|
|
65
|
+
contains(name: string): boolean;
|
|
66
|
+
};
|
|
67
|
+
createObjectStore(name: string): unknown;
|
|
68
|
+
transaction(storeNames: string, mode: 'readonly' | 'readwrite'): IdbTransactionLike;
|
|
69
|
+
}
|
|
70
|
+
/** The minimal IndexedDB factory surface (a structural subset of the DOM `IDBFactory`). */
|
|
71
|
+
interface IndexedDbFactoryLike {
|
|
72
|
+
open(name: string, version?: number): IdbOpenRequestLike;
|
|
73
|
+
}
|
|
74
|
+
/** Options for {@link createIndexedDbPersistence}. */
|
|
75
|
+
interface IndexedDbPersistenceOptions {
|
|
76
|
+
/** Database name (default `'mindees'`). */
|
|
77
|
+
readonly databaseName?: string;
|
|
78
|
+
/** Object-store name (default `'continuum'`). */
|
|
79
|
+
readonly storeName?: string;
|
|
80
|
+
/** The IndexedDB factory; defaults to `globalThis.indexedDB`. Inject (e.g. `fake-indexeddb`) elsewhere. */
|
|
81
|
+
readonly factory?: IndexedDbFactoryLike;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A durable {@link Persistence} backed by IndexedDB — large, asynchronous browser storage (beyond
|
|
85
|
+
* `localStorage`'s synchronous ~5MB cap), a better home for a growing Continuum op log/snapshot. The
|
|
86
|
+
* database + object store open lazily on first use and are reused. Inject `factory` to run outside a
|
|
87
|
+
* browser (tests, or a custom environment); throws if none is available.
|
|
88
|
+
*/
|
|
89
|
+
declare function createIndexedDbPersistence(options?: IndexedDbPersistenceOptions): Persistence;
|
|
47
90
|
//#endregion
|
|
48
|
-
export { Persistence, PersistentEngineOptions, WebStorageLike, createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine };
|
|
91
|
+
export { IndexedDbFactoryLike, IndexedDbPersistenceOptions, Persistence, PersistentEngineOptions, WebStorageLike, createIndexedDbPersistence, createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine };
|
|
49
92
|
//# 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":";;;;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"}
|
|
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;AAAA,UAaZ,cAAA;EACR,MAAA,EAAQ,CAAC;EACT,KAAA;EACA,SAAA;EACA,OAAA;AAAA;AAAA,UAEQ,kBAAA,SAA2B,cAAc,CAAC,eAAA;EAClD,eAAA;AAAA;AAAA,UAEQ,kBAAA;EACR,GAAA,CAAI,GAAA,WAAc,cAAA;EAClB,GAAA,CAAI,KAAA,UAAe,GAAA,WAAc,cAAc;AAAA;AAAA,UAEvC,kBAAA;EACR,WAAA,CAAY,IAAA,WAAe,kBAAkB;AAAA;AAAA,UAErC,eAAA;EACR,gBAAA;IAAoB,QAAA,CAAS,IAAA;EAAA;EAC7B,iBAAA,CAAkB,IAAA;EAClB,WAAA,CAAY,UAAA,UAAoB,IAAA,6BAAiC,kBAAkB;AAAA;AA7EtE;AAAA,UAgFE,oBAAA;EACf,IAAA,CAAK,IAAA,UAAc,OAAA,YAAmB,kBAAkB;AAAA;;UAIzC,2BAAA;EApDO;EAAA,SAsDb,YAAA;EAxD6C;EAAA,SA0D7C,SAAA;EA1D8B;EAAA,SA4D9B,OAAA,GAAU,oBAAoB;AAAA;;;;;;AAxD3B;iBAiEE,0BAAA,CAA2B,OAAA,GAAS,2BAAA,GAAmC,WAAW"}
|
package/dist/persist.js
CHANGED
|
@@ -91,7 +91,41 @@ async function createPersistentEngine(options) {
|
|
|
91
91
|
snapshot
|
|
92
92
|
} : syncOptions), persistence, key);
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* A durable {@link Persistence} backed by IndexedDB — large, asynchronous browser storage (beyond
|
|
96
|
+
* `localStorage`'s synchronous ~5MB cap), a better home for a growing Continuum op log/snapshot. The
|
|
97
|
+
* database + object store open lazily on first use and are reused. Inject `factory` to run outside a
|
|
98
|
+
* browser (tests, or a custom environment); throws if none is available.
|
|
99
|
+
*/
|
|
100
|
+
function createIndexedDbPersistence(options = {}) {
|
|
101
|
+
const dbName = options.databaseName ?? "mindees";
|
|
102
|
+
const storeName = options.storeName ?? "continuum";
|
|
103
|
+
const factory = options.factory ?? globalThis.indexedDB;
|
|
104
|
+
if (!factory) throw new Error("createIndexedDbPersistence: IndexedDB is unavailable; pass `factory`.");
|
|
105
|
+
let dbPromise;
|
|
106
|
+
const openDb = () => {
|
|
107
|
+
if (!dbPromise) dbPromise = new Promise((resolve, reject) => {
|
|
108
|
+
const request = factory.open(dbName, 1);
|
|
109
|
+
request.onupgradeneeded = () => {
|
|
110
|
+
const db = request.result;
|
|
111
|
+
if (!db.objectStoreNames.contains(storeName)) db.createObjectStore(storeName);
|
|
112
|
+
};
|
|
113
|
+
request.onsuccess = () => resolve(request.result);
|
|
114
|
+
request.onerror = () => reject(request.error ?? /* @__PURE__ */ new Error("IndexedDB open failed"));
|
|
115
|
+
});
|
|
116
|
+
return dbPromise;
|
|
117
|
+
};
|
|
118
|
+
const run = (mode, op) => openDb().then((db) => new Promise((resolve, reject) => {
|
|
119
|
+
const request = op(db.transaction(storeName, mode).objectStore(storeName));
|
|
120
|
+
request.onsuccess = () => resolve(request.result);
|
|
121
|
+
request.onerror = () => reject(request.error ?? /* @__PURE__ */ new Error("IndexedDB request failed"));
|
|
122
|
+
}));
|
|
123
|
+
return {
|
|
124
|
+
load: (key) => run("readonly", (store) => store.get(key)).then((value) => value === void 0 || value === null ? null : String(value)),
|
|
125
|
+
save: (key, value) => run("readwrite", (store) => store.put(value, key)).then(() => void 0)
|
|
126
|
+
};
|
|
127
|
+
}
|
|
94
128
|
//#endregion
|
|
95
|
-
export { createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine };
|
|
129
|
+
export { createIndexedDbPersistence, createMemoryPersistence, createPersistentEngine, createWebStoragePersistence, loadSnapshot, persistEngine };
|
|
96
130
|
|
|
97
131
|
//# 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; `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"}
|
|
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\n// --- IndexedDB persistence (durable browser storage; large + async, beyond localStorage's sync ~5MB) ---\n//\n// A minimal structural subset of the DOM IndexedDB types, declared here so @mindees/data stays\n// DOM-lib-free (mirrors WebStorageLike). The real `globalThis.indexedDB` and `fake-indexeddb` are\n// structurally assignable to IndexedDbFactoryLike.\n\ninterface IdbRequestLike<T> {\n result: T\n error: unknown\n onsuccess: (() => void) | null\n onerror: (() => void) | null\n}\ninterface IdbOpenRequestLike extends IdbRequestLike<IdbDatabaseLike> {\n onupgradeneeded: (() => void) | null\n}\ninterface IdbObjectStoreLike {\n get(key: string): IdbRequestLike<unknown>\n put(value: string, key: string): IdbRequestLike<unknown>\n}\ninterface IdbTransactionLike {\n objectStore(name: string): IdbObjectStoreLike\n}\ninterface IdbDatabaseLike {\n objectStoreNames: { contains(name: string): boolean }\n createObjectStore(name: string): unknown\n transaction(storeNames: string, mode: 'readonly' | 'readwrite'): IdbTransactionLike\n}\n/** The minimal IndexedDB factory surface (a structural subset of the DOM `IDBFactory`). */\nexport interface IndexedDbFactoryLike {\n open(name: string, version?: number): IdbOpenRequestLike\n}\n\n/** Options for {@link createIndexedDbPersistence}. */\nexport interface IndexedDbPersistenceOptions {\n /** Database name (default `'mindees'`). */\n readonly databaseName?: string\n /** Object-store name (default `'continuum'`). */\n readonly storeName?: string\n /** The IndexedDB factory; defaults to `globalThis.indexedDB`. Inject (e.g. `fake-indexeddb`) elsewhere. */\n readonly factory?: IndexedDbFactoryLike\n}\n\n/**\n * A durable {@link Persistence} backed by IndexedDB — large, asynchronous browser storage (beyond\n * `localStorage`'s synchronous ~5MB cap), a better home for a growing Continuum op log/snapshot. The\n * database + object store open lazily on first use and are reused. Inject `factory` to run outside a\n * browser (tests, or a custom environment); throws if none is available.\n */\nexport function createIndexedDbPersistence(options: IndexedDbPersistenceOptions = {}): Persistence {\n const dbName = options.databaseName ?? 'mindees'\n const storeName = options.storeName ?? 'continuum'\n const factory = options.factory ?? (globalThis as { indexedDB?: IndexedDbFactoryLike }).indexedDB\n if (!factory) {\n throw new Error('createIndexedDbPersistence: IndexedDB is unavailable; pass `factory`.')\n }\n\n let dbPromise: Promise<IdbDatabaseLike> | undefined\n const openDb = (): Promise<IdbDatabaseLike> => {\n if (!dbPromise) {\n dbPromise = new Promise<IdbDatabaseLike>((resolve, reject) => {\n const request = factory.open(dbName, 1)\n request.onupgradeneeded = () => {\n const db = request.result\n if (!db.objectStoreNames.contains(storeName)) db.createObjectStore(storeName)\n }\n request.onsuccess = () => resolve(request.result)\n request.onerror = () => reject(request.error ?? new Error('IndexedDB open failed'))\n })\n }\n return dbPromise\n }\n\n const run = <T>(\n mode: 'readonly' | 'readwrite',\n op: (store: IdbObjectStoreLike) => IdbRequestLike<T>,\n ): Promise<T> =>\n openDb().then(\n (db) =>\n new Promise<T>((resolve, reject) => {\n const request = op(db.transaction(storeName, mode).objectStore(storeName))\n request.onsuccess = () => resolve(request.result)\n request.onerror = () => reject(request.error ?? new Error('IndexedDB request failed'))\n }),\n )\n\n return {\n load: (key) =>\n run('readonly', (store) => store.get(key)).then((value) =>\n value === undefined || value === null ? null : String(value),\n ),\n save: (key, value) => run('readwrite', (store) => store.put(value, key)).then(() => undefined),\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindees/data",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.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,9 +27,10 @@
|
|
|
27
27
|
"directory": "packages/data"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@mindees/core": "0.
|
|
30
|
+
"@mindees/core": "0.22.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
+
"fake-indexeddb": "6.0.0",
|
|
33
34
|
"fast-check": "4.8.0"
|
|
34
35
|
},
|
|
35
36
|
"scripts": {
|