@orkestrel/indexeddb 0.0.1 → 0.0.2
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/src/browser/index.d.ts +753 -11
- package/dist/src/browser/index.js +50 -112
- package/dist/src/browser/index.js.map +1 -1
- package/package.json +5 -2
- package/dist/src/browser/IndexedDBCursor.d.ts +0 -28
- package/dist/src/browser/IndexedDBDatabase.d.ts +0 -27
- package/dist/src/browser/IndexedDBIndex.d.ts +0 -31
- package/dist/src/browser/IndexedDBStore.d.ts +0 -41
- package/dist/src/browser/IndexedDBTransaction.d.ts +0 -24
- package/dist/src/browser/IndexedDBTransactionStore.d.ts +0 -34
- package/dist/src/browser/constants.d.ts +0 -10
- package/dist/src/browser/errors.d.ts +0 -30
- package/dist/src/browser/factories.d.ts +0 -30
- package/dist/src/browser/helpers.d.ts +0 -130
- package/dist/src/browser/types.d.ts +0 -290
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isArray, isRecord } from "@orkestrel/contract";
|
|
1
2
|
//#region src/browser/constants.ts
|
|
2
3
|
/**
|
|
3
4
|
* Native `DOMException.name` → our {@link IndexedDBErrorCode}.
|
|
@@ -13,9 +14,11 @@ var ERROR_CODES = Object.freeze({
|
|
|
13
14
|
AbortError: "ABORTED",
|
|
14
15
|
NotFoundError: "NOT_FOUND",
|
|
15
16
|
DataError: "DATA",
|
|
17
|
+
DataCloneError: "DATA",
|
|
16
18
|
VersionError: "UPGRADE",
|
|
17
19
|
TransactionInactiveError: "INACTIVE",
|
|
18
|
-
InvalidStateError: "INVALID"
|
|
20
|
+
InvalidStateError: "INVALID",
|
|
21
|
+
ReadOnlyError: "READONLY"
|
|
19
22
|
});
|
|
20
23
|
//#endregion
|
|
21
24
|
//#region src/browser/errors.ts
|
|
@@ -54,99 +57,6 @@ var IndexedDBError = class extends Error {
|
|
|
54
57
|
function isIndexedDBError(value) {
|
|
55
58
|
return value instanceof IndexedDBError;
|
|
56
59
|
}
|
|
57
|
-
Object.freeze([
|
|
58
|
-
"null",
|
|
59
|
-
"boolean",
|
|
60
|
-
"object",
|
|
61
|
-
"array",
|
|
62
|
-
"number",
|
|
63
|
-
"integer",
|
|
64
|
-
"string"
|
|
65
|
-
]);
|
|
66
|
-
/**
|
|
67
|
-
* Determine whether a value is a non-null object.
|
|
68
|
-
*
|
|
69
|
-
* @remarks
|
|
70
|
-
* `true` for arrays, class instances, plain objects, `Map`, `Set`, etc. — use
|
|
71
|
-
* {@link isRecord} when you need a plain-record check.
|
|
72
|
-
*/
|
|
73
|
-
function isObject(value) {
|
|
74
|
-
return typeof value === "object" && value !== null;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Determine whether a value is a plain record (object literal or null-prototype),
|
|
78
|
-
* not an array or class instance.
|
|
79
|
-
*
|
|
80
|
-
* @remarks
|
|
81
|
-
* Use instead of {@link isObject} to distinguish a plain `{}` /
|
|
82
|
-
* `Object.create(null)` from arrays, `Date`, `Map`, etc. The prototype-chain
|
|
83
|
-
* test is realm-agnostic: rather than comparing against the current realm's
|
|
84
|
-
* `Object.prototype` (which a plain object from another `vm.Context`, iframe,
|
|
85
|
-
* or worker would fail), it accepts any value whose prototype is `null`, OR
|
|
86
|
-
* whose prototype's own prototype is `null` — the shape every plain object
|
|
87
|
-
* has in every realm, since `Object.prototype` itself always sits one step
|
|
88
|
-
* above `null`. Arrays and class instances are still rejected: an array's
|
|
89
|
-
* prototype chain runs through `Array.prototype` before `null`, and a class
|
|
90
|
-
* instance's runs through the class's own prototype. The whole body runs
|
|
91
|
-
* inside `attempt` (AGENTS §14) so a revoked `Proxy` or a hostile
|
|
92
|
-
* `getPrototypeOf` trap cannot escape as a thrown error.
|
|
93
|
-
*/
|
|
94
|
-
function isRecord(value) {
|
|
95
|
-
const outcome = attempt(() => {
|
|
96
|
-
if (!isObject(value) || isArray(value)) return false;
|
|
97
|
-
const prototype = Object.getPrototypeOf(value);
|
|
98
|
-
return prototype === null || Object.getPrototypeOf(prototype) === null;
|
|
99
|
-
});
|
|
100
|
-
return outcome.success && outcome.value;
|
|
101
|
-
}
|
|
102
|
-
/** Determine whether a value is an array. */
|
|
103
|
-
function isArray(value) {
|
|
104
|
-
return Array.isArray(value);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Invoke a callback and capture its outcome as a {@link Result}, never letting
|
|
108
|
-
* a throw escape.
|
|
109
|
-
*
|
|
110
|
-
* @remarks
|
|
111
|
-
* The single sanctioned never-throw boundary for the guards (AGENTS §14). The
|
|
112
|
-
* `whereOf`, `lazyOf`, and `transformOf` combinators invoke caller-supplied
|
|
113
|
-
* callbacks *inside* a guard body, yet a guard must NEVER throw — it returns a
|
|
114
|
-
* `boolean`. This converts a throwing callback into a `Failure` so the
|
|
115
|
-
* surrounding guard can treat it as a non-match instead of propagating the
|
|
116
|
-
* exception, written once and shared rather than copy-pasted as ad-hoc
|
|
117
|
-
* `try`/`catch`.
|
|
118
|
-
*
|
|
119
|
-
* @param callback - The callback to invoke with no arguments
|
|
120
|
-
* @returns A `Success` carrying the return value, or a `Failure` carrying the
|
|
121
|
-
* thrown reason normalised to an `Error`
|
|
122
|
-
*
|
|
123
|
-
* @example
|
|
124
|
-
* ```ts
|
|
125
|
-
* const outcome = attempt(() => predicate(value))
|
|
126
|
-
* return outcome.success && outcome.value
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
|
-
function attempt(callback) {
|
|
130
|
-
try {
|
|
131
|
-
return {
|
|
132
|
-
success: true,
|
|
133
|
-
value: callback()
|
|
134
|
-
};
|
|
135
|
-
} catch (reason) {
|
|
136
|
-
if (reason instanceof Error) return {
|
|
137
|
-
success: false,
|
|
138
|
-
error: reason
|
|
139
|
-
};
|
|
140
|
-
let message = "Unknown thrown value";
|
|
141
|
-
try {
|
|
142
|
-
message = String(reason);
|
|
143
|
-
} catch {}
|
|
144
|
-
return {
|
|
145
|
-
success: false,
|
|
146
|
-
error: new Error(message)
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
60
|
//#endregion
|
|
151
61
|
//#region src/browser/helpers.ts
|
|
152
62
|
/**
|
|
@@ -270,6 +180,26 @@ async function hasKey(source, key) {
|
|
|
270
180
|
return await promisifyRequest(guardSync(() => source.count(key))) > 0;
|
|
271
181
|
}
|
|
272
182
|
/**
|
|
183
|
+
* Create a secondary index on a store from its {@link IndexDefinition}.
|
|
184
|
+
*
|
|
185
|
+
* @remarks
|
|
186
|
+
* The shared index-DDL leaf used both by the built-in create-missing-stores pass
|
|
187
|
+
* (`IndexedDBDatabase`'s internal store creation) and by an upgrade's
|
|
188
|
+
* `context.index`: translate the definition's `path` to a native key path and
|
|
189
|
+
* `unique` / `multiple` to `unique` / `multiEntry`, then issue `createIndex`.
|
|
190
|
+
* Versionchange-only — `store` must be inside an active upgrade transaction.
|
|
191
|
+
*
|
|
192
|
+
* @param store - The object store to add the index to
|
|
193
|
+
* @param definition - The index to create
|
|
194
|
+
*/
|
|
195
|
+
function createIndex(store, definition) {
|
|
196
|
+
const keyPath = typeof definition.path === "string" ? definition.path : [...definition.path];
|
|
197
|
+
store.createIndex(definition.name, keyPath, {
|
|
198
|
+
unique: definition.unique ?? false,
|
|
199
|
+
multiEntry: definition.multiple ?? false
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
273
203
|
* Key-range builders — the wrapper's filter vocabulary.
|
|
274
204
|
*
|
|
275
205
|
* @remarks
|
|
@@ -717,14 +647,14 @@ var IndexedDBTransaction = class {
|
|
|
717
647
|
return new IndexedDBTransactionStore(this.#transaction.objectStore(name));
|
|
718
648
|
}
|
|
719
649
|
abort() {
|
|
720
|
-
if (this.#finished) throw new IndexedDBError("
|
|
721
|
-
this.#transaction.abort();
|
|
650
|
+
if (this.#finished) throw new IndexedDBError("INACTIVE", "Cannot abort an already-finished transaction");
|
|
651
|
+
guardSync(() => this.#transaction.abort());
|
|
722
652
|
this.#active = false;
|
|
723
653
|
this.#finished = true;
|
|
724
654
|
}
|
|
725
655
|
commit() {
|
|
726
|
-
if (this.#finished) throw new IndexedDBError("
|
|
727
|
-
this.#transaction.commit();
|
|
656
|
+
if (this.#finished) throw new IndexedDBError("INACTIVE", "Cannot commit an already-finished transaction");
|
|
657
|
+
guardSync(() => this.#transaction.commit());
|
|
728
658
|
}
|
|
729
659
|
};
|
|
730
660
|
//#endregion
|
|
@@ -814,13 +744,15 @@ var IndexedDBDatabase = class {
|
|
|
814
744
|
const names = isArray(stores) ? [...stores] : [stores];
|
|
815
745
|
const native = guardSync(() => database.transaction(names, mode));
|
|
816
746
|
const tx = new IndexedDBTransaction(native);
|
|
747
|
+
const settled = promisifyTransaction(native);
|
|
817
748
|
try {
|
|
818
749
|
await scope(tx);
|
|
819
|
-
await
|
|
750
|
+
await settled;
|
|
820
751
|
} catch (error) {
|
|
821
752
|
if (tx.active) try {
|
|
822
753
|
tx.abort();
|
|
823
754
|
} catch {}
|
|
755
|
+
settled.catch(() => {});
|
|
824
756
|
throw error;
|
|
825
757
|
}
|
|
826
758
|
}
|
|
@@ -835,6 +767,7 @@ var IndexedDBDatabase = class {
|
|
|
835
767
|
}
|
|
836
768
|
database.onclose = () => {
|
|
837
769
|
this.#database = void 0;
|
|
770
|
+
this.#opening = void 0;
|
|
838
771
|
};
|
|
839
772
|
database.onversionchange = () => {
|
|
840
773
|
database.close();
|
|
@@ -853,7 +786,7 @@ var IndexedDBDatabase = class {
|
|
|
853
786
|
for (const [name, definition] of Object.entries(this.#stores)) if (!database.objectStoreNames.contains(name)) this.#createStore(database, name, definition);
|
|
854
787
|
if (this.#upgrade !== void 0) {
|
|
855
788
|
const transaction = request.transaction;
|
|
856
|
-
if (transaction !== null) {
|
|
789
|
+
if (transaction !== null) try {
|
|
857
790
|
const result = this.#upgrade(this.#context(database, transaction, event));
|
|
858
791
|
if (result !== void 0) result.catch((error) => {
|
|
859
792
|
upgradeError = error;
|
|
@@ -861,6 +794,11 @@ var IndexedDBDatabase = class {
|
|
|
861
794
|
transaction.abort();
|
|
862
795
|
} catch {}
|
|
863
796
|
});
|
|
797
|
+
} catch (error) {
|
|
798
|
+
upgradeError = error;
|
|
799
|
+
try {
|
|
800
|
+
transaction.abort();
|
|
801
|
+
} catch {}
|
|
864
802
|
}
|
|
865
803
|
}
|
|
866
804
|
};
|
|
@@ -879,25 +817,25 @@ var IndexedDBDatabase = class {
|
|
|
879
817
|
version: event.newVersion ?? database.version,
|
|
880
818
|
stores: Array.from(database.objectStoreNames),
|
|
881
819
|
create: (name, definition) => {
|
|
882
|
-
this.#createStore(database, name, definition);
|
|
820
|
+
guardSync(() => this.#createStore(database, name, definition));
|
|
883
821
|
},
|
|
884
822
|
drop: (name) => {
|
|
885
|
-
database.deleteObjectStore(name);
|
|
823
|
+
guardSync(() => database.deleteObjectStore(name));
|
|
824
|
+
},
|
|
825
|
+
store: (name) => new IndexedDBTransactionStore(guardSync(() => transaction.objectStore(name))),
|
|
826
|
+
index: (store, definition) => {
|
|
827
|
+
guardSync(() => createIndex(transaction.objectStore(store), definition));
|
|
886
828
|
},
|
|
887
|
-
|
|
829
|
+
deindex: (store, name) => {
|
|
830
|
+
guardSync(() => transaction.objectStore(store).deleteIndex(name));
|
|
831
|
+
}
|
|
888
832
|
};
|
|
889
833
|
}
|
|
890
834
|
#createStore(database, name, definition) {
|
|
891
835
|
const options = { autoIncrement: definition.increment ?? false };
|
|
892
836
|
if (definition.path !== void 0) options.keyPath = typeof definition.path === "string" ? definition.path : [...definition.path];
|
|
893
837
|
const store = database.createObjectStore(name, options);
|
|
894
|
-
for (const index of definition.indexes ?? [])
|
|
895
|
-
const keyPath = typeof index.path === "string" ? index.path : [...index.path];
|
|
896
|
-
store.createIndex(index.name, keyPath, {
|
|
897
|
-
unique: index.unique ?? false,
|
|
898
|
-
multiEntry: index.multiple ?? false
|
|
899
|
-
});
|
|
900
|
-
}
|
|
838
|
+
for (const index of definition.indexes ?? []) createIndex(store, index);
|
|
901
839
|
}
|
|
902
840
|
};
|
|
903
841
|
//#endregion
|
|
@@ -917,7 +855,7 @@ var IndexedDBDatabase = class {
|
|
|
917
855
|
*
|
|
918
856
|
* @example
|
|
919
857
|
* ```ts
|
|
920
|
-
* import { createIndexedDBDatabase, range } from '@
|
|
858
|
+
* import { createIndexedDBDatabase, range } from '@orkestrel/indexeddb'
|
|
921
859
|
*
|
|
922
860
|
* const db = createIndexedDBDatabase({
|
|
923
861
|
* name: 'app',
|
|
@@ -934,6 +872,6 @@ function createIndexedDBDatabase(options) {
|
|
|
934
872
|
return new IndexedDBDatabase(options);
|
|
935
873
|
}
|
|
936
874
|
//#endregion
|
|
937
|
-
export { ERROR_CODES, IndexedDBCursor, IndexedDBDatabase, IndexedDBError, IndexedDBIndex, IndexedDBStore, IndexedDBTransaction, IndexedDBTransactionStore, createIndexedDBDatabase, guardSync, hasKey, isIndexedDBError, isIndexedDBSupported, promisifyRequest, promisifyTransaction, range, readRecord, readRecords, wrapError };
|
|
875
|
+
export { ERROR_CODES, IndexedDBCursor, IndexedDBDatabase, IndexedDBError, IndexedDBIndex, IndexedDBStore, IndexedDBTransaction, IndexedDBTransactionStore, createIndex, createIndexedDBDatabase, guardSync, hasKey, isIndexedDBError, isIndexedDBSupported, promisifyRequest, promisifyTransaction, range, readRecord, readRecords, wrapError };
|
|
938
876
|
|
|
939
877
|
//# sourceMappingURL=index.js.map
|