@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.
@@ -1,11 +1,753 @@
1
- export type * from './types.js';
2
- export * from './constants.js';
3
- export * from './errors.js';
4
- export * from './helpers.js';
5
- export * from './factories.js';
6
- export * from './IndexedDBDatabase.js';
7
- export * from './IndexedDBStore.js';
8
- export * from './IndexedDBIndex.js';
9
- export * from './IndexedDBCursor.js';
10
- export * from './IndexedDBTransaction.js';
11
- export * from './IndexedDBTransactionStore.js';
1
+ /**
2
+ * Create a secondary index on a store from its {@link IndexDefinition}.
3
+ *
4
+ * @remarks
5
+ * The shared index-DDL leaf used both by the built-in create-missing-stores pass
6
+ * (`IndexedDBDatabase`'s internal store creation) and by an upgrade's
7
+ * `context.index`: translate the definition's `path` to a native key path and
8
+ * `unique` / `multiple` to `unique` / `multiEntry`, then issue `createIndex`.
9
+ * Versionchange-only — `store` must be inside an active upgrade transaction.
10
+ *
11
+ * @param store - The object store to add the index to
12
+ * @param definition - The index to create
13
+ */
14
+ export declare function createIndex(store: IDBObjectStore, definition: IndexDefinition): void;
15
+
16
+ /**
17
+ * Create a browser-native IndexedDB database over a store schema.
18
+ *
19
+ * @remarks
20
+ * The `const` type parameter captures the literal store names, so `db.store(name)`
21
+ * and `db.read` / `db.write` are checked against the declared stores. Stores are
22
+ * created from their definitions the first time the database opens at a new
23
+ * `version`; omit `version` for auto-managed mode, where the database bumps its
24
+ * own version once to create any declared store the stored schema is missing.
25
+ *
26
+ * @param options - The database `name`, `version`, and `stores` schema
27
+ * @returns A typed {@link IndexedDBDatabaseInterface}
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { createIndexedDBDatabase, range } from '@orkestrel/indexeddb'
32
+ *
33
+ * const db = createIndexedDBDatabase({
34
+ * name: 'app',
35
+ * version: 1,
36
+ * stores: {
37
+ * users: { path: 'id', indexes: [{ name: 'byAge', path: 'age' }] },
38
+ * },
39
+ * })
40
+ * await db.store('users').set({ id: 'u1', name: 'Ada', age: 36 })
41
+ * await db.store('users').index('byAge').records(range.from(18)) // adults, index-backed
42
+ * ```
43
+ */
44
+ export declare function createIndexedDBDatabase<const Stores extends StoresShape>(options: IndexedDBDatabaseOptions<Stores>): IndexedDBDatabaseInterface<Stores>;
45
+
46
+ /**
47
+ * Options for opening a cursor.
48
+ *
49
+ * @remarks
50
+ * `query` restricts iteration to a key range (or a single key); `direction` sets
51
+ * the traversal order (`next` / `prev` / their `unique` variants).
52
+ */
53
+ export declare interface CursorOptions {
54
+ readonly query?: IDBKeyRange | IDBValidKey | null;
55
+ readonly direction?: IDBCursorDirection;
56
+ }
57
+
58
+ /**
59
+ * Native `DOMException.name` → our {@link IndexedDBErrorCode}.
60
+ *
61
+ * @remarks
62
+ * The mapping the request boundary's `wrapError` reads to translate a raw
63
+ * IndexedDB fault into a typed {@link IndexedDBError} code; an unmapped name
64
+ * falls back to `UNKNOWN`. Frozen plain data (AGENTS §5).
65
+ */
66
+ export declare const ERROR_CODES: Readonly<Record<string, IndexedDBErrorCode>>;
67
+
68
+ /**
69
+ * Run a synchronous native IndexedDB call, wrapping a thrown `DOMException`
70
+ * into a typed {@link IndexedDBError}.
71
+ *
72
+ * @remarks
73
+ * Native IndexedDB throws SYNCHRONOUSLY (not through a request's `onerror`)
74
+ * from calls like `database.transaction(...)` or an inactive/closed store's
75
+ * `get` / `put` / `openCursor` — `TransactionInactiveError` /
76
+ * `InvalidStateError` never reach {@link promisifyRequest}'s `onerror`
77
+ * bridge. Every request-issuing call site wraps its native invocation in this
78
+ * so those faults surface as the same typed `IndexedDBError` as an
79
+ * asynchronous one.
80
+ *
81
+ * @param action - The synchronous native call to run
82
+ * @returns Its return value
83
+ */
84
+ export declare function guardSync<T>(action: () => T): T;
85
+
86
+ /**
87
+ * Whether a key is present in a store or index.
88
+ *
89
+ * @remarks
90
+ * The shared presence test of every store-like class: a native `count` of the
91
+ * key, true when at least one record matches — cheaper than reading the record
92
+ * when only existence matters.
93
+ *
94
+ * @param source - The object store or index to test
95
+ * @param key - The key to look for
96
+ * @returns `true` when at least one record has the key
97
+ */
98
+ export declare function hasKey(source: IDBObjectStore | IDBIndex, key: IDBValidKey): Promise<boolean>;
99
+
100
+ /**
101
+ * A secondary index on a store.
102
+ *
103
+ * @remarks
104
+ * `name` identifies the index for `store.index(name)`; `path` is the field(s) it
105
+ * indexes; `unique` enforces one record per indexed value; `multiple` (IndexedDB's
106
+ * `multiEntry`) indexes each element of an array value separately.
107
+ */
108
+ export declare interface IndexDefinition {
109
+ readonly name: string;
110
+ readonly path: KeyPath;
111
+ readonly unique?: boolean;
112
+ readonly multiple?: boolean;
113
+ }
114
+
115
+ /**
116
+ * A promisified value cursor over an object store or index.
117
+ *
118
+ * @remarks
119
+ * Wraps `IDBCursorWithValue` and the request that drives it. The position
120
+ * (`key` / `primary` / `value`) is snapshot at construction because IndexedDB
121
+ * mutates the live cursor object in place on each advance. `continue` / `seek` /
122
+ * `advance` re-arm the shared request and resolve to the next position (a fresh
123
+ * `IndexedDBCursor`) or `null` at the end. `update` / `delete` act on the current
124
+ * record — they require the cursor's transaction to be `readwrite` (a `store`
125
+ * cursor), so they reject on an `index` cursor's read-only transaction.
126
+ */
127
+ export declare class IndexedDBCursor implements IndexedDBCursorInterface {
128
+ #private;
129
+ constructor(cursor: IDBCursorWithValue, request: IDBRequest<IDBCursorWithValue | null>);
130
+ get cursor(): IDBCursorWithValue;
131
+ get source(): IDBObjectStore | IDBIndex;
132
+ get key(): IDBValidKey;
133
+ get primary(): IDBValidKey;
134
+ get value(): Row;
135
+ get direction(): IDBCursorDirection;
136
+ continue(key?: IDBValidKey): Promise<IndexedDBCursorInterface | null>;
137
+ seek(key: IDBValidKey, primary: IDBValidKey): Promise<IndexedDBCursorInterface | null>;
138
+ advance(count: number): Promise<IndexedDBCursorInterface | null>;
139
+ update(value: Row): Promise<IDBValidKey>;
140
+ delete(): Promise<void>;
141
+ }
142
+
143
+ /**
144
+ * A promisified value cursor for streaming and in-place mutation.
145
+ *
146
+ * @remarks
147
+ * Wraps `IDBCursorWithValue`. `key` / `primary` / `value` snapshot the current
148
+ * position (IndexedDB reuses the live cursor object on advance, so they are read
149
+ * eagerly). `continue` / `seek` / `advance` resolve to the next cursor or `null`
150
+ * at the end; `update` / `delete` mutate the record at the current position. The
151
+ * owning transaction stays alive only while you drive the cursor promptly — do no
152
+ * unrelated `await` between steps, or it auto-commits.
153
+ */
154
+ export declare interface IndexedDBCursorInterface {
155
+ readonly cursor: IDBCursorWithValue;
156
+ readonly source: IDBObjectStore | IDBIndex;
157
+ readonly key: IDBValidKey;
158
+ readonly primary: IDBValidKey;
159
+ readonly value: Row;
160
+ readonly direction: IDBCursorDirection;
161
+ continue(key?: IDBValidKey): Promise<IndexedDBCursorInterface | null>;
162
+ seek(key: IDBValidKey, primary: IDBValidKey): Promise<IndexedDBCursorInterface | null>;
163
+ advance(count: number): Promise<IndexedDBCursorInterface | null>;
164
+ update(value: Row): Promise<IDBValidKey>;
165
+ delete(): Promise<void>;
166
+ }
167
+
168
+ /**
169
+ * A browser-native IndexedDB database — a typed, Promise-based handle.
170
+ *
171
+ * @remarks
172
+ * Connects lazily on first use (`connect`, also awaited internally by every store
173
+ * operation), creating any missing stores from their definitions inside
174
+ * `onupgradeneeded`. `store` reaches a typed store; `read` / `write` run an atomic
175
+ * scope over one or more stores, committing on resolve and rolling back on a throw;
176
+ * `close` releases the connection and `drop` deletes the database. Schema changes
177
+ * beyond creating new stores (dropping stores, altering indexes) are deferred.
178
+ */
179
+ export declare class IndexedDBDatabase<Stores extends StoresShape = StoresShape> implements IndexedDBDatabaseInterface<Stores> {
180
+ #private;
181
+ constructor(options: IndexedDBDatabaseOptions<Stores>);
182
+ get database(): IDBDatabase;
183
+ get name(): string;
184
+ get version(): number;
185
+ get stores(): readonly string[];
186
+ get open(): boolean;
187
+ connect(): Promise<IDBDatabase>;
188
+ store<K extends keyof Stores & string>(name: K): IndexedDBStoreInterface;
189
+ read(stores: (keyof Stores & string) | readonly (keyof Stores & string)[], scope: (tx: IndexedDBTransactionInterface<Stores>) => void | Promise<void>): Promise<void>;
190
+ write(stores: (keyof Stores & string) | readonly (keyof Stores & string)[], scope: (tx: IndexedDBTransactionInterface<Stores>) => void | Promise<void>): Promise<void>;
191
+ close(): void;
192
+ drop(): Promise<void>;
193
+ }
194
+
195
+ /**
196
+ * A browser-native IndexedDB database.
197
+ *
198
+ * @remarks
199
+ * A typed, Promise-based handle over `IDBDatabase`. It connects lazily on first
200
+ * use (`connect`, also awaited by every store operation); `store` reaches a typed
201
+ * store; `read` / `write` run an atomic scope over one or more stores; `close`
202
+ * releases the connection and `drop` deletes the database. `stores` lists the
203
+ * declared (or, once open, the live) store names; `open` reports whether a live
204
+ * connection is held.
205
+ */
206
+ export declare interface IndexedDBDatabaseInterface<Stores extends StoresShape = StoresShape> {
207
+ readonly database: IDBDatabase;
208
+ readonly name: string;
209
+ readonly version: number;
210
+ readonly stores: readonly string[];
211
+ readonly open: boolean;
212
+ connect(): Promise<IDBDatabase>;
213
+ store<K extends keyof Stores & string>(name: K): IndexedDBStoreInterface;
214
+ read(stores: (keyof Stores & string) | readonly (keyof Stores & string)[], scope: (tx: IndexedDBTransactionInterface<Stores>) => void | Promise<void>): Promise<void>;
215
+ write(stores: (keyof Stores & string) | readonly (keyof Stores & string)[], scope: (tx: IndexedDBTransactionInterface<Stores>) => void | Promise<void>): Promise<void>;
216
+ close(): void;
217
+ drop(): Promise<void>;
218
+ }
219
+
220
+ /**
221
+ * Options for `createIndexedDBDatabase`.
222
+ *
223
+ * @remarks
224
+ * `name` is passed to `indexedDB.open`. `version` is optional: give it to pin an
225
+ * explicit schema version (a higher number than the stored one triggers an upgrade
226
+ * that creates any missing `stores`); omit it for **auto-managed** mode, where the
227
+ * database opens at its current version and bumps once to create any declared store
228
+ * the stored schema is missing — so adding a store never needs a manual version
229
+ * bump. `upgrade` runs after the built-in create-missing-stores pass, inside the
230
+ * same versionchange transaction — use it to drop a store, add or remove an index
231
+ * on any store with `context.index` / `context.deindex`, or migrate data with
232
+ * `context.store(name)`. It may return `void` or a `Promise<void>` — an async
233
+ * `upgrade` may `await` the IDB requests it issues through `context.store(...)`
234
+ * (see the auto-commit rule on {@link IndexedDBUpgradeContext}); a rejection
235
+ * aborts the versionchange transaction and rejects the pending `connect()` with
236
+ * an `IndexedDBError` (code `UPGRADE`) instead of an unhandled rejection.
237
+ */
238
+ export declare interface IndexedDBDatabaseOptions<Stores extends StoresShape = StoresShape> {
239
+ readonly name: string;
240
+ readonly version?: number;
241
+ readonly stores: Stores;
242
+ readonly upgrade?: (context: IndexedDBUpgradeContext) => void | Promise<void>;
243
+ }
244
+
245
+ /**
246
+ * An error thrown by the IndexedDB wrapper.
247
+ *
248
+ * @remarks
249
+ * Carries an {@link IndexedDBErrorCode} and the originating native error as the
250
+ * standard `cause`. Construct it directly for wrapper-lifecycle faults; the
251
+ * internal `wrapError` maps a native `DOMException` to the right code at the
252
+ * request boundary. Narrow a caught value with `instanceof IndexedDBError`.
253
+ *
254
+ * @example
255
+ * ```ts
256
+ * try {
257
+ * await store.add(row)
258
+ * } catch (error) {
259
+ * if (error instanceof IndexedDBError && error.code === 'CONSTRAINT') await store.set(row)
260
+ * }
261
+ * ```
262
+ */
263
+ export declare class IndexedDBError extends Error {
264
+ readonly code: IndexedDBErrorCode;
265
+ constructor(code: IndexedDBErrorCode, message: string, cause?: unknown);
266
+ }
267
+
268
+ /**
269
+ * A machine-readable {@link IndexedDBError} code.
270
+ *
271
+ * @remarks
272
+ * Each maps from a native `DOMException.name` or a wrapper-lifecycle fault:
273
+ * `NOT_OPEN` (used before `connect`), `CLOSED` (used after `close`), `NOT_FOUND`
274
+ * (a `resolve` miss), `CONSTRAINT` (a unique-key violation), `QUOTA` (storage
275
+ * full), `ABORTED` (a transaction rolled back), `BLOCKED` (an open held up by
276
+ * another live connection), `DATA` (an invalid key or an un-clonable value —
277
+ * native `DataError` and `DataCloneError` both map here), `OPEN` /
278
+ * `UPGRADE` (a failed open or schema upgrade), `INACTIVE` (the transaction went
279
+ * inactive — IndexedDB's auto-commit fault, raised when an operation runs after
280
+ * a non-IDB `await` deactivated its transaction — reachable through
281
+ * `IndexedDBTransactionStoreInterface`, and when `IndexedDBTransactionInterface`'s
282
+ * `abort` / `commit` are called on an already-finished transaction), `READONLY`
283
+ * (native `ReadOnlyError` — a write attempted on a `readonly` transaction, e.g.
284
+ * mutating through a cursor opened in a `read` scope), `INVALID` (native
285
+ * `InvalidStateError` — a defensive mapping for a deleted store/index or
286
+ * similarly invalid native handle; not cleanly reachable through this
287
+ * wrapper's public API, which always opens a fresh transaction or routes
288
+ * through the auto-commit-guarded transaction store above), and `UNKNOWN` (any
289
+ * unmapped fault).
290
+ */
291
+ export declare type IndexedDBErrorCode = 'NOT_OPEN' | 'CLOSED' | 'NOT_FOUND' | 'CONSTRAINT' | 'QUOTA' | 'ABORTED' | 'BLOCKED' | 'DATA' | 'OPEN' | 'UPGRADE' | 'INACTIVE' | 'READONLY' | 'INVALID' | 'UNKNOWN';
292
+
293
+ /**
294
+ * A secondary index on a store — a read-only view keyed by an indexed path.
295
+ *
296
+ * @remarks
297
+ * Reached through `store.index(name)`. Each call opens its own `readonly`
298
+ * transaction. `get` / `resolve` fetch the first record for an index key
299
+ * (`resolve` throws `NOT_FOUND`); `records` reads the matching records and `keys`
300
+ * their **primary** keys; `primary` maps an index key to one primary key; `count`
301
+ * / `has` test presence; `cursor` streams matches. Reads batch by their array
302
+ * overload (AGENTS §9.2).
303
+ */
304
+ export declare class IndexedDBIndex implements IndexedDBIndexInterface {
305
+ #private;
306
+ constructor(store: string, name: string, definition: IndexDefinition, connect: () => Promise<IDBDatabase>);
307
+ get name(): string;
308
+ get path(): KeyPath;
309
+ get unique(): boolean;
310
+ get multiple(): boolean;
311
+ get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
312
+ get(key: IDBValidKey): Promise<Row | undefined>;
313
+ resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
314
+ resolve(key: IDBValidKey): Promise<Row>;
315
+ records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
316
+ keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
317
+ primary(key: IDBValidKey): Promise<IDBValidKey | undefined>;
318
+ has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
319
+ has(key: IDBValidKey): Promise<boolean>;
320
+ count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
321
+ cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
322
+ }
323
+
324
+ /**
325
+ * A secondary index — read access by an indexed key path.
326
+ *
327
+ * @remarks
328
+ * Indexes are read-only views over a store. `get` / `resolve` fetch the first
329
+ * record for an index key (`resolve` throws `NOT_FOUND` on a miss); `records` /
330
+ * `keys` read many (the matching records, and their **primary** keys); `primary`
331
+ * maps an index key to one primary key; `count` / `has` test presence; `cursor`
332
+ * streams matches. A read of several keys is the array overload of the same verb
333
+ * (AGENTS §9.2).
334
+ */
335
+ export declare interface IndexedDBIndexInterface {
336
+ readonly name: string;
337
+ readonly path: KeyPath;
338
+ readonly unique: boolean;
339
+ readonly multiple: boolean;
340
+ get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
341
+ get(key: IDBValidKey): Promise<Row | undefined>;
342
+ resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
343
+ resolve(key: IDBValidKey): Promise<Row>;
344
+ records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
345
+ keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
346
+ primary(key: IDBValidKey): Promise<IDBValidKey | undefined>;
347
+ has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
348
+ has(key: IDBValidKey): Promise<boolean>;
349
+ count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
350
+ cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
351
+ }
352
+
353
+ /**
354
+ * An object store — the full keyed CRUD surface plus index, count, and cursor
355
+ * access.
356
+ *
357
+ * @remarks
358
+ * Reached through `database.store(name)`. Each call runs in its own implicit
359
+ * transaction (`readonly` for reads, `readwrite` for writes), awaiting completion
360
+ * so writes are durable on return; for atomic multi-operation work use the
361
+ * database's `read` / `write`. The keyed verbs batch by their array overload — and
362
+ * those overloads are declared first, because an array is itself both a record and
363
+ * a compound `IDBValidKey`, so the array signature must take precedence to read as
364
+ * a batch (AGENTS §9.2). Pass `range.only([…])` to `records` / `count` to act on a
365
+ * single compound key.
366
+ */
367
+ export declare class IndexedDBStore implements IndexedDBStoreInterface {
368
+ #private;
369
+ constructor(name: string, definition: StoreDefinition, connect: () => Promise<IDBDatabase>);
370
+ get name(): string;
371
+ get path(): KeyPath | null;
372
+ get indexes(): readonly string[];
373
+ get increment(): boolean;
374
+ get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
375
+ get(key: IDBValidKey): Promise<Row | undefined>;
376
+ resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
377
+ resolve(key: IDBValidKey): Promise<Row>;
378
+ records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
379
+ keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
380
+ has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
381
+ has(key: IDBValidKey): Promise<boolean>;
382
+ count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
383
+ set(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
384
+ set(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
385
+ add(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
386
+ add(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
387
+ remove(keys: readonly IDBValidKey[]): Promise<void>;
388
+ remove(key: IDBValidKey): Promise<void>;
389
+ clear(): Promise<void>;
390
+ index(name: string): IndexedDBIndexInterface;
391
+ cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
392
+ }
393
+
394
+ /**
395
+ * An object store — the full keyed CRUD surface, plus index, count, and cursor
396
+ * access.
397
+ *
398
+ * @remarks
399
+ * Each call runs in its own implicit transaction; for atomic multi-operation work
400
+ * use the database's `read` / `write`. `get` / `resolve` read by key (`resolve`
401
+ * throws `NOT_FOUND`); `records` / `keys` read many over an optional key range;
402
+ * `set` upserts and `add` inserts (throwing `CONSTRAINT` on a duplicate);
403
+ * `remove` deletes; `clear` empties the store. The keyed verbs batch by their
404
+ * array overload — listed first, since an array is itself a valid record and a
405
+ * compound `IDBValidKey`, so the array signature must win (AGENTS §9.2). To act on
406
+ * a single **compound** key, pass `range.only([…])` to `records` / `count`.
407
+ */
408
+ export declare interface IndexedDBStoreInterface {
409
+ readonly name: string;
410
+ readonly path: KeyPath | null;
411
+ readonly indexes: readonly string[];
412
+ readonly increment: boolean;
413
+ get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
414
+ get(key: IDBValidKey): Promise<Row | undefined>;
415
+ resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
416
+ resolve(key: IDBValidKey): Promise<Row>;
417
+ records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
418
+ keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
419
+ has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
420
+ has(key: IDBValidKey): Promise<boolean>;
421
+ count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
422
+ set(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
423
+ set(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
424
+ add(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
425
+ add(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
426
+ remove(keys: readonly IDBValidKey[]): Promise<void>;
427
+ remove(key: IDBValidKey): Promise<void>;
428
+ clear(): Promise<void>;
429
+ index(name: string): IndexedDBIndexInterface;
430
+ cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
431
+ }
432
+
433
+ /**
434
+ * An explicit transaction over one or more stores.
435
+ *
436
+ * @remarks
437
+ * Wraps `IDBTransaction` with state tracking and typed, scope-bound store access.
438
+ * Constructed by the database's `read` / `write`, which await its completion (or
439
+ * roll it back on a throw). `store` reaches a store within the transaction's scope;
440
+ * `abort` rolls back; `commit` flushes early (the scope's completion commits
441
+ * otherwise). `active` is true until commit or abort; `finished` is its complement.
442
+ */
443
+ export declare class IndexedDBTransaction<Stores extends StoresShape = StoresShape> implements IndexedDBTransactionInterface<Stores> {
444
+ #private;
445
+ constructor(transaction: IDBTransaction);
446
+ get transaction(): IDBTransaction;
447
+ get mode(): IDBTransactionMode;
448
+ get stores(): readonly string[];
449
+ get active(): boolean;
450
+ get finished(): boolean;
451
+ get error(): DOMException | null;
452
+ store<K extends keyof Stores & string>(name: K): IndexedDBTransactionStoreInterface;
453
+ abort(): void;
454
+ commit(): void;
455
+ }
456
+
457
+ /**
458
+ * An explicit transaction over one or more stores.
459
+ *
460
+ * @remarks
461
+ * Obtained through the `scope` callback of the database's `read` / `write`. `store`
462
+ * reaches a typed, transaction-bound store; the transaction commits automatically
463
+ * when the scope resolves, or rolls back if it throws or `abort` is called.
464
+ * `active` is true while it still accepts operations; `finished` is true after
465
+ * commit or abort.
466
+ */
467
+ export declare interface IndexedDBTransactionInterface<Stores extends StoresShape = StoresShape> {
468
+ readonly transaction: IDBTransaction;
469
+ readonly mode: IDBTransactionMode;
470
+ readonly stores: readonly string[];
471
+ readonly active: boolean;
472
+ readonly finished: boolean;
473
+ readonly error: DOMException | null;
474
+ store<K extends keyof Stores & string>(name: K): IndexedDBTransactionStoreInterface;
475
+ abort(): void;
476
+ commit(): void;
477
+ }
478
+
479
+ /**
480
+ * An object store bound to an explicit transaction.
481
+ *
482
+ * @remarks
483
+ * The same CRUD surface as a standalone store, but every call runs in the owning
484
+ * transaction (opened by the database's `read` / `write`) rather than its own — so
485
+ * a sequence of reads and writes commits atomically when the scope resolves. It
486
+ * does not await transaction completion per call (the scope does that once) and
487
+ * omits `index`; keep your awaited operations on IndexedDB requests only, so the
488
+ * transaction stays active across them.
489
+ */
490
+ export declare class IndexedDBTransactionStore implements IndexedDBTransactionStoreInterface {
491
+ #private;
492
+ constructor(store: IDBObjectStore);
493
+ get store(): IDBObjectStore;
494
+ get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
495
+ get(key: IDBValidKey): Promise<Row | undefined>;
496
+ resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
497
+ resolve(key: IDBValidKey): Promise<Row>;
498
+ records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
499
+ keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
500
+ has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
501
+ has(key: IDBValidKey): Promise<boolean>;
502
+ count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
503
+ set(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
504
+ set(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
505
+ add(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
506
+ add(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
507
+ remove(keys: readonly IDBValidKey[]): Promise<void>;
508
+ remove(key: IDBValidKey): Promise<void>;
509
+ clear(): Promise<void>;
510
+ cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
511
+ }
512
+
513
+ /**
514
+ * An object store bound to an explicit transaction.
515
+ *
516
+ * @remarks
517
+ * The same CRUD surface as {@link IndexedDBStoreInterface}, but every call runs in
518
+ * the owning transaction (opened by the database's `read` / `write`) rather than
519
+ * its own — so a sequence of reads and writes is atomic. It drops `index` and the
520
+ * standalone implicit-transaction conveniences; reach the live `store` for those.
521
+ */
522
+ export declare interface IndexedDBTransactionStoreInterface {
523
+ readonly store: IDBObjectStore;
524
+ get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
525
+ get(key: IDBValidKey): Promise<Row | undefined>;
526
+ resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
527
+ resolve(key: IDBValidKey): Promise<Row>;
528
+ records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
529
+ keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
530
+ has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
531
+ has(key: IDBValidKey): Promise<boolean>;
532
+ count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
533
+ set(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
534
+ set(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
535
+ add(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
536
+ add(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
537
+ remove(keys: readonly IDBValidKey[]): Promise<void>;
538
+ remove(key: IDBValidKey): Promise<void>;
539
+ clear(): Promise<void>;
540
+ cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
541
+ }
542
+
543
+ /**
544
+ * The escape hatch into a version-change upgrade, passed to
545
+ * `IndexedDBDatabaseOptions.upgrade`.
546
+ *
547
+ * @remarks
548
+ * Runs INSIDE `onupgradeneeded`, after the built-in create-missing-stores pass —
549
+ * so `stores` already reflects any store just created from the declared schema.
550
+ * `transaction` is the raw versionchange `IDBTransaction`, the escape hatch for
551
+ * anything the raw API offers that this wrapper does not model directly; `old` /
552
+ * `version` are the prior and target database versions (`old` is `0` on first
553
+ * create); `create` / `drop` add or remove a whole store; `index` / `deindex` add
554
+ * or remove a secondary index on a store; `store` reaches a transaction-bound
555
+ * store for data migration. Everything invoked here must stay within the
556
+ * versionchange transaction — no non-IDB `await`, or it auto-commits and the
557
+ * upgrade fails.
558
+ */
559
+ export declare interface IndexedDBUpgradeContext {
560
+ readonly transaction: IDBTransaction;
561
+ readonly old: number;
562
+ readonly version: number;
563
+ readonly stores: readonly string[];
564
+ create(name: string, definition: StoreDefinition): void;
565
+ drop(name: string): void;
566
+ store(name: string): IndexedDBTransactionStoreInterface;
567
+ /**
568
+ * Create a secondary index on `store`.
569
+ *
570
+ * @param store - Name of an existing store, or one just created in this same upgrade via `create`.
571
+ * @param definition - The index to add — {@link IndexDefinition}.
572
+ * @remarks
573
+ * Versionchange-only: `store` must already exist within the current upgrade
574
+ * transaction (either declared in the schema, created earlier in the same
575
+ * upgrade, or already present from a prior version). Mirrors the index
576
+ * translation the built-in schema pass applies to a store's declared
577
+ * `indexes`.
578
+ * @example
579
+ * ```ts
580
+ * upgrade(context) {
581
+ * context.index('books', { name: 'byAuthor', path: 'author' })
582
+ * }
583
+ * ```
584
+ */
585
+ index(store: string, definition: IndexDefinition): void;
586
+ /**
587
+ * Remove a named index from `store`.
588
+ *
589
+ * @param store - Name of an existing store within the current upgrade transaction.
590
+ * @param name - The index name to remove.
591
+ * @remarks
592
+ * Versionchange-only, same constraint as `index`.
593
+ * @example
594
+ * ```ts
595
+ * upgrade(context) {
596
+ * context.deindex('books', 'byAuthor')
597
+ * }
598
+ * ```
599
+ */
600
+ deindex(store: string, name: string): void;
601
+ }
602
+
603
+ /**
604
+ * Whether a value is an {@link IndexedDBError}.
605
+ *
606
+ * @param value - The value to test
607
+ * @returns `true` when `value` is an `IndexedDBError`
608
+ */
609
+ export declare function isIndexedDBError(value: unknown): value is IndexedDBError;
610
+
611
+ /**
612
+ * Whether IndexedDB is available in this environment.
613
+ *
614
+ * @remarks
615
+ * Gate IndexedDB code with this and fall back to another storage strategy where
616
+ * it is absent (a non-browser runtime, a privacy mode that disables storage).
617
+ * The entry probe, checked before reaching for the rest of this module.
618
+ *
619
+ * @returns `true` when `globalThis.indexedDB` exists
620
+ */
621
+ export declare function isIndexedDBSupported(): boolean;
622
+
623
+ /**
624
+ * A key path — one field, or several for a compound key.
625
+ *
626
+ * @remarks
627
+ * A single string addresses one field; an array addresses a compound key over
628
+ * several fields, in order.
629
+ */
630
+ export declare type KeyPath = string | readonly string[];
631
+
632
+ /**
633
+ * Resolve an `IDBRequest` to its result, rejecting with an {@link IndexedDBError}.
634
+ *
635
+ * @remarks
636
+ * The single bridge from IndexedDB's event-based requests to Promises. Issue the
637
+ * request, then `await` this — within an implicit transaction, issue every request
638
+ * for that transaction before the first `await`, so they share it.
639
+ *
640
+ * @param request - The pending request
641
+ * @returns Its `result` on success
642
+ */
643
+ export declare function promisifyRequest<T>(request: IDBRequest<T>): Promise<T>;
644
+
645
+ /**
646
+ * Resolve once an `IDBTransaction` commits, rejecting if it errors or aborts.
647
+ *
648
+ * @remarks
649
+ * Await this after issuing the writes of a `readwrite` transaction to guarantee
650
+ * they are durable before continuing.
651
+ *
652
+ * @param transaction - The transaction to await
653
+ */
654
+ export declare function promisifyTransaction(transaction: IDBTransaction): Promise<void>;
655
+
656
+ /**
657
+ * Key-range builders — the wrapper's filter vocabulary.
658
+ *
659
+ * @remarks
660
+ * Each returns an `IDBKeyRange` to pass to `records` / `keys` / `count` / `cursor`,
661
+ * so a read is index-backed (O(log n)) rather than a full scan. `only` (exact),
662
+ * `above` / `from` (greater than, exclusive / inclusive), `below` / `to` (less
663
+ * than, exclusive / inclusive), `between` (bounded), and `prefix` (string
664
+ * starts-with).
665
+ */
666
+ export declare const range: {
667
+ only(value: IDBValidKey): IDBKeyRange;
668
+ above(value: IDBValidKey): IDBKeyRange;
669
+ from(value: IDBValidKey): IDBKeyRange;
670
+ below(value: IDBValidKey): IDBKeyRange;
671
+ to(value: IDBValidKey): IDBKeyRange;
672
+ between(lower: IDBValidKey, upper: IDBValidKey, options?: {
673
+ readonly lowerOpen?: boolean;
674
+ readonly upperOpen?: boolean;
675
+ }): IDBKeyRange;
676
+ prefix(value: string): IDBKeyRange;
677
+ };
678
+
679
+ /**
680
+ * Read one record by key from a store or index, narrowing it to a {@link Row}.
681
+ *
682
+ * @remarks
683
+ * The shared point-read of every store-like class (`IndexedDBStore`,
684
+ * `IndexedDBIndex`, `IndexedDBTransactionStore`): issue the native `get`, then
685
+ * narrow the structured clone with `isRecord` — a non-record (or a miss) reads as
686
+ * `undefined`, never an unchecked cast. On an index, `source.get` returns the
687
+ * first record for the index key.
688
+ *
689
+ * @param source - The object store or index to read from
690
+ * @param key - The key (a primary key for a store, an index key for an index)
691
+ * @returns The record, or `undefined` on a miss
692
+ */
693
+ export declare function readRecord(source: IDBObjectStore | IDBIndex, key: IDBValidKey): Promise<Row | undefined>;
694
+
695
+ /**
696
+ * Read many records from a store or index over an optional key range.
697
+ *
698
+ * @remarks
699
+ * The shared bulk read of every store-like class: issue the native `getAll` over
700
+ * an optional `query` (a key range or a single key) and `count` cap, then keep
701
+ * only the records with `isRecord` — the same boundary narrowing as
702
+ * {@link readRecord}, applied across the batch.
703
+ *
704
+ * @param source - The object store or index to read from
705
+ * @param query - A key range or single key to restrict the read, or `null` for all
706
+ * @param count - The maximum number of records to read
707
+ * @returns The matching records
708
+ */
709
+ export declare function readRecords(source: IDBObjectStore | IDBIndex, query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
710
+
711
+ /**
712
+ * A record stored in, and read from, an object store.
713
+ *
714
+ * @remarks
715
+ * The value shape every store / index / transaction-store CRUD method reads and
716
+ * writes. A structured-clone value narrowed with `isRecord` at the read
717
+ * boundary (see `helpers.ts`), never an unchecked cast.
718
+ */
719
+ export declare type Row = Record<string, unknown>;
720
+
721
+ /**
722
+ * A store's schema.
723
+ *
724
+ * @remarks
725
+ * `path` is the in-line key path (omit it for an **out-of-line** store, where the
726
+ * key is passed explicitly to `set` / `add`); `increment` auto-generates numeric
727
+ * keys; `indexes` declares secondary indexes.
728
+ * Stores are created from these definitions inside `onupgradeneeded`.
729
+ */
730
+ export declare interface StoreDefinition {
731
+ readonly path?: KeyPath;
732
+ readonly increment?: boolean;
733
+ readonly indexes?: readonly IndexDefinition[];
734
+ }
735
+
736
+ /** A database's stores — a map of store name to its {@link StoreDefinition}. */
737
+ export declare type StoresShape = Readonly<Record<string, StoreDefinition>>;
738
+
739
+ /**
740
+ * Map a native IndexedDB `DOMException` to a typed {@link IndexedDBError}.
741
+ *
742
+ * @remarks
743
+ * The boundary the two Promise bridges ({@link promisifyRequest} /
744
+ * {@link promisifyTransaction}) share: it reads {@link ERROR_CODES} to pick the
745
+ * machine-readable code for the native `name`, falling back to `UNKNOWN` for an
746
+ * unmapped name or a `null` error.
747
+ *
748
+ * @param error - The native error, or `null` when none is attached
749
+ * @returns The wrapped, typed error
750
+ */
751
+ export declare function wrapError(error: DOMException | null): IndexedDBError;
752
+
753
+ export { }