mvc-kit 2.5.2 → 2.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/agent-config/claude-code/skills/guide/api-reference.md +10 -10
- package/dist/Channel.cjs +291 -0
- package/dist/Channel.cjs.map +1 -0
- package/dist/Channel.d.ts +1 -1
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +291 -0
- package/dist/Channel.js.map +1 -0
- package/dist/Collection.cjs +452 -0
- package/dist/Collection.cjs.map +1 -0
- package/dist/Collection.d.ts +7 -7
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +452 -0
- package/dist/Collection.js.map +1 -0
- package/dist/Controller.cjs +57 -0
- package/dist/Controller.cjs.map +1 -0
- package/dist/Controller.js +57 -0
- package/dist/Controller.js.map +1 -0
- package/dist/EventBus.cjs +84 -0
- package/dist/EventBus.cjs.map +1 -0
- package/dist/EventBus.js +84 -0
- package/dist/EventBus.js.map +1 -0
- package/dist/Model.cjs +175 -0
- package/dist/Model.cjs.map +1 -0
- package/dist/Model.d.ts +4 -4
- package/dist/Model.d.ts.map +1 -1
- package/dist/Model.js +175 -0
- package/dist/Model.js.map +1 -0
- package/dist/PersistentCollection.cjs +285 -0
- package/dist/PersistentCollection.cjs.map +1 -0
- package/dist/PersistentCollection.d.ts +4 -4
- package/dist/PersistentCollection.d.ts.map +1 -1
- package/dist/PersistentCollection.js +285 -0
- package/dist/PersistentCollection.js.map +1 -0
- package/dist/Resource.cjs +308 -0
- package/dist/Resource.cjs.map +1 -0
- package/dist/Resource.d.ts +6 -6
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +308 -0
- package/dist/Resource.js.map +1 -0
- package/dist/Service.cjs +51 -0
- package/dist/Service.cjs.map +1 -0
- package/dist/Service.js +51 -0
- package/dist/Service.js.map +1 -0
- package/dist/ViewModel.cjs +582 -0
- package/dist/ViewModel.cjs.map +1 -0
- package/dist/ViewModel.d.ts +3 -9
- package/dist/ViewModel.d.ts.map +1 -1
- package/dist/ViewModel.js +582 -0
- package/dist/ViewModel.js.map +1 -0
- package/dist/errors.cjs +79 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.js +79 -0
- package/dist/errors.js.map +1 -0
- package/dist/mvc-kit.cjs +29 -1
- package/dist/mvc-kit.cjs.map +1 -1
- package/dist/mvc-kit.js +27 -1132
- package/dist/mvc-kit.js.map +1 -1
- package/dist/react/guards.cjs +7 -0
- package/dist/react/guards.cjs.map +1 -0
- package/dist/react/guards.js +7 -0
- package/dist/react/guards.js.map +1 -0
- package/dist/react/provider.cjs +26 -0
- package/dist/react/provider.cjs.map +1 -0
- package/dist/react/provider.js +26 -0
- package/dist/react/provider.js.map +1 -0
- package/dist/react/types.d.ts +1 -1
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/use-event-bus.cjs +26 -0
- package/dist/react/use-event-bus.cjs.map +1 -0
- package/dist/react/use-event-bus.js +26 -0
- package/dist/react/use-event-bus.js.map +1 -0
- package/dist/react/use-instance.cjs +31 -0
- package/dist/react/use-instance.cjs.map +1 -0
- package/dist/react/use-instance.d.ts +1 -1
- package/dist/react/use-instance.d.ts.map +1 -1
- package/dist/react/use-instance.js +31 -0
- package/dist/react/use-instance.js.map +1 -0
- package/dist/react/use-local.cjs +64 -0
- package/dist/react/use-local.cjs.map +1 -0
- package/dist/react/use-local.d.ts +4 -4
- package/dist/react/use-local.d.ts.map +1 -1
- package/dist/react/use-local.js +64 -0
- package/dist/react/use-local.js.map +1 -0
- package/dist/react/use-model.cjs +80 -0
- package/dist/react/use-model.cjs.map +1 -0
- package/dist/react/use-model.d.ts +1 -1
- package/dist/react/use-model.d.ts.map +1 -1
- package/dist/react/use-model.js +80 -0
- package/dist/react/use-model.js.map +1 -0
- package/dist/react/use-singleton.cjs +21 -0
- package/dist/react/use-singleton.cjs.map +1 -0
- package/dist/react/use-singleton.d.ts +1 -1
- package/dist/react/use-singleton.d.ts.map +1 -1
- package/dist/react/use-singleton.js +21 -0
- package/dist/react/use-singleton.js.map +1 -0
- package/dist/react/use-teardown.cjs +22 -0
- package/dist/react/use-teardown.cjs.map +1 -0
- package/dist/react/use-teardown.js +22 -0
- package/dist/react/use-teardown.js.map +1 -0
- package/dist/react-native/NativeCollection.cjs +76 -0
- package/dist/react-native/NativeCollection.cjs.map +1 -0
- package/dist/react-native/NativeCollection.js +76 -0
- package/dist/react-native/NativeCollection.js.map +1 -0
- package/dist/react-native.cjs +4 -1
- package/dist/react-native.cjs.map +1 -1
- package/dist/react-native.js +2 -60
- package/dist/react-native.js.map +1 -1
- package/dist/react.cjs +19 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +17 -145
- package/dist/react.js.map +1 -1
- package/dist/singleton.cjs +34 -0
- package/dist/singleton.cjs.map +1 -0
- package/dist/singleton.js +34 -0
- package/dist/singleton.js.map +1 -0
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/walkPrototypeChain.cjs +15 -0
- package/dist/walkPrototypeChain.cjs.map +1 -0
- package/dist/walkPrototypeChain.d.ts +9 -0
- package/dist/walkPrototypeChain.d.ts.map +1 -0
- package/dist/walkPrototypeChain.js +15 -0
- package/dist/walkPrototypeChain.js.map +1 -0
- package/dist/web/IndexedDBCollection.cjs +37 -0
- package/dist/web/IndexedDBCollection.cjs.map +1 -0
- package/dist/web/IndexedDBCollection.js +37 -0
- package/dist/web/IndexedDBCollection.js.map +1 -0
- package/dist/web/WebStorageCollection.cjs +85 -0
- package/dist/web/WebStorageCollection.cjs.map +1 -0
- package/dist/web/WebStorageCollection.d.ts +2 -2
- package/dist/web/WebStorageCollection.d.ts.map +1 -1
- package/dist/web/WebStorageCollection.js +85 -0
- package/dist/web/WebStorageCollection.js.map +1 -0
- package/dist/web/idb.cjs +121 -0
- package/dist/web/idb.cjs.map +1 -0
- package/dist/web/idb.js +121 -0
- package/dist/web/idb.js.map +1 -0
- package/dist/web.cjs +6 -1
- package/dist/web.cjs.map +1 -1
- package/dist/web.js +4 -178
- package/dist/web.js.map +1 -1
- package/package.json +4 -2
- package/dist/PersistentCollection-B8kNECDj.cjs +0 -2
- package/dist/PersistentCollection-B8kNECDj.cjs.map +0 -1
- package/dist/PersistentCollection-BFrgskju.js +0 -542
- package/dist/PersistentCollection-BFrgskju.js.map +0 -1
- package/dist/singleton-CaEXSbYg.js +0 -89
- package/dist/singleton-CaEXSbYg.js.map +0 -1
- package/dist/singleton-L-u2W_lX.cjs +0 -2
- package/dist/singleton-L-u2W_lX.cjs.map +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const PersistentCollection = require("../PersistentCollection.cjs");
|
|
4
|
+
const idb = require("./idb.cjs");
|
|
5
|
+
class IndexedDBCollection extends PersistentCollection.PersistentCollection {
|
|
6
|
+
/** IndexedDB database name. Override to use a separate database. */
|
|
7
|
+
static DB_NAME = "mvc-kit";
|
|
8
|
+
get _dbName() {
|
|
9
|
+
return this.constructor.DB_NAME;
|
|
10
|
+
}
|
|
11
|
+
_getStore(mode) {
|
|
12
|
+
return idb.getStore(this._dbName, this.storageKey, mode);
|
|
13
|
+
}
|
|
14
|
+
// ── Persist interface (per-item strategy) ──
|
|
15
|
+
async persistGetAll() {
|
|
16
|
+
const store = await this._getStore("readonly");
|
|
17
|
+
return idb.idbGetAll(store);
|
|
18
|
+
}
|
|
19
|
+
async persistGet(id) {
|
|
20
|
+
const store = await this._getStore("readonly");
|
|
21
|
+
return idb.idbGet(store, id);
|
|
22
|
+
}
|
|
23
|
+
async persistSet(items) {
|
|
24
|
+
const store = await this._getStore("readwrite");
|
|
25
|
+
return idb.idbPut(store, items);
|
|
26
|
+
}
|
|
27
|
+
async persistRemove(ids) {
|
|
28
|
+
const store = await this._getStore("readwrite");
|
|
29
|
+
return idb.idbDelete(store, ids);
|
|
30
|
+
}
|
|
31
|
+
async persistClear() {
|
|
32
|
+
const store = await this._getStore("readwrite");
|
|
33
|
+
return idb.idbClear(store);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.IndexedDBCollection = IndexedDBCollection;
|
|
37
|
+
//# sourceMappingURL=IndexedDBCollection.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndexedDBCollection.cjs","sources":["../../src/web/IndexedDBCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\nimport { getStore, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from './idb';\n\n/**\n * PersistentCollection backed by IndexedDB. Stores items individually by `id`\n * in a dedicated object store (named by `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n * Typically called in ViewModel's `onInit()`.\n *\n * Uses per-item strategy: each item is stored as a separate entry in the object store.\n * No JSON serialization needed — IndexedDB uses structured cloning.\n *\n * ```ts\n * class MessagesCollection extends IndexedDBCollection<Message> {\n * protected readonly storageKey = 'messages';\n * }\n *\n * // In ViewModel:\n * async onInit() {\n * await this.collection.hydrate();\n * if (this.collection.length === 0) this.load();\n * }\n * ```\n */\nexport abstract class IndexedDBCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** IndexedDB database name. Override to use a separate database. */\n static DB_NAME = 'mvc-kit';\n\n private get _dbName(): string {\n return (this.constructor as typeof IndexedDBCollection).DB_NAME;\n }\n\n private _getStore(mode: IDBTransactionMode) {\n return getStore(this._dbName, this.storageKey, mode);\n }\n\n // ── Persist interface (per-item strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const store = await this._getStore('readonly');\n return idbGetAll<T>(store);\n }\n\n protected async persistGet(id: T['id']): Promise<T | null> {\n const store = await this._getStore('readonly');\n return idbGet<T>(store, id as IDBValidKey);\n }\n\n protected async persistSet(items: T[]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbPut(store, items);\n }\n\n protected async persistRemove(ids: T['id'][]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbDelete(store, ids as IDBValidKey[]);\n }\n\n protected async persistClear(): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbClear(store);\n }\n}\n"],"names":["PersistentCollection","getStore","idbGetAll","idbGet","idbPut","idbDelete","idbClear"],"mappings":";;;;AAyBO,MAAe,4BAEZA,qBAAAA,qBAAwB;AAAA;AAAA,EAEhC,OAAO,UAAU;AAAA,EAEjB,IAAY,UAAkB;AAC5B,WAAQ,KAAK,YAA2C;AAAA,EAC1D;AAAA,EAEQ,UAAU,MAA0B;AAC1C,WAAOC,IAAAA,SAAS,KAAK,SAAS,KAAK,YAAY,IAAI;AAAA,EACrD;AAAA;AAAA,EAIA,MAAgB,gBAA8B;AAC5C,UAAM,QAAQ,MAAM,KAAK,UAAU,UAAU;AAC7C,WAAOC,IAAAA,UAAa,KAAK;AAAA,EAC3B;AAAA,EAEA,MAAgB,WAAW,IAAgC;AACzD,UAAM,QAAQ,MAAM,KAAK,UAAU,UAAU;AAC7C,WAAOC,IAAAA,OAAU,OAAO,EAAiB;AAAA,EAC3C;AAAA,EAEA,MAAgB,WAAW,OAA2B;AACpD,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAOC,IAAAA,OAAO,OAAO,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAgB,cAAc,KAA+B;AAC3D,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAOC,IAAAA,UAAU,OAAO,GAAoB;AAAA,EAC9C;AAAA,EAEA,MAAgB,eAA8B;AAC5C,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAOC,IAAAA,SAAS,KAAK;AAAA,EACvB;AACF;;"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { PersistentCollection } from "../PersistentCollection.js";
|
|
2
|
+
import { getStore, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from "./idb.js";
|
|
3
|
+
class IndexedDBCollection extends PersistentCollection {
|
|
4
|
+
/** IndexedDB database name. Override to use a separate database. */
|
|
5
|
+
static DB_NAME = "mvc-kit";
|
|
6
|
+
get _dbName() {
|
|
7
|
+
return this.constructor.DB_NAME;
|
|
8
|
+
}
|
|
9
|
+
_getStore(mode) {
|
|
10
|
+
return getStore(this._dbName, this.storageKey, mode);
|
|
11
|
+
}
|
|
12
|
+
// ── Persist interface (per-item strategy) ──
|
|
13
|
+
async persistGetAll() {
|
|
14
|
+
const store = await this._getStore("readonly");
|
|
15
|
+
return idbGetAll(store);
|
|
16
|
+
}
|
|
17
|
+
async persistGet(id) {
|
|
18
|
+
const store = await this._getStore("readonly");
|
|
19
|
+
return idbGet(store, id);
|
|
20
|
+
}
|
|
21
|
+
async persistSet(items) {
|
|
22
|
+
const store = await this._getStore("readwrite");
|
|
23
|
+
return idbPut(store, items);
|
|
24
|
+
}
|
|
25
|
+
async persistRemove(ids) {
|
|
26
|
+
const store = await this._getStore("readwrite");
|
|
27
|
+
return idbDelete(store, ids);
|
|
28
|
+
}
|
|
29
|
+
async persistClear() {
|
|
30
|
+
const store = await this._getStore("readwrite");
|
|
31
|
+
return idbClear(store);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
IndexedDBCollection
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=IndexedDBCollection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndexedDBCollection.js","sources":["../../src/web/IndexedDBCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\nimport { getStore, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from './idb';\n\n/**\n * PersistentCollection backed by IndexedDB. Stores items individually by `id`\n * in a dedicated object store (named by `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n * Typically called in ViewModel's `onInit()`.\n *\n * Uses per-item strategy: each item is stored as a separate entry in the object store.\n * No JSON serialization needed — IndexedDB uses structured cloning.\n *\n * ```ts\n * class MessagesCollection extends IndexedDBCollection<Message> {\n * protected readonly storageKey = 'messages';\n * }\n *\n * // In ViewModel:\n * async onInit() {\n * await this.collection.hydrate();\n * if (this.collection.length === 0) this.load();\n * }\n * ```\n */\nexport abstract class IndexedDBCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** IndexedDB database name. Override to use a separate database. */\n static DB_NAME = 'mvc-kit';\n\n private get _dbName(): string {\n return (this.constructor as typeof IndexedDBCollection).DB_NAME;\n }\n\n private _getStore(mode: IDBTransactionMode) {\n return getStore(this._dbName, this.storageKey, mode);\n }\n\n // ── Persist interface (per-item strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const store = await this._getStore('readonly');\n return idbGetAll<T>(store);\n }\n\n protected async persistGet(id: T['id']): Promise<T | null> {\n const store = await this._getStore('readonly');\n return idbGet<T>(store, id as IDBValidKey);\n }\n\n protected async persistSet(items: T[]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbPut(store, items);\n }\n\n protected async persistRemove(ids: T['id'][]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbDelete(store, ids as IDBValidKey[]);\n }\n\n protected async persistClear(): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbClear(store);\n }\n}\n"],"names":[],"mappings":";;AAyBO,MAAe,4BAEZ,qBAAwB;AAAA;AAAA,EAEhC,OAAO,UAAU;AAAA,EAEjB,IAAY,UAAkB;AAC5B,WAAQ,KAAK,YAA2C;AAAA,EAC1D;AAAA,EAEQ,UAAU,MAA0B;AAC1C,WAAO,SAAS,KAAK,SAAS,KAAK,YAAY,IAAI;AAAA,EACrD;AAAA;AAAA,EAIA,MAAgB,gBAA8B;AAC5C,UAAM,QAAQ,MAAM,KAAK,UAAU,UAAU;AAC7C,WAAO,UAAa,KAAK;AAAA,EAC3B;AAAA,EAEA,MAAgB,WAAW,IAAgC;AACzD,UAAM,QAAQ,MAAM,KAAK,UAAU,UAAU;AAC7C,WAAO,OAAU,OAAO,EAAiB;AAAA,EAC3C;AAAA,EAEA,MAAgB,WAAW,OAA2B;AACpD,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAO,OAAO,OAAO,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAgB,cAAc,KAA+B;AAC3D,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAO,UAAU,OAAO,GAAoB;AAAA,EAC9C;AAAA,EAEA,MAAgB,eAA8B;AAC5C,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAO,SAAS,KAAK;AAAA,EACvB;AACF;"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const PersistentCollection = require("../PersistentCollection.cjs");
|
|
4
|
+
const __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
|
|
5
|
+
class WebStorageCollection extends PersistentCollection.PersistentCollection {
|
|
6
|
+
/** Which Web Storage backend to use. Override to 'session' for sessionStorage. */
|
|
7
|
+
static STORAGE = "local";
|
|
8
|
+
_autoHydrated = false;
|
|
9
|
+
get _storage() {
|
|
10
|
+
return this.constructor.STORAGE === "session" ? sessionStorage : localStorage;
|
|
11
|
+
}
|
|
12
|
+
_ensureHydrated() {
|
|
13
|
+
if (this._autoHydrated) return;
|
|
14
|
+
this._autoHydrated = true;
|
|
15
|
+
this._hydrateSync();
|
|
16
|
+
}
|
|
17
|
+
// ── Override access points to trigger lazy hydration ──
|
|
18
|
+
get items() {
|
|
19
|
+
this._ensureHydrated();
|
|
20
|
+
return super.items;
|
|
21
|
+
}
|
|
22
|
+
get state() {
|
|
23
|
+
return this.items;
|
|
24
|
+
}
|
|
25
|
+
get length() {
|
|
26
|
+
this._ensureHydrated();
|
|
27
|
+
return super.length;
|
|
28
|
+
}
|
|
29
|
+
get(id) {
|
|
30
|
+
this._ensureHydrated();
|
|
31
|
+
return super.get(id);
|
|
32
|
+
}
|
|
33
|
+
has(id) {
|
|
34
|
+
this._ensureHydrated();
|
|
35
|
+
return super.has(id);
|
|
36
|
+
}
|
|
37
|
+
// ── Persist interface (blob strategy) ──
|
|
38
|
+
persistGetAll() {
|
|
39
|
+
const raw = this._storage.getItem(this.storageKey);
|
|
40
|
+
if (!raw) return [];
|
|
41
|
+
try {
|
|
42
|
+
return this.deserialize(raw);
|
|
43
|
+
} catch {
|
|
44
|
+
if (__DEV__) {
|
|
45
|
+
console.warn(
|
|
46
|
+
`[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
persistGet(id) {
|
|
53
|
+
const all = this.persistGetAll();
|
|
54
|
+
return all.find((i) => i.id === id) ?? null;
|
|
55
|
+
}
|
|
56
|
+
persistSet(_items) {
|
|
57
|
+
try {
|
|
58
|
+
this._storage.setItem(this.storageKey, this.serialize([...this.items]));
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") {
|
|
61
|
+
console.warn(
|
|
62
|
+
`[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
persistRemove(_ids) {
|
|
69
|
+
try {
|
|
70
|
+
this._storage.setItem(this.storageKey, this.serialize([...this.items]));
|
|
71
|
+
} catch (err) {
|
|
72
|
+
if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") {
|
|
73
|
+
console.warn(
|
|
74
|
+
`[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
persistClear() {
|
|
81
|
+
this._storage.removeItem(this.storageKey);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.WebStorageCollection = WebStorageCollection;
|
|
85
|
+
//# sourceMappingURL=WebStorageCollection.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebStorageCollection.cjs","sources":["../../src/web/WebStorageCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n/**\n * PersistentCollection backed by localStorage or sessionStorage.\n * Auto-hydrates on first access (sync storage — no need for manual `hydrate()` call).\n *\n * Uses blob strategy: all items stored as a single JSON string under `storageKey`.\n *\n * ```ts\n * class CartCollection extends WebStorageCollection<CartItem> {\n * protected readonly storageKey = 'cart';\n * }\n * ```\n */\nexport abstract class WebStorageCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */\n static STORAGE: 'local' | 'session' = 'local';\n\n private _autoHydrated = false;\n\n private get _storage(): Storage {\n return (this.constructor as typeof WebStorageCollection).STORAGE === 'session'\n ? sessionStorage\n : localStorage;\n }\n\n private _ensureHydrated(): void {\n if (this._autoHydrated) return;\n this._autoHydrated = true;\n this._hydrateSync();\n }\n\n // ── Override access points to trigger lazy hydration ──\n\n get items(): T[] {\n this._ensureHydrated();\n return super.items;\n }\n\n get state(): T[] {\n return this.items;\n }\n\n get length(): number {\n this._ensureHydrated();\n return super.length;\n }\n\n get(id: T['id']): T | undefined {\n this._ensureHydrated();\n return super.get(id);\n }\n\n has(id: T['id']): boolean {\n this._ensureHydrated();\n return super.has(id);\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected persistGetAll(): T[] {\n const raw = this._storage.getItem(this.storageKey);\n if (!raw) return [];\n try {\n return this.deserialize(raw);\n } catch {\n if (__DEV__) {\n console.warn(\n `[mvc-kit] Corrupted data in storage key \"${this.storageKey}\". Ignoring stored data.`,\n );\n }\n return [];\n }\n }\n\n protected persistGet(id: T['id']): T | null {\n const all = this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected persistSet(_items: T[]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistRemove(_ids: T['id'][]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistClear(): void {\n this._storage.removeItem(this.storageKey);\n }\n}\n"],"names":["PersistentCollection"],"mappings":";;;AAEA,MAAM,UAAU,OAAO,oBAAoB,eAAe;AAcnD,MAAe,6BAEZA,qBAAAA,qBAAwB;AAAA;AAAA,EAEhC,OAAO,UAA+B;AAAA,EAE9B,gBAAgB;AAAA,EAExB,IAAY,WAAoB;AAC9B,WAAQ,KAAK,YAA4C,YAAY,YACjE,iBACA;AAAA,EACN;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,KAAK,cAAe;AACxB,SAAK,gBAAgB;AACrB,SAAK,aAAA;AAAA,EACP;AAAA;AAAA,EAIA,IAAI,QAAa;AACf,SAAK,gBAAA;AACL,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,QAAa;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAiB;AACnB,SAAK,gBAAA;AACL,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,IAA4B;AAC9B,SAAK,gBAAA;AACL,WAAO,MAAM,IAAI,EAAE;AAAA,EACrB;AAAA,EAEA,IAAI,IAAsB;AACxB,SAAK,gBAAA;AACL,WAAO,MAAM,IAAI,EAAE;AAAA,EACrB;AAAA;AAAA,EAIU,gBAAqB;AAC7B,UAAM,MAAM,KAAK,SAAS,QAAQ,KAAK,UAAU;AACjD,QAAI,CAAC,IAAK,QAAO,CAAA;AACjB,QAAI;AACF,aAAO,KAAK,YAAY,GAAG;AAAA,IAC7B,QAAQ;AACN,UAAI,SAAS;AACX,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAE/D;AACA,aAAO,CAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEU,WAAW,IAAuB;AAC1C,UAAM,MAAM,KAAK,cAAA;AACjB,WAAO,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAAA,EACzC;AAAA,EAEU,WAAW,QAAmB;AACtC,QAAI;AACF,WAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,sBAAsB;AAC/E,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAG/D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,cAAc,MAAuB;AAC7C,QAAI;AACF,WAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,sBAAsB;AAC/E,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAG/D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,eAAqB;AAC7B,SAAK,SAAS,WAAW,KAAK,UAAU;AAAA,EAC1C;AACF;;"}
|
|
@@ -19,8 +19,8 @@ export declare abstract class WebStorageCollection<T extends {
|
|
|
19
19
|
private _autoHydrated;
|
|
20
20
|
private get _storage();
|
|
21
21
|
private _ensureHydrated;
|
|
22
|
-
get items():
|
|
23
|
-
get state():
|
|
22
|
+
get items(): T[];
|
|
23
|
+
get state(): T[];
|
|
24
24
|
get length(): number;
|
|
25
25
|
get(id: T['id']): T | undefined;
|
|
26
26
|
has(id: T['id']): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebStorageCollection.d.ts","sourceRoot":"","sources":["../../src/web/WebStorageCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAI/D;;;;;;;;;;;GAWG;AACH,8BAAsB,oBAAoB,CACxC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CACjC,SAAQ,oBAAoB,CAAC,CAAC,CAAC;IAC/B,kFAAkF;IAClF,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAW;IAE9C,OAAO,CAAC,aAAa,CAAS;IAE9B,OAAO,KAAK,QAAQ,GAInB;IAED,OAAO,CAAC,eAAe;IAQvB,IAAI,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"WebStorageCollection.d.ts","sourceRoot":"","sources":["../../src/web/WebStorageCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAI/D;;;;;;;;;;;GAWG;AACH,8BAAsB,oBAAoB,CACxC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CACjC,SAAQ,oBAAoB,CAAC,CAAC,CAAC;IAC/B,kFAAkF;IAClF,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAW;IAE9C,OAAO,CAAC,aAAa,CAAS;IAE9B,OAAO,KAAK,QAAQ,GAInB;IAED,OAAO,CAAC,eAAe;IAQvB,IAAI,KAAK,IAAI,CAAC,EAAE,CAGf;IAED,IAAI,KAAK,IAAI,CAAC,EAAE,CAEf;IAED,IAAI,MAAM,IAAI,MAAM,CAGnB;IAED,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS;IAK/B,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO;IAOzB,SAAS,CAAC,aAAa,IAAI,CAAC,EAAE;IAe9B,SAAS,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI;IAK3C,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI;IAcvC,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI;IAc9C,SAAS,CAAC,YAAY,IAAI,IAAI;CAG/B"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { PersistentCollection } from "../PersistentCollection.js";
|
|
2
|
+
const __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
|
|
3
|
+
class WebStorageCollection extends PersistentCollection {
|
|
4
|
+
/** Which Web Storage backend to use. Override to 'session' for sessionStorage. */
|
|
5
|
+
static STORAGE = "local";
|
|
6
|
+
_autoHydrated = false;
|
|
7
|
+
get _storage() {
|
|
8
|
+
return this.constructor.STORAGE === "session" ? sessionStorage : localStorage;
|
|
9
|
+
}
|
|
10
|
+
_ensureHydrated() {
|
|
11
|
+
if (this._autoHydrated) return;
|
|
12
|
+
this._autoHydrated = true;
|
|
13
|
+
this._hydrateSync();
|
|
14
|
+
}
|
|
15
|
+
// ── Override access points to trigger lazy hydration ──
|
|
16
|
+
get items() {
|
|
17
|
+
this._ensureHydrated();
|
|
18
|
+
return super.items;
|
|
19
|
+
}
|
|
20
|
+
get state() {
|
|
21
|
+
return this.items;
|
|
22
|
+
}
|
|
23
|
+
get length() {
|
|
24
|
+
this._ensureHydrated();
|
|
25
|
+
return super.length;
|
|
26
|
+
}
|
|
27
|
+
get(id) {
|
|
28
|
+
this._ensureHydrated();
|
|
29
|
+
return super.get(id);
|
|
30
|
+
}
|
|
31
|
+
has(id) {
|
|
32
|
+
this._ensureHydrated();
|
|
33
|
+
return super.has(id);
|
|
34
|
+
}
|
|
35
|
+
// ── Persist interface (blob strategy) ──
|
|
36
|
+
persistGetAll() {
|
|
37
|
+
const raw = this._storage.getItem(this.storageKey);
|
|
38
|
+
if (!raw) return [];
|
|
39
|
+
try {
|
|
40
|
+
return this.deserialize(raw);
|
|
41
|
+
} catch {
|
|
42
|
+
if (__DEV__) {
|
|
43
|
+
console.warn(
|
|
44
|
+
`[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
persistGet(id) {
|
|
51
|
+
const all = this.persistGetAll();
|
|
52
|
+
return all.find((i) => i.id === id) ?? null;
|
|
53
|
+
}
|
|
54
|
+
persistSet(_items) {
|
|
55
|
+
try {
|
|
56
|
+
this._storage.setItem(this.storageKey, this.serialize([...this.items]));
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") {
|
|
59
|
+
console.warn(
|
|
60
|
+
`[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
persistRemove(_ids) {
|
|
67
|
+
try {
|
|
68
|
+
this._storage.setItem(this.storageKey, this.serialize([...this.items]));
|
|
69
|
+
} catch (err) {
|
|
70
|
+
if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") {
|
|
71
|
+
console.warn(
|
|
72
|
+
`[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
persistClear() {
|
|
79
|
+
this._storage.removeItem(this.storageKey);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
WebStorageCollection
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=WebStorageCollection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebStorageCollection.js","sources":["../../src/web/WebStorageCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n/**\n * PersistentCollection backed by localStorage or sessionStorage.\n * Auto-hydrates on first access (sync storage — no need for manual `hydrate()` call).\n *\n * Uses blob strategy: all items stored as a single JSON string under `storageKey`.\n *\n * ```ts\n * class CartCollection extends WebStorageCollection<CartItem> {\n * protected readonly storageKey = 'cart';\n * }\n * ```\n */\nexport abstract class WebStorageCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */\n static STORAGE: 'local' | 'session' = 'local';\n\n private _autoHydrated = false;\n\n private get _storage(): Storage {\n return (this.constructor as typeof WebStorageCollection).STORAGE === 'session'\n ? sessionStorage\n : localStorage;\n }\n\n private _ensureHydrated(): void {\n if (this._autoHydrated) return;\n this._autoHydrated = true;\n this._hydrateSync();\n }\n\n // ── Override access points to trigger lazy hydration ──\n\n get items(): T[] {\n this._ensureHydrated();\n return super.items;\n }\n\n get state(): T[] {\n return this.items;\n }\n\n get length(): number {\n this._ensureHydrated();\n return super.length;\n }\n\n get(id: T['id']): T | undefined {\n this._ensureHydrated();\n return super.get(id);\n }\n\n has(id: T['id']): boolean {\n this._ensureHydrated();\n return super.has(id);\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected persistGetAll(): T[] {\n const raw = this._storage.getItem(this.storageKey);\n if (!raw) return [];\n try {\n return this.deserialize(raw);\n } catch {\n if (__DEV__) {\n console.warn(\n `[mvc-kit] Corrupted data in storage key \"${this.storageKey}\". Ignoring stored data.`,\n );\n }\n return [];\n }\n }\n\n protected persistGet(id: T['id']): T | null {\n const all = this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected persistSet(_items: T[]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistRemove(_ids: T['id'][]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistClear(): void {\n this._storage.removeItem(this.storageKey);\n }\n}\n"],"names":[],"mappings":";AAEA,MAAM,UAAU,OAAO,oBAAoB,eAAe;AAcnD,MAAe,6BAEZ,qBAAwB;AAAA;AAAA,EAEhC,OAAO,UAA+B;AAAA,EAE9B,gBAAgB;AAAA,EAExB,IAAY,WAAoB;AAC9B,WAAQ,KAAK,YAA4C,YAAY,YACjE,iBACA;AAAA,EACN;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,KAAK,cAAe;AACxB,SAAK,gBAAgB;AACrB,SAAK,aAAA;AAAA,EACP;AAAA;AAAA,EAIA,IAAI,QAAa;AACf,SAAK,gBAAA;AACL,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,QAAa;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAiB;AACnB,SAAK,gBAAA;AACL,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,IAA4B;AAC9B,SAAK,gBAAA;AACL,WAAO,MAAM,IAAI,EAAE;AAAA,EACrB;AAAA,EAEA,IAAI,IAAsB;AACxB,SAAK,gBAAA;AACL,WAAO,MAAM,IAAI,EAAE;AAAA,EACrB;AAAA;AAAA,EAIU,gBAAqB;AAC7B,UAAM,MAAM,KAAK,SAAS,QAAQ,KAAK,UAAU;AACjD,QAAI,CAAC,IAAK,QAAO,CAAA;AACjB,QAAI;AACF,aAAO,KAAK,YAAY,GAAG;AAAA,IAC7B,QAAQ;AACN,UAAI,SAAS;AACX,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAE/D;AACA,aAAO,CAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEU,WAAW,IAAuB;AAC1C,UAAM,MAAM,KAAK,cAAA;AACjB,WAAO,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAAA,EACzC;AAAA,EAEU,WAAW,QAAmB;AACtC,QAAI;AACF,WAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,sBAAsB;AAC/E,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAG/D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,cAAc,MAAuB;AAC7C,QAAI;AACF,WAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,sBAAsB;AAC/E,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAG/D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,eAAqB;AAC7B,SAAK,SAAS,WAAW,KAAK,UAAU;AAAA,EAC1C;AACF;"}
|
package/dist/web/idb.cjs
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const _connections = /* @__PURE__ */ new Map();
|
|
4
|
+
const _stores = /* @__PURE__ */ new Map();
|
|
5
|
+
let _openQueue = Promise.resolve();
|
|
6
|
+
function openDB(dbName, storeName) {
|
|
7
|
+
const existing = _connections.get(dbName);
|
|
8
|
+
if (existing) {
|
|
9
|
+
if (existing.objectStoreNames.contains(storeName)) {
|
|
10
|
+
return Promise.resolve(existing);
|
|
11
|
+
}
|
|
12
|
+
existing.close();
|
|
13
|
+
_connections.delete(dbName);
|
|
14
|
+
}
|
|
15
|
+
let stores = _stores.get(dbName);
|
|
16
|
+
if (!stores) {
|
|
17
|
+
stores = /* @__PURE__ */ new Set();
|
|
18
|
+
_stores.set(dbName, stores);
|
|
19
|
+
}
|
|
20
|
+
stores.add(storeName);
|
|
21
|
+
const result = _openQueue.then(() => doOpen(dbName, stores));
|
|
22
|
+
_openQueue = result.then(() => {
|
|
23
|
+
}, () => {
|
|
24
|
+
});
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
function doOpen(dbName, stores) {
|
|
28
|
+
const existingDb = _connections.get(dbName);
|
|
29
|
+
existingDb?.close();
|
|
30
|
+
_connections.delete(dbName);
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const probe = indexedDB.open(dbName);
|
|
33
|
+
probe.onsuccess = () => {
|
|
34
|
+
const db = probe.result;
|
|
35
|
+
const version = db.version;
|
|
36
|
+
let needsUpgrade = false;
|
|
37
|
+
for (const name of stores) {
|
|
38
|
+
if (!db.objectStoreNames.contains(name)) {
|
|
39
|
+
needsUpgrade = true;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!needsUpgrade) {
|
|
44
|
+
_connections.set(dbName, db);
|
|
45
|
+
resolve(db);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
db.close();
|
|
49
|
+
const upgrade = indexedDB.open(dbName, version + 1);
|
|
50
|
+
upgrade.onupgradeneeded = () => {
|
|
51
|
+
const udb = upgrade.result;
|
|
52
|
+
for (const name of stores) {
|
|
53
|
+
if (!udb.objectStoreNames.contains(name)) {
|
|
54
|
+
udb.createObjectStore(name, { keyPath: "id" });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
upgrade.onsuccess = () => {
|
|
59
|
+
_connections.set(dbName, upgrade.result);
|
|
60
|
+
resolve(upgrade.result);
|
|
61
|
+
};
|
|
62
|
+
upgrade.onerror = () => reject(upgrade.error);
|
|
63
|
+
};
|
|
64
|
+
probe.onerror = () => reject(probe.error);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function getStore(dbName, storeName, mode) {
|
|
68
|
+
return openDB(dbName, storeName).then((db) => {
|
|
69
|
+
const tx = db.transaction(storeName, mode);
|
|
70
|
+
return tx.objectStore(storeName);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function idbGetAll(store) {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const request = store.getAll();
|
|
76
|
+
request.onsuccess = () => resolve(request.result);
|
|
77
|
+
request.onerror = () => reject(request.error);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function idbGet(store, id) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const request = store.get(id);
|
|
83
|
+
request.onsuccess = () => resolve(request.result ?? null);
|
|
84
|
+
request.onerror = () => reject(request.error);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function idbPut(store, items) {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const tx = store.transaction;
|
|
90
|
+
for (const item of items) {
|
|
91
|
+
store.put(item);
|
|
92
|
+
}
|
|
93
|
+
tx.oncomplete = () => resolve();
|
|
94
|
+
tx.onerror = () => reject(tx.error);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function idbDelete(store, ids) {
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
const tx = store.transaction;
|
|
100
|
+
for (const id of ids) {
|
|
101
|
+
store.delete(id);
|
|
102
|
+
}
|
|
103
|
+
tx.oncomplete = () => resolve();
|
|
104
|
+
tx.onerror = () => reject(tx.error);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function idbClear(store) {
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
const tx = store.transaction;
|
|
110
|
+
store.clear();
|
|
111
|
+
tx.oncomplete = () => resolve();
|
|
112
|
+
tx.onerror = () => reject(tx.error);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
exports.getStore = getStore;
|
|
116
|
+
exports.idbClear = idbClear;
|
|
117
|
+
exports.idbDelete = idbDelete;
|
|
118
|
+
exports.idbGet = idbGet;
|
|
119
|
+
exports.idbGetAll = idbGetAll;
|
|
120
|
+
exports.idbPut = idbPut;
|
|
121
|
+
//# sourceMappingURL=idb.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idb.cjs","sources":["../../src/web/idb.ts"],"sourcesContent":["/**\n * Shared IndexedDB connection manager.\n * Deduplicates indexedDB.open() calls and handles dynamic object store creation\n * by bumping the DB version when a new storageKey is encountered.\n */\n\nconst _connections = new Map<string, IDBDatabase>();\nconst _stores = new Map<string, Set<string>>(); // dbName → known store names\nlet _openQueue: Promise<void> = Promise.resolve(); // Sequential open queue\n\nfunction openDB(dbName: string, storeName: string): Promise<IDBDatabase> {\n // If we already have a connection with the required store, reuse it\n const existing = _connections.get(dbName);\n if (existing) {\n if (existing.objectStoreNames.contains(storeName)) {\n return Promise.resolve(existing);\n }\n // Need to add a new store — close and reopen with bumped version\n existing.close();\n _connections.delete(dbName);\n }\n\n // Track known stores\n let stores = _stores.get(dbName);\n if (!stores) {\n stores = new Set();\n _stores.set(dbName, stores);\n }\n stores.add(storeName);\n\n // Serialize opens to prevent version conflicts\n const result = _openQueue.then(() => doOpen(dbName, stores!));\n _openQueue = result.then(() => {}, () => {}); // Absorb errors for the queue\n return result;\n}\n\nfunction doOpen(dbName: string, stores: Set<string>): Promise<IDBDatabase> {\n // Close existing cached connection if any (may have been opened by queued op)\n const existingDb = _connections.get(dbName);\n existingDb?.close();\n _connections.delete(dbName);\n\n // Probe current DB version (version-less open never triggers upgrade)\n return new Promise<IDBDatabase>((resolve, reject) => {\n const probe = indexedDB.open(dbName);\n probe.onsuccess = () => {\n const db = probe.result;\n const version = db.version;\n\n // Check if all required stores already exist\n let needsUpgrade = false;\n for (const name of stores) {\n if (!db.objectStoreNames.contains(name)) {\n needsUpgrade = true;\n break;\n }\n }\n\n if (!needsUpgrade) {\n _connections.set(dbName, db);\n resolve(db);\n return;\n }\n\n // Need new stores — close and reopen with bumped version\n db.close();\n const upgrade = indexedDB.open(dbName, version + 1);\n upgrade.onupgradeneeded = () => {\n const udb = upgrade.result;\n for (const name of stores) {\n if (!udb.objectStoreNames.contains(name)) {\n udb.createObjectStore(name, { keyPath: 'id' });\n }\n }\n };\n upgrade.onsuccess = () => {\n _connections.set(dbName, upgrade.result);\n resolve(upgrade.result);\n };\n upgrade.onerror = () => reject(upgrade.error);\n };\n probe.onerror = () => reject(probe.error);\n });\n}\n\nexport function getStore(\n dbName: string,\n storeName: string,\n mode: IDBTransactionMode,\n): Promise<IDBObjectStore> {\n return openDB(dbName, storeName).then((db) => {\n const tx = db.transaction(storeName, mode);\n return tx.objectStore(storeName);\n });\n}\n\nexport function idbGetAll<T>(store: IDBObjectStore): Promise<T[]> {\n return new Promise((resolve, reject) => {\n const request = store.getAll();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport function idbGet<T>(store: IDBObjectStore, id: IDBValidKey): Promise<T | null> {\n return new Promise((resolve, reject) => {\n const request = store.get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport function idbPut<T>(store: IDBObjectStore, items: T[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n for (const item of items) {\n store.put(item);\n }\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nexport function idbDelete(store: IDBObjectStore, ids: IDBValidKey[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n for (const id of ids) {\n store.delete(id);\n }\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nexport function idbClear(store: IDBObjectStore): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n store.clear();\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Close all cached connections and delete all known databases. Used in test cleanup. */\nexport function closeAllConnections(): void {\n for (const db of _connections.values()) {\n db.close();\n }\n _connections.clear();\n _stores.clear();\n _openQueue = Promise.resolve();\n}\n\n/** Delete a database by name. Returns a promise that resolves when deleted. */\nexport function deleteDatabase(dbName: string): Promise<void> {\n const existing = _connections.get(dbName);\n existing?.close();\n _connections.delete(dbName);\n _stores.delete(dbName);\n\n return new Promise((resolve, reject) => {\n const request = indexedDB.deleteDatabase(dbName);\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n}\n"],"names":[],"mappings":"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"}
|
package/dist/web/idb.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const _connections = /* @__PURE__ */ new Map();
|
|
2
|
+
const _stores = /* @__PURE__ */ new Map();
|
|
3
|
+
let _openQueue = Promise.resolve();
|
|
4
|
+
function openDB(dbName, storeName) {
|
|
5
|
+
const existing = _connections.get(dbName);
|
|
6
|
+
if (existing) {
|
|
7
|
+
if (existing.objectStoreNames.contains(storeName)) {
|
|
8
|
+
return Promise.resolve(existing);
|
|
9
|
+
}
|
|
10
|
+
existing.close();
|
|
11
|
+
_connections.delete(dbName);
|
|
12
|
+
}
|
|
13
|
+
let stores = _stores.get(dbName);
|
|
14
|
+
if (!stores) {
|
|
15
|
+
stores = /* @__PURE__ */ new Set();
|
|
16
|
+
_stores.set(dbName, stores);
|
|
17
|
+
}
|
|
18
|
+
stores.add(storeName);
|
|
19
|
+
const result = _openQueue.then(() => doOpen(dbName, stores));
|
|
20
|
+
_openQueue = result.then(() => {
|
|
21
|
+
}, () => {
|
|
22
|
+
});
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
function doOpen(dbName, stores) {
|
|
26
|
+
const existingDb = _connections.get(dbName);
|
|
27
|
+
existingDb?.close();
|
|
28
|
+
_connections.delete(dbName);
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const probe = indexedDB.open(dbName);
|
|
31
|
+
probe.onsuccess = () => {
|
|
32
|
+
const db = probe.result;
|
|
33
|
+
const version = db.version;
|
|
34
|
+
let needsUpgrade = false;
|
|
35
|
+
for (const name of stores) {
|
|
36
|
+
if (!db.objectStoreNames.contains(name)) {
|
|
37
|
+
needsUpgrade = true;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!needsUpgrade) {
|
|
42
|
+
_connections.set(dbName, db);
|
|
43
|
+
resolve(db);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
db.close();
|
|
47
|
+
const upgrade = indexedDB.open(dbName, version + 1);
|
|
48
|
+
upgrade.onupgradeneeded = () => {
|
|
49
|
+
const udb = upgrade.result;
|
|
50
|
+
for (const name of stores) {
|
|
51
|
+
if (!udb.objectStoreNames.contains(name)) {
|
|
52
|
+
udb.createObjectStore(name, { keyPath: "id" });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
upgrade.onsuccess = () => {
|
|
57
|
+
_connections.set(dbName, upgrade.result);
|
|
58
|
+
resolve(upgrade.result);
|
|
59
|
+
};
|
|
60
|
+
upgrade.onerror = () => reject(upgrade.error);
|
|
61
|
+
};
|
|
62
|
+
probe.onerror = () => reject(probe.error);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function getStore(dbName, storeName, mode) {
|
|
66
|
+
return openDB(dbName, storeName).then((db) => {
|
|
67
|
+
const tx = db.transaction(storeName, mode);
|
|
68
|
+
return tx.objectStore(storeName);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function idbGetAll(store) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
const request = store.getAll();
|
|
74
|
+
request.onsuccess = () => resolve(request.result);
|
|
75
|
+
request.onerror = () => reject(request.error);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function idbGet(store, id) {
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const request = store.get(id);
|
|
81
|
+
request.onsuccess = () => resolve(request.result ?? null);
|
|
82
|
+
request.onerror = () => reject(request.error);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function idbPut(store, items) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const tx = store.transaction;
|
|
88
|
+
for (const item of items) {
|
|
89
|
+
store.put(item);
|
|
90
|
+
}
|
|
91
|
+
tx.oncomplete = () => resolve();
|
|
92
|
+
tx.onerror = () => reject(tx.error);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function idbDelete(store, ids) {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
const tx = store.transaction;
|
|
98
|
+
for (const id of ids) {
|
|
99
|
+
store.delete(id);
|
|
100
|
+
}
|
|
101
|
+
tx.oncomplete = () => resolve();
|
|
102
|
+
tx.onerror = () => reject(tx.error);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function idbClear(store) {
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
const tx = store.transaction;
|
|
108
|
+
store.clear();
|
|
109
|
+
tx.oncomplete = () => resolve();
|
|
110
|
+
tx.onerror = () => reject(tx.error);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
export {
|
|
114
|
+
getStore,
|
|
115
|
+
idbClear,
|
|
116
|
+
idbDelete,
|
|
117
|
+
idbGet,
|
|
118
|
+
idbGetAll,
|
|
119
|
+
idbPut
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=idb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idb.js","sources":["../../src/web/idb.ts"],"sourcesContent":["/**\n * Shared IndexedDB connection manager.\n * Deduplicates indexedDB.open() calls and handles dynamic object store creation\n * by bumping the DB version when a new storageKey is encountered.\n */\n\nconst _connections = new Map<string, IDBDatabase>();\nconst _stores = new Map<string, Set<string>>(); // dbName → known store names\nlet _openQueue: Promise<void> = Promise.resolve(); // Sequential open queue\n\nfunction openDB(dbName: string, storeName: string): Promise<IDBDatabase> {\n // If we already have a connection with the required store, reuse it\n const existing = _connections.get(dbName);\n if (existing) {\n if (existing.objectStoreNames.contains(storeName)) {\n return Promise.resolve(existing);\n }\n // Need to add a new store — close and reopen with bumped version\n existing.close();\n _connections.delete(dbName);\n }\n\n // Track known stores\n let stores = _stores.get(dbName);\n if (!stores) {\n stores = new Set();\n _stores.set(dbName, stores);\n }\n stores.add(storeName);\n\n // Serialize opens to prevent version conflicts\n const result = _openQueue.then(() => doOpen(dbName, stores!));\n _openQueue = result.then(() => {}, () => {}); // Absorb errors for the queue\n return result;\n}\n\nfunction doOpen(dbName: string, stores: Set<string>): Promise<IDBDatabase> {\n // Close existing cached connection if any (may have been opened by queued op)\n const existingDb = _connections.get(dbName);\n existingDb?.close();\n _connections.delete(dbName);\n\n // Probe current DB version (version-less open never triggers upgrade)\n return new Promise<IDBDatabase>((resolve, reject) => {\n const probe = indexedDB.open(dbName);\n probe.onsuccess = () => {\n const db = probe.result;\n const version = db.version;\n\n // Check if all required stores already exist\n let needsUpgrade = false;\n for (const name of stores) {\n if (!db.objectStoreNames.contains(name)) {\n needsUpgrade = true;\n break;\n }\n }\n\n if (!needsUpgrade) {\n _connections.set(dbName, db);\n resolve(db);\n return;\n }\n\n // Need new stores — close and reopen with bumped version\n db.close();\n const upgrade = indexedDB.open(dbName, version + 1);\n upgrade.onupgradeneeded = () => {\n const udb = upgrade.result;\n for (const name of stores) {\n if (!udb.objectStoreNames.contains(name)) {\n udb.createObjectStore(name, { keyPath: 'id' });\n }\n }\n };\n upgrade.onsuccess = () => {\n _connections.set(dbName, upgrade.result);\n resolve(upgrade.result);\n };\n upgrade.onerror = () => reject(upgrade.error);\n };\n probe.onerror = () => reject(probe.error);\n });\n}\n\nexport function getStore(\n dbName: string,\n storeName: string,\n mode: IDBTransactionMode,\n): Promise<IDBObjectStore> {\n return openDB(dbName, storeName).then((db) => {\n const tx = db.transaction(storeName, mode);\n return tx.objectStore(storeName);\n });\n}\n\nexport function idbGetAll<T>(store: IDBObjectStore): Promise<T[]> {\n return new Promise((resolve, reject) => {\n const request = store.getAll();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport function idbGet<T>(store: IDBObjectStore, id: IDBValidKey): Promise<T | null> {\n return new Promise((resolve, reject) => {\n const request = store.get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport function idbPut<T>(store: IDBObjectStore, items: T[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n for (const item of items) {\n store.put(item);\n }\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nexport function idbDelete(store: IDBObjectStore, ids: IDBValidKey[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n for (const id of ids) {\n store.delete(id);\n }\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nexport function idbClear(store: IDBObjectStore): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n store.clear();\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Close all cached connections and delete all known databases. Used in test cleanup. */\nexport function closeAllConnections(): void {\n for (const db of _connections.values()) {\n db.close();\n }\n _connections.clear();\n _stores.clear();\n _openQueue = Promise.resolve();\n}\n\n/** Delete a database by name. Returns a promise that resolves when deleted. */\nexport function deleteDatabase(dbName: string): Promise<void> {\n const existing = _connections.get(dbName);\n existing?.close();\n _connections.delete(dbName);\n _stores.delete(dbName);\n\n return new Promise((resolve, reject) => {\n const request = indexedDB.deleteDatabase(dbName);\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n}\n"],"names":[],"mappings":"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"}
|
package/dist/web.cjs
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const WebStorageCollection = require("./web/WebStorageCollection.cjs");
|
|
4
|
+
const IndexedDBCollection = require("./web/IndexedDBCollection.cjs");
|
|
5
|
+
exports.WebStorageCollection = WebStorageCollection.WebStorageCollection;
|
|
6
|
+
exports.IndexedDBCollection = IndexedDBCollection.IndexedDBCollection;
|
|
2
7
|
//# sourceMappingURL=web.cjs.map
|
package/dist/web.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.cjs","sources":["../src/web/WebStorageCollection.ts","../src/web/idb.ts","../src/web/IndexedDBCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n/**\n * PersistentCollection backed by localStorage or sessionStorage.\n * Auto-hydrates on first access (sync storage — no need for manual `hydrate()` call).\n *\n * Uses blob strategy: all items stored as a single JSON string under `storageKey`.\n *\n * ```ts\n * class CartCollection extends WebStorageCollection<CartItem> {\n * protected readonly storageKey = 'cart';\n * }\n * ```\n */\nexport abstract class WebStorageCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */\n static STORAGE: 'local' | 'session' = 'local';\n\n private _autoHydrated = false;\n\n private get _storage(): Storage {\n return (this.constructor as typeof WebStorageCollection).STORAGE === 'session'\n ? sessionStorage\n : localStorage;\n }\n\n private _ensureHydrated(): void {\n if (this._autoHydrated) return;\n this._autoHydrated = true;\n this._hydrateSync();\n }\n\n // ── Override access points to trigger lazy hydration ──\n\n get items(): readonly T[] {\n this._ensureHydrated();\n return super.items;\n }\n\n get state(): readonly T[] {\n return this.items;\n }\n\n get length(): number {\n this._ensureHydrated();\n return super.length;\n }\n\n get(id: T['id']): T | undefined {\n this._ensureHydrated();\n return super.get(id);\n }\n\n has(id: T['id']): boolean {\n this._ensureHydrated();\n return super.has(id);\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected persistGetAll(): T[] {\n const raw = this._storage.getItem(this.storageKey);\n if (!raw) return [];\n try {\n return this.deserialize(raw);\n } catch {\n if (__DEV__) {\n console.warn(\n `[mvc-kit] Corrupted data in storage key \"${this.storageKey}\". Ignoring stored data.`,\n );\n }\n return [];\n }\n }\n\n protected persistGet(id: T['id']): T | null {\n const all = this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected persistSet(_items: T[]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistRemove(_ids: T['id'][]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistClear(): void {\n this._storage.removeItem(this.storageKey);\n }\n}\n","/**\n * Shared IndexedDB connection manager.\n * Deduplicates indexedDB.open() calls and handles dynamic object store creation\n * by bumping the DB version when a new storageKey is encountered.\n */\n\nconst _connections = new Map<string, IDBDatabase>();\nconst _stores = new Map<string, Set<string>>(); // dbName → known store names\nlet _openQueue: Promise<void> = Promise.resolve(); // Sequential open queue\n\nfunction openDB(dbName: string, storeName: string): Promise<IDBDatabase> {\n // If we already have a connection with the required store, reuse it\n const existing = _connections.get(dbName);\n if (existing) {\n if (existing.objectStoreNames.contains(storeName)) {\n return Promise.resolve(existing);\n }\n // Need to add a new store — close and reopen with bumped version\n existing.close();\n _connections.delete(dbName);\n }\n\n // Track known stores\n let stores = _stores.get(dbName);\n if (!stores) {\n stores = new Set();\n _stores.set(dbName, stores);\n }\n stores.add(storeName);\n\n // Serialize opens to prevent version conflicts\n const result = _openQueue.then(() => doOpen(dbName, stores!));\n _openQueue = result.then(() => {}, () => {}); // Absorb errors for the queue\n return result;\n}\n\nfunction doOpen(dbName: string, stores: Set<string>): Promise<IDBDatabase> {\n // Close existing cached connection if any (may have been opened by queued op)\n const existingDb = _connections.get(dbName);\n existingDb?.close();\n _connections.delete(dbName);\n\n // Probe current DB version (version-less open never triggers upgrade)\n return new Promise<IDBDatabase>((resolve, reject) => {\n const probe = indexedDB.open(dbName);\n probe.onsuccess = () => {\n const db = probe.result;\n const version = db.version;\n\n // Check if all required stores already exist\n let needsUpgrade = false;\n for (const name of stores) {\n if (!db.objectStoreNames.contains(name)) {\n needsUpgrade = true;\n break;\n }\n }\n\n if (!needsUpgrade) {\n _connections.set(dbName, db);\n resolve(db);\n return;\n }\n\n // Need new stores — close and reopen with bumped version\n db.close();\n const upgrade = indexedDB.open(dbName, version + 1);\n upgrade.onupgradeneeded = () => {\n const udb = upgrade.result;\n for (const name of stores) {\n if (!udb.objectStoreNames.contains(name)) {\n udb.createObjectStore(name, { keyPath: 'id' });\n }\n }\n };\n upgrade.onsuccess = () => {\n _connections.set(dbName, upgrade.result);\n resolve(upgrade.result);\n };\n upgrade.onerror = () => reject(upgrade.error);\n };\n probe.onerror = () => reject(probe.error);\n });\n}\n\nexport function getStore(\n dbName: string,\n storeName: string,\n mode: IDBTransactionMode,\n): Promise<IDBObjectStore> {\n return openDB(dbName, storeName).then((db) => {\n const tx = db.transaction(storeName, mode);\n return tx.objectStore(storeName);\n });\n}\n\nexport function idbGetAll<T>(store: IDBObjectStore): Promise<T[]> {\n return new Promise((resolve, reject) => {\n const request = store.getAll();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport function idbGet<T>(store: IDBObjectStore, id: IDBValidKey): Promise<T | null> {\n return new Promise((resolve, reject) => {\n const request = store.get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport function idbPut<T>(store: IDBObjectStore, items: T[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n for (const item of items) {\n store.put(item);\n }\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nexport function idbDelete(store: IDBObjectStore, ids: IDBValidKey[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n for (const id of ids) {\n store.delete(id);\n }\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nexport function idbClear(store: IDBObjectStore): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = store.transaction;\n store.clear();\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Close all cached connections and delete all known databases. Used in test cleanup. */\nexport function closeAllConnections(): void {\n for (const db of _connections.values()) {\n db.close();\n }\n _connections.clear();\n _stores.clear();\n _openQueue = Promise.resolve();\n}\n\n/** Delete a database by name. Returns a promise that resolves when deleted. */\nexport function deleteDatabase(dbName: string): Promise<void> {\n const existing = _connections.get(dbName);\n existing?.close();\n _connections.delete(dbName);\n _stores.delete(dbName);\n\n return new Promise((resolve, reject) => {\n const request = indexedDB.deleteDatabase(dbName);\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n}\n","import { PersistentCollection } from '../PersistentCollection';\nimport { getStore, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from './idb';\n\n/**\n * PersistentCollection backed by IndexedDB. Stores items individually by `id`\n * in a dedicated object store (named by `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n * Typically called in ViewModel's `onInit()`.\n *\n * Uses per-item strategy: each item is stored as a separate entry in the object store.\n * No JSON serialization needed — IndexedDB uses structured cloning.\n *\n * ```ts\n * class MessagesCollection extends IndexedDBCollection<Message> {\n * protected readonly storageKey = 'messages';\n * }\n *\n * // In ViewModel:\n * async onInit() {\n * await this.collection.hydrate();\n * if (this.collection.length === 0) this.load();\n * }\n * ```\n */\nexport abstract class IndexedDBCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** IndexedDB database name. Override to use a separate database. */\n static DB_NAME = 'mvc-kit';\n\n private get _dbName(): string {\n return (this.constructor as typeof IndexedDBCollection).DB_NAME;\n }\n\n private _getStore(mode: IDBTransactionMode) {\n return getStore(this._dbName, this.storageKey, mode);\n }\n\n // ── Persist interface (per-item strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const store = await this._getStore('readonly');\n return idbGetAll<T>(store);\n }\n\n protected async persistGet(id: T['id']): Promise<T | null> {\n const store = await this._getStore('readonly');\n return idbGet<T>(store, id as IDBValidKey);\n }\n\n protected async persistSet(items: T[]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbPut(store, items);\n }\n\n protected async persistRemove(ids: T['id'][]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbDelete(store, ids as IDBValidKey[]);\n }\n\n protected async persistClear(): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbClear(store);\n }\n}\n"],"names":["__DEV__","WebStorageCollection","PersistentCollection","id","raw","i","_items","err","_ids","_connections","_stores","_openQueue","openDB","dbName","storeName","existing","stores","result","doOpen","resolve","reject","probe","db","version","needsUpgrade","name","upgrade","udb","getStore","mode","idbGetAll","store","request","idbGet","idbPut","items","tx","item","idbDelete","ids","idbClear","IndexedDBCollection"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"web.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|