@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,27 +0,0 @@
1
- import type { IndexedDBDatabaseInterface, IndexedDBDatabaseOptions, IndexedDBStoreInterface, IndexedDBTransactionInterface, StoresShape } from './types.js';
2
- /**
3
- * A browser-native IndexedDB database — a typed, Promise-based handle.
4
- *
5
- * @remarks
6
- * Connects lazily on first use (`connect`, also awaited internally by every store
7
- * operation), creating any missing stores from their definitions inside
8
- * `onupgradeneeded`. `store` reaches a typed store; `read` / `write` run an atomic
9
- * scope over one or more stores, committing on resolve and rolling back on a throw;
10
- * `close` releases the connection and `drop` deletes the database. Schema changes
11
- * beyond creating new stores (dropping stores, altering indexes) are deferred.
12
- */
13
- export declare class IndexedDBDatabase<Stores extends StoresShape = StoresShape> implements IndexedDBDatabaseInterface<Stores> {
14
- #private;
15
- constructor(options: IndexedDBDatabaseOptions<Stores>);
16
- get database(): IDBDatabase;
17
- get name(): string;
18
- get version(): number;
19
- get stores(): readonly string[];
20
- get open(): boolean;
21
- connect(): Promise<IDBDatabase>;
22
- store<K extends keyof Stores & string>(name: K): IndexedDBStoreInterface;
23
- read(stores: (keyof Stores & string) | readonly (keyof Stores & string)[], scope: (tx: IndexedDBTransactionInterface<Stores>) => void | Promise<void>): Promise<void>;
24
- write(stores: (keyof Stores & string) | readonly (keyof Stores & string)[], scope: (tx: IndexedDBTransactionInterface<Stores>) => void | Promise<void>): Promise<void>;
25
- close(): void;
26
- drop(): Promise<void>;
27
- }
@@ -1,31 +0,0 @@
1
- import type { CursorOptions, IndexDefinition, IndexedDBCursorInterface, IndexedDBIndexInterface, KeyPath, Row } from './types.js';
2
- /**
3
- * A secondary index on a store — a read-only view keyed by an indexed path.
4
- *
5
- * @remarks
6
- * Reached through `store.index(name)`. Each call opens its own `readonly`
7
- * transaction. `get` / `resolve` fetch the first record for an index key
8
- * (`resolve` throws `NOT_FOUND`); `records` reads the matching records and `keys`
9
- * their **primary** keys; `primary` maps an index key to one primary key; `count`
10
- * / `has` test presence; `cursor` streams matches. Reads batch by their array
11
- * overload (AGENTS §9.2).
12
- */
13
- export declare class IndexedDBIndex implements IndexedDBIndexInterface {
14
- #private;
15
- constructor(store: string, name: string, definition: IndexDefinition, connect: () => Promise<IDBDatabase>);
16
- get name(): string;
17
- get path(): KeyPath;
18
- get unique(): boolean;
19
- get multiple(): boolean;
20
- get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
21
- get(key: IDBValidKey): Promise<Row | undefined>;
22
- resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
23
- resolve(key: IDBValidKey): Promise<Row>;
24
- records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
25
- keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
26
- primary(key: IDBValidKey): Promise<IDBValidKey | undefined>;
27
- has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
28
- has(key: IDBValidKey): Promise<boolean>;
29
- count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
30
- cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
31
- }
@@ -1,41 +0,0 @@
1
- import type { CursorOptions, IndexedDBCursorInterface, IndexedDBIndexInterface, IndexedDBStoreInterface, KeyPath, Row, StoreDefinition } from './types.js';
2
- /**
3
- * An object store — the full keyed CRUD surface plus index, count, and cursor
4
- * access.
5
- *
6
- * @remarks
7
- * Reached through `database.store(name)`. Each call runs in its own implicit
8
- * transaction (`readonly` for reads, `readwrite` for writes), awaiting completion
9
- * so writes are durable on return; for atomic multi-operation work use the
10
- * database's `read` / `write`. The keyed verbs batch by their array overload — and
11
- * those overloads are declared first, because an array is itself both a record and
12
- * a compound `IDBValidKey`, so the array signature must take precedence to read as
13
- * a batch (AGENTS §9.2). Pass `range.only([…])` to `records` / `count` to act on a
14
- * single compound key.
15
- */
16
- export declare class IndexedDBStore implements IndexedDBStoreInterface {
17
- #private;
18
- constructor(name: string, definition: StoreDefinition, connect: () => Promise<IDBDatabase>);
19
- get name(): string;
20
- get path(): KeyPath | null;
21
- get indexes(): readonly string[];
22
- get increment(): boolean;
23
- get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
24
- get(key: IDBValidKey): Promise<Row | undefined>;
25
- resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
26
- resolve(key: IDBValidKey): Promise<Row>;
27
- records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
28
- keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
29
- has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
30
- has(key: IDBValidKey): Promise<boolean>;
31
- count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
32
- set(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
33
- set(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
34
- add(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
35
- add(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
36
- remove(keys: readonly IDBValidKey[]): Promise<void>;
37
- remove(key: IDBValidKey): Promise<void>;
38
- clear(): Promise<void>;
39
- index(name: string): IndexedDBIndexInterface;
40
- cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
41
- }
@@ -1,24 +0,0 @@
1
- import type { IndexedDBTransactionInterface, IndexedDBTransactionStoreInterface, StoresShape } from './types.js';
2
- /**
3
- * An explicit transaction over one or more stores.
4
- *
5
- * @remarks
6
- * Wraps `IDBTransaction` with state tracking and typed, scope-bound store access.
7
- * Constructed by the database's `read` / `write`, which await its completion (or
8
- * roll it back on a throw). `store` reaches a store within the transaction's scope;
9
- * `abort` rolls back; `commit` flushes early (the scope's completion commits
10
- * otherwise). `active` is true until commit or abort; `finished` is its complement.
11
- */
12
- export declare class IndexedDBTransaction<Stores extends StoresShape = StoresShape> implements IndexedDBTransactionInterface<Stores> {
13
- #private;
14
- constructor(transaction: IDBTransaction);
15
- get transaction(): IDBTransaction;
16
- get mode(): IDBTransactionMode;
17
- get stores(): readonly string[];
18
- get active(): boolean;
19
- get finished(): boolean;
20
- get error(): DOMException | null;
21
- store<K extends keyof Stores & string>(name: K): IndexedDBTransactionStoreInterface;
22
- abort(): void;
23
- commit(): void;
24
- }
@@ -1,34 +0,0 @@
1
- import type { CursorOptions, IndexedDBCursorInterface, IndexedDBTransactionStoreInterface, Row } from './types.js';
2
- /**
3
- * An object store bound to an explicit transaction.
4
- *
5
- * @remarks
6
- * The same CRUD surface as a standalone store, but every call runs in the owning
7
- * transaction (opened by the database's `read` / `write`) rather than its own — so
8
- * a sequence of reads and writes commits atomically when the scope resolves. It
9
- * does not await transaction completion per call (the scope does that once) and
10
- * omits `index`; keep your awaited operations on IndexedDB requests only, so the
11
- * transaction stays active across them.
12
- */
13
- export declare class IndexedDBTransactionStore implements IndexedDBTransactionStoreInterface {
14
- #private;
15
- constructor(store: IDBObjectStore);
16
- get store(): IDBObjectStore;
17
- get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
18
- get(key: IDBValidKey): Promise<Row | undefined>;
19
- resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
20
- resolve(key: IDBValidKey): Promise<Row>;
21
- records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
22
- keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
23
- has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
24
- has(key: IDBValidKey): Promise<boolean>;
25
- count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
26
- set(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
27
- set(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
28
- add(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
29
- add(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
30
- remove(keys: readonly IDBValidKey[]): Promise<void>;
31
- remove(key: IDBValidKey): Promise<void>;
32
- clear(): Promise<void>;
33
- cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
34
- }
@@ -1,10 +0,0 @@
1
- import type { IndexedDBErrorCode } from './types.js';
2
- /**
3
- * Native `DOMException.name` → our {@link IndexedDBErrorCode}.
4
- *
5
- * @remarks
6
- * The mapping the request boundary's `wrapError` reads to translate a raw
7
- * IndexedDB fault into a typed {@link IndexedDBError} code; an unmapped name
8
- * falls back to `UNKNOWN`. Frozen plain data (AGENTS §5).
9
- */
10
- export declare const ERROR_CODES: Readonly<Record<string, IndexedDBErrorCode>>;
@@ -1,30 +0,0 @@
1
- import type { IndexedDBErrorCode } from './types.js';
2
- /**
3
- * An error thrown by the IndexedDB wrapper.
4
- *
5
- * @remarks
6
- * Carries an {@link IndexedDBErrorCode} and the originating native error as the
7
- * standard `cause`. Construct it directly for wrapper-lifecycle faults; the
8
- * internal `wrapError` maps a native `DOMException` to the right code at the
9
- * request boundary. Narrow a caught value with `instanceof IndexedDBError`.
10
- *
11
- * @example
12
- * ```ts
13
- * try {
14
- * await store.add(row)
15
- * } catch (error) {
16
- * if (error instanceof IndexedDBError && error.code === 'CONSTRAINT') await store.set(row)
17
- * }
18
- * ```
19
- */
20
- export declare class IndexedDBError extends Error {
21
- readonly code: IndexedDBErrorCode;
22
- constructor(code: IndexedDBErrorCode, message: string, cause?: unknown);
23
- }
24
- /**
25
- * Whether a value is an {@link IndexedDBError}.
26
- *
27
- * @param value - The value to test
28
- * @returns `true` when `value` is an `IndexedDBError`
29
- */
30
- export declare function isIndexedDBError(value: unknown): value is IndexedDBError;
@@ -1,30 +0,0 @@
1
- import type { IndexedDBDatabaseInterface, IndexedDBDatabaseOptions, StoresShape } from './types.js';
2
- /**
3
- * Create a browser-native IndexedDB database over a store schema.
4
- *
5
- * @remarks
6
- * The `const` type parameter captures the literal store names, so `db.store(name)`
7
- * and `db.read` / `db.write` are checked against the declared stores. Stores are
8
- * created from their definitions the first time the database opens at a new
9
- * `version`; omit `version` for auto-managed mode, where the database bumps its
10
- * own version once to create any declared store the stored schema is missing.
11
- *
12
- * @param options - The database `name`, `version`, and `stores` schema
13
- * @returns A typed {@link IndexedDBDatabaseInterface}
14
- *
15
- * @example
16
- * ```ts
17
- * import { createIndexedDBDatabase, range } from '@src/browser'
18
- *
19
- * const db = createIndexedDBDatabase({
20
- * name: 'app',
21
- * version: 1,
22
- * stores: {
23
- * users: { path: 'id', indexes: [{ name: 'byAge', path: 'age' }] },
24
- * },
25
- * })
26
- * await db.store('users').set({ id: 'u1', name: 'Ada', age: 36 })
27
- * await db.store('users').index('byAge').records(range.from(18)) // adults, index-backed
28
- * ```
29
- */
30
- export declare function createIndexedDBDatabase<const Stores extends StoresShape>(options: IndexedDBDatabaseOptions<Stores>): IndexedDBDatabaseInterface<Stores>;
@@ -1,130 +0,0 @@
1
- import type { Row } from './types.js';
2
- import { IndexedDBError } from './errors.js';
3
- /**
4
- * Whether IndexedDB is available in this environment.
5
- *
6
- * @remarks
7
- * Gate IndexedDB code with this and fall back to another storage strategy where
8
- * it is absent (a non-browser runtime, a privacy mode that disables storage).
9
- * The entry probe, checked before reaching for the rest of this module.
10
- *
11
- * @returns `true` when `globalThis.indexedDB` exists
12
- */
13
- export declare function isIndexedDBSupported(): boolean;
14
- /**
15
- * Resolve an `IDBRequest` to its result, rejecting with an {@link IndexedDBError}.
16
- *
17
- * @remarks
18
- * The single bridge from IndexedDB's event-based requests to Promises. Issue the
19
- * request, then `await` this — within an implicit transaction, issue every request
20
- * for that transaction before the first `await`, so they share it.
21
- *
22
- * @param request - The pending request
23
- * @returns Its `result` on success
24
- */
25
- export declare function promisifyRequest<T>(request: IDBRequest<T>): Promise<T>;
26
- /**
27
- * Resolve once an `IDBTransaction` commits, rejecting if it errors or aborts.
28
- *
29
- * @remarks
30
- * Await this after issuing the writes of a `readwrite` transaction to guarantee
31
- * they are durable before continuing.
32
- *
33
- * @param transaction - The transaction to await
34
- */
35
- export declare function promisifyTransaction(transaction: IDBTransaction): Promise<void>;
36
- /**
37
- * Run a synchronous native IndexedDB call, wrapping a thrown `DOMException`
38
- * into a typed {@link IndexedDBError}.
39
- *
40
- * @remarks
41
- * Native IndexedDB throws SYNCHRONOUSLY (not through a request's `onerror`)
42
- * from calls like `database.transaction(...)` or an inactive/closed store's
43
- * `get` / `put` / `openCursor` — `TransactionInactiveError` /
44
- * `InvalidStateError` never reach {@link promisifyRequest}'s `onerror`
45
- * bridge. Every request-issuing call site wraps its native invocation in this
46
- * so those faults surface as the same typed `IndexedDBError` as an
47
- * asynchronous one.
48
- *
49
- * @param action - The synchronous native call to run
50
- * @returns Its return value
51
- */
52
- export declare function guardSync<T>(action: () => T): T;
53
- /**
54
- * Read one record by key from a store or index, narrowing it to a {@link Row}.
55
- *
56
- * @remarks
57
- * The shared point-read of every store-like class (`IndexedDBStore`,
58
- * `IndexedDBIndex`, `IndexedDBTransactionStore`): issue the native `get`, then
59
- * narrow the structured clone with `isRecord` — a non-record (or a miss) reads as
60
- * `undefined`, never an unchecked cast. On an index, `source.get` returns the
61
- * first record for the index key.
62
- *
63
- * @param source - The object store or index to read from
64
- * @param key - The key (a primary key for a store, an index key for an index)
65
- * @returns The record, or `undefined` on a miss
66
- */
67
- export declare function readRecord(source: IDBObjectStore | IDBIndex, key: IDBValidKey): Promise<Row | undefined>;
68
- /**
69
- * Read many records from a store or index over an optional key range.
70
- *
71
- * @remarks
72
- * The shared bulk read of every store-like class: issue the native `getAll` over
73
- * an optional `query` (a key range or a single key) and `count` cap, then keep
74
- * only the records with `isRecord` — the same boundary narrowing as
75
- * {@link readRecord}, applied across the batch.
76
- *
77
- * @param source - The object store or index to read from
78
- * @param query - A key range or single key to restrict the read, or `null` for all
79
- * @param count - The maximum number of records to read
80
- * @returns The matching records
81
- */
82
- export declare function readRecords(source: IDBObjectStore | IDBIndex, query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
83
- /**
84
- * Whether a key is present in a store or index.
85
- *
86
- * @remarks
87
- * The shared presence test of every store-like class: a native `count` of the
88
- * key, true when at least one record matches — cheaper than reading the record
89
- * when only existence matters.
90
- *
91
- * @param source - The object store or index to test
92
- * @param key - The key to look for
93
- * @returns `true` when at least one record has the key
94
- */
95
- export declare function hasKey(source: IDBObjectStore | IDBIndex, key: IDBValidKey): Promise<boolean>;
96
- /**
97
- * Key-range builders — the wrapper's filter vocabulary.
98
- *
99
- * @remarks
100
- * Each returns an `IDBKeyRange` to pass to `records` / `keys` / `count` / `cursor`,
101
- * so a read is index-backed (O(log n)) rather than a full scan. `only` (exact),
102
- * `above` / `from` (greater than, exclusive / inclusive), `below` / `to` (less
103
- * than, exclusive / inclusive), `between` (bounded), and `prefix` (string
104
- * starts-with).
105
- */
106
- export declare const range: {
107
- only(value: IDBValidKey): IDBKeyRange;
108
- above(value: IDBValidKey): IDBKeyRange;
109
- from(value: IDBValidKey): IDBKeyRange;
110
- below(value: IDBValidKey): IDBKeyRange;
111
- to(value: IDBValidKey): IDBKeyRange;
112
- between(lower: IDBValidKey, upper: IDBValidKey, options?: {
113
- readonly lowerOpen?: boolean;
114
- readonly upperOpen?: boolean;
115
- }): IDBKeyRange;
116
- prefix(value: string): IDBKeyRange;
117
- };
118
- /**
119
- * Map a native IndexedDB `DOMException` to a typed {@link IndexedDBError}.
120
- *
121
- * @remarks
122
- * The boundary the two Promise bridges ({@link promisifyRequest} /
123
- * {@link promisifyTransaction}) share: it reads {@link ERROR_CODES} to pick the
124
- * machine-readable code for the native `name`, falling back to `UNKNOWN` for an
125
- * unmapped name or a `null` error.
126
- *
127
- * @param error - The native error, or `null` when none is attached
128
- * @returns The wrapped, typed error
129
- */
130
- export declare function wrapError(error: DOMException | null): IndexedDBError;
@@ -1,290 +0,0 @@
1
- /**
2
- * A record stored in, and read from, an object store.
3
- *
4
- * @remarks
5
- * The value shape every store / index / transaction-store CRUD method reads and
6
- * writes. A structured-clone value narrowed with `isRecord` at the read
7
- * boundary (see `helpers.ts`), never an unchecked cast.
8
- */
9
- export type Row = Record<string, unknown>;
10
- /**
11
- * A machine-readable {@link IndexedDBError} code.
12
- *
13
- * @remarks
14
- * Each maps from a native `DOMException.name` or a wrapper-lifecycle fault:
15
- * `NOT_OPEN` (used before `connect`), `CLOSED` (used after `close`), `NOT_FOUND`
16
- * (a `resolve` miss), `CONSTRAINT` (a unique-key violation), `QUOTA` (storage
17
- * full), `ABORTED` (a transaction rolled back), `BLOCKED` (an open held up by
18
- * another live connection), `DATA` (an invalid key or value), `OPEN` /
19
- * `UPGRADE` (a failed open or schema upgrade), `INACTIVE` (the transaction went
20
- * inactive — IndexedDB's auto-commit fault, raised when an operation runs after
21
- * a non-IDB `await` deactivated its transaction — reachable through
22
- * `IndexedDBTransactionStoreInterface`), `INVALID` (native `InvalidStateError` —
23
- * a defensive mapping for a deleted store/index or similarly invalid native
24
- * handle; not cleanly reachable through this wrapper's public API, which always
25
- * opens a fresh transaction or routes through the auto-commit-guarded
26
- * transaction store above), and `UNKNOWN` (any unmapped fault).
27
- */
28
- export type IndexedDBErrorCode = 'NOT_OPEN' | 'CLOSED' | 'NOT_FOUND' | 'CONSTRAINT' | 'QUOTA' | 'ABORTED' | 'BLOCKED' | 'DATA' | 'OPEN' | 'UPGRADE' | 'INACTIVE' | 'INVALID' | 'UNKNOWN';
29
- /**
30
- * A key path — one field, or several for a compound key.
31
- *
32
- * @remarks
33
- * A single string addresses one field; an array addresses a compound key over
34
- * several fields, in order.
35
- */
36
- export type KeyPath = string | readonly string[];
37
- /**
38
- * A secondary index on a store.
39
- *
40
- * @remarks
41
- * `name` identifies the index for `store.index(name)`; `path` is the field(s) it
42
- * indexes; `unique` enforces one record per indexed value; `multiple` (IndexedDB's
43
- * `multiEntry`) indexes each element of an array value separately.
44
- */
45
- export interface IndexDefinition {
46
- readonly name: string;
47
- readonly path: KeyPath;
48
- readonly unique?: boolean;
49
- readonly multiple?: boolean;
50
- }
51
- /**
52
- * A store's schema.
53
- *
54
- * @remarks
55
- * `path` is the in-line key path (omit it for an **out-of-line** store, where the
56
- * key is passed explicitly to `set` / `add`); `increment` auto-generates numeric
57
- * keys; `indexes` declares secondary indexes.
58
- * Stores are created from these definitions inside `onupgradeneeded`.
59
- */
60
- export interface StoreDefinition {
61
- readonly path?: KeyPath;
62
- readonly increment?: boolean;
63
- readonly indexes?: readonly IndexDefinition[];
64
- }
65
- /** A database's stores — a map of store name to its {@link StoreDefinition}. */
66
- export type StoresShape = Readonly<Record<string, StoreDefinition>>;
67
- /**
68
- * The escape hatch into a version-change upgrade, passed to
69
- * `IndexedDBDatabaseOptions.upgrade`.
70
- *
71
- * @remarks
72
- * Runs INSIDE `onupgradeneeded`, after the built-in create-missing-stores pass —
73
- * so `stores` already reflects any store just created from the declared schema.
74
- * `transaction` is the raw versionchange `IDBTransaction`, the escape hatch for
75
- * native operations this wrapper does not model directly (creating or dropping an
76
- * index on an EXISTING store, or anything else the raw API offers); `old` /
77
- * `version` are the prior and target database versions (`old` is `0` on first
78
- * create); `create` / `drop` add or remove a whole store; `store` reaches a
79
- * transaction-bound store for data migration. Everything invoked here must stay
80
- * within the versionchange transaction — no non-IDB `await`, or it auto-commits
81
- * and the upgrade fails.
82
- */
83
- export interface IndexedDBUpgradeContext {
84
- readonly transaction: IDBTransaction;
85
- readonly old: number;
86
- readonly version: number;
87
- readonly stores: readonly string[];
88
- create(name: string, definition: StoreDefinition): void;
89
- drop(name: string): void;
90
- store(name: string): IndexedDBTransactionStoreInterface;
91
- }
92
- /**
93
- * Options for `createIndexedDBDatabase`.
94
- *
95
- * @remarks
96
- * `name` is passed to `indexedDB.open`. `version` is optional: give it to pin an
97
- * explicit schema version (a higher number than the stored one triggers an upgrade
98
- * that creates any missing `stores`); omit it for **auto-managed** mode, where the
99
- * database opens at its current version and bumps once to create any declared store
100
- * the stored schema is missing — so adding a store never needs a manual version
101
- * bump. `upgrade` runs after the built-in create-missing-stores pass, inside the
102
- * same versionchange transaction — use it to drop a store, add or remove an index
103
- * on an existing store (via `context.transaction`), or migrate data with
104
- * `context.store(name)`. It may return `void` or a `Promise<void>` — an async
105
- * `upgrade` may `await` the IDB requests it issues through `context.store(...)`
106
- * (see the auto-commit rule on {@link IndexedDBUpgradeContext}); a rejection
107
- * aborts the versionchange transaction and rejects the pending `connect()` with
108
- * an `IndexedDBError` (code `UPGRADE`) instead of an unhandled rejection.
109
- */
110
- export interface IndexedDBDatabaseOptions<Stores extends StoresShape = StoresShape> {
111
- readonly name: string;
112
- readonly version?: number;
113
- readonly stores: Stores;
114
- readonly upgrade?: (context: IndexedDBUpgradeContext) => void | Promise<void>;
115
- }
116
- /**
117
- * Options for opening a cursor.
118
- *
119
- * @remarks
120
- * `query` restricts iteration to a key range (or a single key); `direction` sets
121
- * the traversal order (`next` / `prev` / their `unique` variants).
122
- */
123
- export interface CursorOptions {
124
- readonly query?: IDBKeyRange | IDBValidKey | null;
125
- readonly direction?: IDBCursorDirection;
126
- }
127
- /**
128
- * A promisified value cursor for streaming and in-place mutation.
129
- *
130
- * @remarks
131
- * Wraps `IDBCursorWithValue`. `key` / `primary` / `value` snapshot the current
132
- * position (IndexedDB reuses the live cursor object on advance, so they are read
133
- * eagerly). `continue` / `seek` / `advance` resolve to the next cursor or `null`
134
- * at the end; `update` / `delete` mutate the record at the current position. The
135
- * owning transaction stays alive only while you drive the cursor promptly — do no
136
- * unrelated `await` between steps, or it auto-commits.
137
- */
138
- export interface IndexedDBCursorInterface {
139
- readonly cursor: IDBCursorWithValue;
140
- readonly source: IDBObjectStore | IDBIndex;
141
- readonly key: IDBValidKey;
142
- readonly primary: IDBValidKey;
143
- readonly value: Row;
144
- readonly direction: IDBCursorDirection;
145
- continue(key?: IDBValidKey): Promise<IndexedDBCursorInterface | null>;
146
- seek(key: IDBValidKey, primary: IDBValidKey): Promise<IndexedDBCursorInterface | null>;
147
- advance(count: number): Promise<IndexedDBCursorInterface | null>;
148
- update(value: Row): Promise<IDBValidKey>;
149
- delete(): Promise<void>;
150
- }
151
- /**
152
- * A secondary index — read access by an indexed key path.
153
- *
154
- * @remarks
155
- * Indexes are read-only views over a store. `get` / `resolve` fetch the first
156
- * record for an index key (`resolve` throws `NOT_FOUND` on a miss); `records` /
157
- * `keys` read many (the matching records, and their **primary** keys); `primary`
158
- * maps an index key to one primary key; `count` / `has` test presence; `cursor`
159
- * streams matches. A read of several keys is the array overload of the same verb
160
- * (AGENTS §9.2).
161
- */
162
- export interface IndexedDBIndexInterface {
163
- readonly name: string;
164
- readonly path: KeyPath;
165
- readonly unique: boolean;
166
- readonly multiple: boolean;
167
- get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
168
- get(key: IDBValidKey): Promise<Row | undefined>;
169
- resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
170
- resolve(key: IDBValidKey): Promise<Row>;
171
- records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
172
- keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
173
- primary(key: IDBValidKey): Promise<IDBValidKey | undefined>;
174
- has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
175
- has(key: IDBValidKey): Promise<boolean>;
176
- count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
177
- cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
178
- }
179
- /**
180
- * An object store — the full keyed CRUD surface, plus index, count, and cursor
181
- * access.
182
- *
183
- * @remarks
184
- * Each call runs in its own implicit transaction; for atomic multi-operation work
185
- * use the database's `read` / `write`. `get` / `resolve` read by key (`resolve`
186
- * throws `NOT_FOUND`); `records` / `keys` read many over an optional key range;
187
- * `set` upserts and `add` inserts (throwing `CONSTRAINT` on a duplicate);
188
- * `remove` deletes; `clear` empties the store. The keyed verbs batch by their
189
- * array overload — listed first, since an array is itself a valid record and a
190
- * compound `IDBValidKey`, so the array signature must win (AGENTS §9.2). To act on
191
- * a single **compound** key, pass `range.only([…])` to `records` / `count`.
192
- */
193
- export interface IndexedDBStoreInterface {
194
- readonly name: string;
195
- readonly path: KeyPath | null;
196
- readonly indexes: readonly string[];
197
- readonly increment: boolean;
198
- get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
199
- get(key: IDBValidKey): Promise<Row | undefined>;
200
- resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
201
- resolve(key: IDBValidKey): Promise<Row>;
202
- records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
203
- keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
204
- has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
205
- has(key: IDBValidKey): Promise<boolean>;
206
- count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
207
- set(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
208
- set(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
209
- add(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
210
- add(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
211
- remove(keys: readonly IDBValidKey[]): Promise<void>;
212
- remove(key: IDBValidKey): Promise<void>;
213
- clear(): Promise<void>;
214
- index(name: string): IndexedDBIndexInterface;
215
- cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
216
- }
217
- /**
218
- * An object store bound to an explicit transaction.
219
- *
220
- * @remarks
221
- * The same CRUD surface as {@link IndexedDBStoreInterface}, but every call runs in
222
- * the owning transaction (opened by the database's `read` / `write`) rather than
223
- * its own — so a sequence of reads and writes is atomic. It drops `index` and the
224
- * standalone implicit-transaction conveniences; reach the live `store` for those.
225
- */
226
- export interface IndexedDBTransactionStoreInterface {
227
- readonly store: IDBObjectStore;
228
- get(keys: readonly IDBValidKey[]): Promise<readonly (Row | undefined)[]>;
229
- get(key: IDBValidKey): Promise<Row | undefined>;
230
- resolve(keys: readonly IDBValidKey[]): Promise<readonly Row[]>;
231
- resolve(key: IDBValidKey): Promise<Row>;
232
- records(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly Row[]>;
233
- keys(query?: IDBKeyRange | IDBValidKey | null, count?: number): Promise<readonly IDBValidKey[]>;
234
- has(keys: readonly IDBValidKey[]): Promise<readonly boolean[]>;
235
- has(key: IDBValidKey): Promise<boolean>;
236
- count(query?: IDBKeyRange | IDBValidKey | null): Promise<number>;
237
- set(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
238
- set(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
239
- add(values: readonly Row[]): Promise<readonly IDBValidKey[]>;
240
- add(value: Row, key?: IDBValidKey): Promise<IDBValidKey>;
241
- remove(keys: readonly IDBValidKey[]): Promise<void>;
242
- remove(key: IDBValidKey): Promise<void>;
243
- clear(): Promise<void>;
244
- cursor(options?: CursorOptions): Promise<IndexedDBCursorInterface | null>;
245
- }
246
- /**
247
- * An explicit transaction over one or more stores.
248
- *
249
- * @remarks
250
- * Obtained through the `scope` callback of the database's `read` / `write`. `store`
251
- * reaches a typed, transaction-bound store; the transaction commits automatically
252
- * when the scope resolves, or rolls back if it throws or `abort` is called.
253
- * `active` is true while it still accepts operations; `finished` is true after
254
- * commit or abort.
255
- */
256
- export interface IndexedDBTransactionInterface<Stores extends StoresShape = StoresShape> {
257
- readonly transaction: IDBTransaction;
258
- readonly mode: IDBTransactionMode;
259
- readonly stores: readonly string[];
260
- readonly active: boolean;
261
- readonly finished: boolean;
262
- readonly error: DOMException | null;
263
- store<K extends keyof Stores & string>(name: K): IndexedDBTransactionStoreInterface;
264
- abort(): void;
265
- commit(): void;
266
- }
267
- /**
268
- * A browser-native IndexedDB database.
269
- *
270
- * @remarks
271
- * A typed, Promise-based handle over `IDBDatabase`. It connects lazily on first
272
- * use (`connect`, also awaited by every store operation); `store` reaches a typed
273
- * store; `read` / `write` run an atomic scope over one or more stores; `close`
274
- * releases the connection and `drop` deletes the database. `stores` lists the
275
- * declared (or, once open, the live) store names; `open` reports whether a live
276
- * connection is held.
277
- */
278
- export interface IndexedDBDatabaseInterface<Stores extends StoresShape = StoresShape> {
279
- readonly database: IDBDatabase;
280
- readonly name: string;
281
- readonly version: number;
282
- readonly stores: readonly string[];
283
- readonly open: boolean;
284
- connect(): Promise<IDBDatabase>;
285
- store<K extends keyof Stores & string>(name: K): IndexedDBStoreInterface;
286
- read(stores: (keyof Stores & string) | readonly (keyof Stores & string)[], scope: (tx: IndexedDBTransactionInterface<Stores>) => void | Promise<void>): Promise<void>;
287
- write(stores: (keyof Stores & string) | readonly (keyof Stores & string)[], scope: (tx: IndexedDBTransactionInterface<Stores>) => void | Promise<void>): Promise<void>;
288
- close(): void;
289
- drop(): Promise<void>;
290
- }