web-idb-client 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +230 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.js +12 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/indexed-db-client.d.ts +40 -0
- package/dist/client/indexed-db-client.js +211 -0
- package/dist/client/indexed-db-client.js.map +1 -0
- package/dist/client/mutations.d.ts +12 -0
- package/dist/client/mutations.js +3 -0
- package/dist/client/mutations.js.map +1 -0
- package/dist/client/store.d.ts +42 -0
- package/dist/client/store.js +356 -0
- package/dist/client/store.js.map +1 -0
- package/dist/client/transaction.d.ts +14 -0
- package/dist/client/transaction.js +37 -0
- package/dist/client/transaction.js.map +1 -0
- package/dist/errors/index.d.ts +15 -0
- package/dist/errors/index.js +35 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/liveQuery/index.d.ts +31 -0
- package/dist/liveQuery/index.js +216 -0
- package/dist/liveQuery/index.js.map +1 -0
- package/dist/migrate/diff.d.ts +28 -0
- package/dist/migrate/diff.js +89 -0
- package/dist/migrate/diff.js.map +1 -0
- package/dist/migrate/helpers.d.ts +29 -0
- package/dist/migrate/helpers.js +89 -0
- package/dist/migrate/helpers.js.map +1 -0
- package/dist/migrate/index.d.ts +6 -0
- package/dist/migrate/index.js +14 -0
- package/dist/migrate/index.js.map +1 -0
- package/dist/migrate/upgrade.d.ts +19 -0
- package/dist/migrate/upgrade.js +123 -0
- package/dist/migrate/upgrade.js.map +1 -0
- package/dist/query/order.d.ts +8 -0
- package/dist/query/order.js +30 -0
- package/dist/query/order.js.map +1 -0
- package/dist/query/where.d.ts +17 -0
- package/dist/query/where.js +106 -0
- package/dist/query/where.js.map +1 -0
- package/dist/relation/define-relation.d.ts +49 -0
- package/dist/relation/define-relation.js +101 -0
- package/dist/relation/define-relation.js.map +1 -0
- package/dist/relation/index.d.ts +3 -0
- package/dist/relation/index.js +14 -0
- package/dist/relation/index.js.map +1 -0
- package/dist/relation/load-related.d.ts +21 -0
- package/dist/relation/load-related.js +54 -0
- package/dist/relation/load-related.js.map +1 -0
- package/dist/schema/define-db.d.ts +5 -0
- package/dist/schema/define-db.js +41 -0
- package/dist/schema/define-db.js.map +1 -0
- package/dist/schema/define-store.d.ts +17 -0
- package/dist/schema/define-store.js +95 -0
- package/dist/schema/define-store.js.map +1 -0
- package/dist/schema/fields.d.ts +75 -0
- package/dist/schema/fields.js +90 -0
- package/dist/schema/fields.js.map +1 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.js +22 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/infer.d.ts +131 -0
- package/dist/schema/infer.js +3 -0
- package/dist/schema/infer.js.map +1 -0
- package/dist/schema/infer.test-types.d.ts +11 -0
- package/dist/schema/infer.test-types.js +80 -0
- package/dist/schema/infer.test-types.js.map +1 -0
- package/dist/schema/types.d.ts +55 -0
- package/dist/schema/types.js +3 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/utils/assert-keys.d.ts +3 -0
- package/dist/utils/assert-keys.js +15 -0
- package/dist/utils/assert-keys.js.map +1 -0
- package/dist/utils/boolean-codec.d.ts +23 -0
- package/dist/utils/boolean-codec.js +149 -0
- package/dist/utils/boolean-codec.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +16 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/key-range.d.ts +14 -0
- package/dist/utils/key-range.js +157 -0
- package/dist/utils/key-range.js.map +1 -0
- package/dist/utils/promisify.d.ts +2 -0
- package/dist/utils/promisify.js +29 -0
- package/dist/utils/promisify.js.map +1 -0
- package/dist/utils/type-utils.d.ts +2 -0
- package/dist/utils/type-utils.js +3 -0
- package/dist/utils/type-utils.js.map +1 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Sergey Azarov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# IndexedDbClient
|
|
2
|
+
|
|
3
|
+
Typed IndexedDB client for the **browser** (`web-idb-client`) with a Prisma-like store API, schema-in-TypeScript factories, and explicit migrations.
|
|
4
|
+
|
|
5
|
+
> 🇷🇺 [Читать на русском языке](README_RU.md)
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Schema via `defineStore` / `field.*` — `InferSelect` / `InferInsert` without codegen
|
|
10
|
+
- Store API: `insert`, `find`, `findMany`, `findUnique`, `update`, `delete`, `count`, `clear`
|
|
11
|
+
- Index-only `where` (equality + ranges) and `orderBy` / `take` / `skip`
|
|
12
|
+
- Multi-store `transaction('r' | 'rw', stores, fn)`
|
|
13
|
+
- Versioned `open` with schema diff + optional `upgrade` hooks
|
|
14
|
+
- Opt-in [`liveQuery`](docs/liveQuery.md) plugin for same/cross-tab UI invalidation
|
|
15
|
+
|
|
16
|
+
## When to use / When not to use
|
|
17
|
+
|
|
18
|
+
**Use this library** when you need a typed, Prisma-shaped API over real IndexedDB in the **browser** — typically for **private or corporate web** apps: internal SPAs, account cabinets, form drafts, client-side caches, multi-step wizards with local state. Such cases exist, but they are **relatively uncommon**; pick this library deliberately, not as a default “better localStorage”.
|
|
19
|
+
|
|
20
|
+
**Do not use this library** when you need:
|
|
21
|
+
|
|
22
|
+
- **Mobile / React Native** as the primary platform — use mature options there (e.g. WatermelonDB, RxDB)
|
|
23
|
+
- **Offline-first sync / replication** across devices — that is a different product category (e.g. RxDB)
|
|
24
|
+
- A battle-tested IndexedDB ecosystem with plugins, liveQuery, and years of production hardening — prefer **Dexie**
|
|
25
|
+
- A minimal get/put/cursor wrapper with no ORM surface — prefer **idb**
|
|
26
|
+
- SQL in the browser (WASM SQLite/Postgres) — prefer Drizzle/Kysely-style stacks
|
|
27
|
+
|
|
28
|
+
**Platform:** browser IndexedDB only. Not aimed at Node (unless you polyfill IndexedDB) and **not** planned as a mobile SDK.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install web-idb-client
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick start
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import {
|
|
40
|
+
createClient,
|
|
41
|
+
defineStore,
|
|
42
|
+
field,
|
|
43
|
+
type InferSelect,
|
|
44
|
+
} from 'web-idb-client';
|
|
45
|
+
|
|
46
|
+
const tasks = defineStore('tasks', {
|
|
47
|
+
id: field.number().primaryKey({ autoIncrement: true }),
|
|
48
|
+
name: field.string().index('byName'),
|
|
49
|
+
isDone: field.boolean().index('byDone'),
|
|
50
|
+
createdAt: field.date().index('byCreatedAt'),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
type Task = InferSelect<typeof tasks>;
|
|
54
|
+
|
|
55
|
+
const db = createClient({
|
|
56
|
+
name: 'myApp',
|
|
57
|
+
version: 1,
|
|
58
|
+
stores: { tasks },
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
await db.open();
|
|
62
|
+
|
|
63
|
+
const id = await db.tasks.insert({
|
|
64
|
+
name: 'Learn IndexedDB',
|
|
65
|
+
isDone: false,
|
|
66
|
+
createdAt: new Date(),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const task: Task | null = await db.tasks.find({ where: { id } });
|
|
70
|
+
|
|
71
|
+
const byName = await db.tasks.findMany({
|
|
72
|
+
where: { name: 'Learn IndexedDB' },
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const newest = await db.tasks.findMany({
|
|
76
|
+
orderBy: { createdAt: 'desc' },
|
|
77
|
+
take: 10,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await db.tasks.update({
|
|
81
|
+
where: { id },
|
|
82
|
+
data: { isDone: true },
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await db.transaction('rw', ['tasks'], async (tx) => {
|
|
86
|
+
await tx.tasks.insert({
|
|
87
|
+
name: 'In a transaction',
|
|
88
|
+
isDone: false,
|
|
89
|
+
createdAt: new Date(),
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Schema
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { defineStore, compoundIndex, field } from 'web-idb-client';
|
|
98
|
+
|
|
99
|
+
const tasks = defineStore(
|
|
100
|
+
'tasks',
|
|
101
|
+
{
|
|
102
|
+
id: field.number().primaryKey({ autoIncrement: true }),
|
|
103
|
+
title: field.string(),
|
|
104
|
+
status: field.string().index('byStatus'),
|
|
105
|
+
tags: field.array(field.string()).multiEntry('byTags'),
|
|
106
|
+
userId: field.string(),
|
|
107
|
+
dueAt: field.date().optional(),
|
|
108
|
+
},
|
|
109
|
+
() => [compoundIndex('byUserDue', ['userId', 'dueAt'])],
|
|
110
|
+
);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Field helpers: `field.string`, `field.number`, `field.boolean`, `field.date`, `field.json`, `field.array`.
|
|
114
|
+
Chain: `.optional()`, `.primaryKey({ autoIncrement? })`, `.ref(store)`, `.index(name)`, `.uniqueIndex(name)`, `.multiEntry(name)`.
|
|
115
|
+
|
|
116
|
+
Only PK and fields with `.index()` / `.uniqueIndex()` / `.multiEntry()` / `compoundIndex()` become IndexedDB indexes. Other fields are typed for insert/select only.
|
|
117
|
+
|
|
118
|
+
FK fields: prefer `.ref(users).index('byUserId')` (or `.ref('users')`) then `loadMany` / `loadOne`; relation endpoints via `end(users, 'id')` — see [docs/relations.md](docs/relations.md). There is **no** Prisma-style `include`.
|
|
119
|
+
|
|
120
|
+
### Boolean fields and indexes
|
|
121
|
+
|
|
122
|
+
IndexedDB keys **cannot** be `true` / `false`. For every `field.boolean()` (indexed or not) the client:
|
|
123
|
+
|
|
124
|
+
- accepts and returns **`boolean`** in the TypeScript API (`insert`, `where`, `findMany`, …);
|
|
125
|
+
- stores **`0 | 1`** in the object store so indexes like `.index('byDone')` work.
|
|
126
|
+
|
|
127
|
+
**In DevTools / Application → IndexedDB you will see numbers (`0` / `1`), not booleans.** The app still gets `boolean`. Legacy rows that already contain `true`/`false` are decoded on read; rewrite them to `0|1` on upgrade if you add a boolean index later.
|
|
128
|
+
|
|
129
|
+
## Store methods
|
|
130
|
+
|
|
131
|
+
| Method | Returns | Notes |
|
|
132
|
+
| --- | --- | --- |
|
|
133
|
+
| `insert(data)` | `IDBValidKey` | `add`; autoIncrement PK optional on insert |
|
|
134
|
+
| `insertMany(data[])` | `IDBValidKey[]` | Sequential adds on one store tx |
|
|
135
|
+
| `find({ where, orderBy? })` | `T \| null` | First match (Prisma `findFirst` style) |
|
|
136
|
+
| `findMany({ where?, orderBy?, take?, skip?, sortInMemory? })` | `T[]` | List |
|
|
137
|
+
| `findUnique({ where })` | `T \| null` | PK or unique index only |
|
|
138
|
+
| `update({ where, data })` / `updateMany` | `number` | Rows modified |
|
|
139
|
+
| `delete({ where })` / `deleteMany` | `number` | Rows deleted |
|
|
140
|
+
| `count({ where? })` | `number` | |
|
|
141
|
+
| `clear()` | `void` | Clears the store |
|
|
142
|
+
|
|
143
|
+
`where` must target the primary key or a declared index (field name or index name).
|
|
144
|
+
|
|
145
|
+
Range operators (map to `IDBKeyRange`): `equals`, `gt` / `gte` / `lt` / `lte`, aliases `above` / `aboveOrEqual` / `below` / `belowOrEqual`, `startsWith` (string prefix), `between: [lo, hi]` (optional open flags).
|
|
146
|
+
|
|
147
|
+
Compound indexes:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// exact key
|
|
151
|
+
where: { byUserDue: [userId, dueAt] }
|
|
152
|
+
// exact prefix + range on the last part only
|
|
153
|
+
where: { byUserDue: [userId, { gte: dueAt }] }
|
|
154
|
+
// or object form matching the compound keyPath fields
|
|
155
|
+
where: { userId, dueAt: { between: [a, b] } }
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
If `where` and `orderBy` use different indexes, pass `sortInMemory: true` (fetches the `where` set, then sorts in JS — can be expensive). Otherwise the client throws `QUERY_INVALID`.
|
|
159
|
+
|
|
160
|
+
Bulk helpers: `insertMany`, `updateMany`, `deleteMany` (the last two are aliases of multi-row `update` / `delete`).
|
|
161
|
+
|
|
162
|
+
## Client methods
|
|
163
|
+
|
|
164
|
+
| Method | Notes |
|
|
165
|
+
| --- | --- |
|
|
166
|
+
| `open()` / `init()` | Opens DB; creates/upgrades stores & indexes |
|
|
167
|
+
| `close()` | Closes connection |
|
|
168
|
+
| `deleteDatabase()` | Deletes the whole DB |
|
|
169
|
+
| `transaction(mode, storeNames, fn)` | `mode`: `'r'` \| `'rw'`; `fn` receives typed stores on one `IDBTransaction` |
|
|
170
|
+
|
|
171
|
+
Also available: `new IndexedDbClient({ name, version, stores })` (same config as `createClient`).
|
|
172
|
+
|
|
173
|
+
Upgrade hooks (keyed by target version):
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
const db = createClient({
|
|
177
|
+
name: 'myApp',
|
|
178
|
+
version: 2,
|
|
179
|
+
stores: { tasks },
|
|
180
|
+
upgrade: {
|
|
181
|
+
2: (tx) => {
|
|
182
|
+
// data transforms during versionchange on `tx`
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Changing a store `keyPath` in place is rejected with `SCHEMA_MISMATCH` unless you recreate the store in an upgrade hook via `copyStoreAndDrop` — see [docs/upgrades.md](docs/upgrades.md).
|
|
189
|
+
|
|
190
|
+
## Errors
|
|
191
|
+
|
|
192
|
+
Thrown as `IndexedDbError` with `code`: `NOT_OPEN`, `SCHEMA_INVALID`, `SCHEMA_MISMATCH`, `QUERY_INVALID`, `TRANSACTION_FAILED`, `OPEN_FAILED`, `BLOCKED`.
|
|
193
|
+
Optional context fields: `store`, `index`, `field` (also appended to `message`).
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const db = createClient({
|
|
197
|
+
name: 'myApp',
|
|
198
|
+
version: 1,
|
|
199
|
+
stores: { tasks },
|
|
200
|
+
// Reject unknown keys on insert (helpful in corp TS codebases)
|
|
201
|
+
strictInsert: true,
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Breaking changes from `@azarov-serge/indexed-db-client`
|
|
206
|
+
|
|
207
|
+
- Install / import **`web-idb-client`** (this package)
|
|
208
|
+
- Removed `from().select` / string-based config (`dbName`, `storageNames`, `storeNameToIndexes`)
|
|
209
|
+
- Use `defineStore` + `createClient` / `new IndexedDbClient({ name, version, stores })`
|
|
210
|
+
- Prefer `find` / `findMany` instead of `select`
|
|
211
|
+
|
|
212
|
+
## Docs
|
|
213
|
+
|
|
214
|
+
- [Upgrades / migrations](docs/upgrades.md) · [RU](docs/upgrades.ru.md)
|
|
215
|
+
- [Relations (FK helpers)](docs/relations.md) · [RU](docs/relations.ru.md)
|
|
216
|
+
- [liveQuery (opt-in)](docs/liveQuery.md) · [RU](docs/liveQuery.ru.md)
|
|
217
|
+
- Internal notes: [API design (v2)](.docs/indexeddb-client-v2-api-design.md) · [ORM research](.docs/indexeddb-orm-research.md) · [PLAN](.docs/PLAN.md)
|
|
218
|
+
|
|
219
|
+
## Examples
|
|
220
|
+
|
|
221
|
+
- **UI demo:** [examples/todo](examples/todo) — Vite + Tailwind CSS
|
|
222
|
+
Local: `npm run demo:dev` → open the URL Vite prints (base path `/indexed-db-client/`)
|
|
223
|
+
Overview: [examples/README.md](examples/README.md)
|
|
224
|
+
- **Relations demo:** [examples/relations](examples/relations) — users + tasks (`npm run relations:dev`)
|
|
225
|
+
- **Upgrade recipes:** [docs/upgrades.md](docs/upgrades.md)
|
|
226
|
+
- **Relations guide:** [docs/relations.md](docs/relations.md)
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { IndexedDbClient, createClient } from './indexed-db-client';
|
|
2
|
+
export type { IndexedDbClientWithStores } from './indexed-db-client';
|
|
3
|
+
export { Store } from './store';
|
|
4
|
+
export type { StoreContextInterface } from './store';
|
|
5
|
+
export { Transaction, toIndexedDbTransactionMode } from './transaction';
|
|
6
|
+
export type { TransactionMode, TxStores } from './transaction';
|
|
7
|
+
export type { MutationBatch, MutationListener, MutationOp, StoreMutationEvent, } from './mutations';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toIndexedDbTransactionMode = exports.Transaction = exports.Store = exports.createClient = exports.IndexedDbClient = void 0;
|
|
4
|
+
var indexed_db_client_1 = require("./indexed-db-client");
|
|
5
|
+
Object.defineProperty(exports, "IndexedDbClient", { enumerable: true, get: function () { return indexed_db_client_1.IndexedDbClient; } });
|
|
6
|
+
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return indexed_db_client_1.createClient; } });
|
|
7
|
+
var store_1 = require("./store");
|
|
8
|
+
Object.defineProperty(exports, "Store", { enumerable: true, get: function () { return store_1.Store; } });
|
|
9
|
+
var transaction_1 = require("./transaction");
|
|
10
|
+
Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return transaction_1.Transaction; } });
|
|
11
|
+
Object.defineProperty(exports, "toIndexedDbTransactionMode", { enumerable: true, get: function () { return transaction_1.toIndexedDbTransactionMode; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":";;;AAAA,yDAAoE;AAA3D,oHAAA,eAAe,OAAA;AAAE,iHAAA,YAAY,OAAA;AAEtC,iCAAgC;AAAvB,8FAAA,KAAK,OAAA;AAEd,6CAAwE;AAA/D,0GAAA,WAAW,OAAA;AAAE,yHAAA,0BAA0B,OAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DbConfigInterface, DbStoresInterface } from '../schema/types';
|
|
2
|
+
import { Store } from './store';
|
|
3
|
+
import { type TransactionMode, type TxStores } from './transaction';
|
|
4
|
+
import type { MutationListener } from './mutations';
|
|
5
|
+
type ClientStores<TStores extends DbStoresInterface> = {
|
|
6
|
+
[K in keyof TStores]: Store<TStores[K]>;
|
|
7
|
+
};
|
|
8
|
+
export declare class IndexedDbClient<TStores extends DbStoresInterface = DbStoresInterface> {
|
|
9
|
+
private readonly config;
|
|
10
|
+
private db;
|
|
11
|
+
private readonly _stores;
|
|
12
|
+
private readonly mutationListeners;
|
|
13
|
+
constructor(config: DbConfigInterface<TStores>);
|
|
14
|
+
/** Typed store accessors (also available as `db.<storeName>`). */
|
|
15
|
+
get stores(): ClientStores<TStores>;
|
|
16
|
+
get isOpen(): boolean;
|
|
17
|
+
get name(): string;
|
|
18
|
+
get version(): number;
|
|
19
|
+
/**
|
|
20
|
+
* Subscribe to store mutations (same-tab). Used by the liveQuery plugin;
|
|
21
|
+
* also useful for custom UI invalidation.
|
|
22
|
+
*/
|
|
23
|
+
subscribeMutations(listener: MutationListener): () => void;
|
|
24
|
+
/** @internal Notify mutation listeners (and liveQuery / cross-tab bridges). */
|
|
25
|
+
emitMutations(stores: string[], remote?: boolean): void;
|
|
26
|
+
open(): Promise<this>;
|
|
27
|
+
/** Alias for open() for familiarity with v1 `init`. */
|
|
28
|
+
init(): Promise<this>;
|
|
29
|
+
close(): void;
|
|
30
|
+
deleteDatabase(): Promise<void>;
|
|
31
|
+
transaction<T>(mode: TransactionMode, storeNames: (keyof TStores & string)[], fn: (tx: TxStores<TStores>) => Promise<T> | T): Promise<T>;
|
|
32
|
+
private openDatabase;
|
|
33
|
+
private deleteDatabaseRequest;
|
|
34
|
+
private requireDb;
|
|
35
|
+
private requireStore;
|
|
36
|
+
}
|
|
37
|
+
export type IndexedDbClientWithStores<TStores extends DbStoresInterface> = IndexedDbClient<TStores> & ClientStores<TStores>;
|
|
38
|
+
/** Construct a client with store properties typed on the instance. */
|
|
39
|
+
export declare function createClient<TStores extends DbStoresInterface>(config: DbConfigInterface<TStores>): IndexedDbClientWithStores<TStores>;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createClient = exports.IndexedDbClient = void 0;
|
|
13
|
+
const define_db_1 = require("../schema/define-db");
|
|
14
|
+
const upgrade_1 = require("../migrate/upgrade");
|
|
15
|
+
const store_1 = require("./store");
|
|
16
|
+
const transaction_1 = require("./transaction");
|
|
17
|
+
const errors_1 = require("../errors");
|
|
18
|
+
class IndexedDbClient {
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.db = null;
|
|
21
|
+
this.mutationListeners = new Set();
|
|
22
|
+
this.config = config;
|
|
23
|
+
const stores = {};
|
|
24
|
+
for (const key of Object.keys(config.stores)) {
|
|
25
|
+
const def = config.stores[key];
|
|
26
|
+
stores[key] = new store_1.Store(def, {
|
|
27
|
+
getObjectStore: (mode) => this.requireStore(def.name, mode),
|
|
28
|
+
strictInsert: Boolean(config.strictInsert),
|
|
29
|
+
onMutate: (event) => this.emitMutations([event.store]),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
this._stores = stores;
|
|
33
|
+
// Expose stores as enumerable properties: db.tasks
|
|
34
|
+
for (const key of Object.keys(stores)) {
|
|
35
|
+
Object.defineProperty(this, key, {
|
|
36
|
+
get: () => this._stores[key],
|
|
37
|
+
enumerable: true,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Typed store accessors (also available as `db.<storeName>`). */
|
|
42
|
+
get stores() {
|
|
43
|
+
return this._stores;
|
|
44
|
+
}
|
|
45
|
+
get isOpen() {
|
|
46
|
+
return this.db !== null;
|
|
47
|
+
}
|
|
48
|
+
get name() {
|
|
49
|
+
return this.config.name;
|
|
50
|
+
}
|
|
51
|
+
get version() {
|
|
52
|
+
return this.config.version;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Subscribe to store mutations (same-tab). Used by the liveQuery plugin;
|
|
56
|
+
* also useful for custom UI invalidation.
|
|
57
|
+
*/
|
|
58
|
+
subscribeMutations(listener) {
|
|
59
|
+
this.mutationListeners.add(listener);
|
|
60
|
+
return () => {
|
|
61
|
+
this.mutationListeners.delete(listener);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** @internal Notify mutation listeners (and liveQuery / cross-tab bridges). */
|
|
65
|
+
emitMutations(stores, remote = false) {
|
|
66
|
+
const unique = [...new Set(stores.filter(Boolean))];
|
|
67
|
+
if (unique.length === 0 || this.mutationListeners.size === 0) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const batch = { stores: unique, remote };
|
|
71
|
+
for (const listener of this.mutationListeners) {
|
|
72
|
+
listener(batch);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
open() {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
if (this.db) {
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
const schema = (0, define_db_1.toDeclaredDbSchema)(this.config);
|
|
81
|
+
this.db = yield this.openDatabase(schema);
|
|
82
|
+
return this;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Alias for open() for familiarity with v1 `init`. */
|
|
86
|
+
init() {
|
|
87
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
return this.open();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
close() {
|
|
92
|
+
if (this.db) {
|
|
93
|
+
this.db.close();
|
|
94
|
+
this.db = null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
deleteDatabase() {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
this.close();
|
|
100
|
+
yield this.deleteDatabaseRequest(this.config.name);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
transaction(mode, storeNames, fn) {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
const db = this.requireDb();
|
|
106
|
+
if (storeNames.length === 0) {
|
|
107
|
+
throw new errors_1.IndexedDbError('QUERY_INVALID', 'transaction() requires at least one store');
|
|
108
|
+
}
|
|
109
|
+
const idbTx = db.transaction(storeNames, (0, transaction_1.toIndexedDbTransactionMode)(mode));
|
|
110
|
+
const pending = new Set();
|
|
111
|
+
const tx = new transaction_1.Transaction(idbTx, this.config.stores, storeNames, Boolean(this.config.strictInsert), (event) => {
|
|
112
|
+
pending.add(event.store);
|
|
113
|
+
});
|
|
114
|
+
try {
|
|
115
|
+
const result = yield fn(tx.stores);
|
|
116
|
+
yield tx.done();
|
|
117
|
+
if (pending.size > 0) {
|
|
118
|
+
this.emitMutations([...pending]);
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
try {
|
|
124
|
+
idbTx.abort();
|
|
125
|
+
}
|
|
126
|
+
catch (_a) {
|
|
127
|
+
// ignore
|
|
128
|
+
}
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
openDatabase(schema) {
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const request = indexedDB.open(schema.name, schema.version);
|
|
136
|
+
request.onblocked = () => {
|
|
137
|
+
reject(new errors_1.IndexedDbError('BLOCKED', `Opening database "${schema.name}" is blocked by another connection`));
|
|
138
|
+
};
|
|
139
|
+
request.onerror = () => {
|
|
140
|
+
var _a, _b;
|
|
141
|
+
reject(new errors_1.IndexedDbError('OPEN_FAILED', (_b = (_a = request.error) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : `Failed to open database "${schema.name}"`));
|
|
142
|
+
};
|
|
143
|
+
request.onupgradeneeded = (event) => {
|
|
144
|
+
var _a;
|
|
145
|
+
const db = request.result;
|
|
146
|
+
const tx = request.transaction;
|
|
147
|
+
if (!tx) {
|
|
148
|
+
reject(new errors_1.IndexedDbError('OPEN_FAILED', 'Missing versionchange transaction during upgrade'));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
(0, upgrade_1.applySchemaUpgrade)({
|
|
153
|
+
db,
|
|
154
|
+
tx,
|
|
155
|
+
schema,
|
|
156
|
+
oldVersion: event.oldVersion,
|
|
157
|
+
newVersion: (_a = event.newVersion) !== null && _a !== void 0 ? _a : schema.version,
|
|
158
|
+
upgradeHooks: this.config.upgrade,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
reject(error);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
request.onsuccess = () => {
|
|
166
|
+
const db = request.result;
|
|
167
|
+
try {
|
|
168
|
+
(0, upgrade_1.assertKeyPathsMatchSchema)(db, schema);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
db.close();
|
|
172
|
+
reject(error);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
db.onversionchange = () => {
|
|
176
|
+
db.close();
|
|
177
|
+
};
|
|
178
|
+
resolve(db);
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
deleteDatabaseRequest(name) {
|
|
183
|
+
return new Promise((resolve, reject) => {
|
|
184
|
+
const request = indexedDB.deleteDatabase(name);
|
|
185
|
+
request.onsuccess = () => resolve();
|
|
186
|
+
request.onerror = () => {
|
|
187
|
+
var _a, _b;
|
|
188
|
+
return reject(new errors_1.IndexedDbError('OPEN_FAILED', (_b = (_a = request.error) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : `Failed to delete database "${name}"`));
|
|
189
|
+
};
|
|
190
|
+
request.onblocked = () => reject(new errors_1.IndexedDbError('BLOCKED', `Deleting database "${name}" is blocked by another connection`));
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
requireDb() {
|
|
194
|
+
if (!this.db) {
|
|
195
|
+
throw new errors_1.IndexedDbError('NOT_OPEN', 'Database is not open. Call open() first.');
|
|
196
|
+
}
|
|
197
|
+
return this.db;
|
|
198
|
+
}
|
|
199
|
+
requireStore(name, mode) {
|
|
200
|
+
const db = this.requireDb();
|
|
201
|
+
const tx = db.transaction(name, mode);
|
|
202
|
+
return tx.objectStore(name);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.IndexedDbClient = IndexedDbClient;
|
|
206
|
+
/** Construct a client with store properties typed on the instance. */
|
|
207
|
+
function createClient(config) {
|
|
208
|
+
return new IndexedDbClient(config);
|
|
209
|
+
}
|
|
210
|
+
exports.createClient = createClient;
|
|
211
|
+
//# sourceMappingURL=indexed-db-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexed-db-client.js","sourceRoot":"","sources":["../../src/client/indexed-db-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type MutationOp = 'insert' | 'insertMany' | 'update' | 'delete' | 'clear';
|
|
2
|
+
export interface StoreMutationEvent {
|
|
3
|
+
store: string;
|
|
4
|
+
op: MutationOp;
|
|
5
|
+
}
|
|
6
|
+
/** One or more store mutations (coalesced for multi-store transactions). */
|
|
7
|
+
export interface MutationBatch {
|
|
8
|
+
stores: string[];
|
|
9
|
+
/** True when the batch came from another browser tab. */
|
|
10
|
+
remote?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export type MutationListener = (batch: MutationBatch) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutations.js","sourceRoot":"","sources":["../../src/client/mutations.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { StoreInterface } from '../schema/types';
|
|
2
|
+
import type { CountParamsInterface, DeleteParamsInterface, FindManyParamsInterface, FindParamsInterface, InferInsert, InferSelect, UniqueWhereInputInterface, UpdateParamsInterface } from '../schema/infer';
|
|
3
|
+
import type { StoreMutationEvent } from './mutations';
|
|
4
|
+
export interface StoreContextInterface {
|
|
5
|
+
getObjectStore: (mode: IDBTransactionMode) => IDBObjectStore;
|
|
6
|
+
/** See DbConfigInterface.strictInsert */
|
|
7
|
+
strictInsert?: boolean;
|
|
8
|
+
/** Optional mutation hook (used by liveQuery plugin / tests). */
|
|
9
|
+
onMutate?: (event: StoreMutationEvent) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare class Store<TStore extends StoreInterface> {
|
|
12
|
+
readonly def: TStore;
|
|
13
|
+
private readonly ctx;
|
|
14
|
+
constructor(def: TStore, ctx: StoreContextInterface);
|
|
15
|
+
get name(): string;
|
|
16
|
+
private encodeWhere;
|
|
17
|
+
private decodeRow;
|
|
18
|
+
private decodeRows;
|
|
19
|
+
private notify;
|
|
20
|
+
insert(data: InferInsert<TStore>): Promise<IDBValidKey>;
|
|
21
|
+
insertMany(data: InferInsert<TStore>[]): Promise<IDBValidKey[]>;
|
|
22
|
+
find(params: FindParamsInterface<TStore>): Promise<InferSelect<TStore> | null>;
|
|
23
|
+
findUnique(params: {
|
|
24
|
+
where: UniqueWhereInputInterface<TStore>;
|
|
25
|
+
}): Promise<InferSelect<TStore> | null>;
|
|
26
|
+
findMany(params?: FindManyParamsInterface<TStore>): Promise<InferSelect<TStore>[]>;
|
|
27
|
+
count(params?: CountParamsInterface<TStore>): Promise<number>;
|
|
28
|
+
update(params: UpdateParamsInterface<TStore>): Promise<number>;
|
|
29
|
+
/** Alias of `update` — updates all rows matching `where`. */
|
|
30
|
+
updateMany(params: UpdateParamsInterface<TStore>): Promise<number>;
|
|
31
|
+
delete(params: DeleteParamsInterface<TStore>): Promise<number>;
|
|
32
|
+
/** Alias of `delete` — deletes all rows matching `where`. */
|
|
33
|
+
deleteMany(params: DeleteParamsInterface<TStore>): Promise<number>;
|
|
34
|
+
clear(): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Transform each record (typically inside an upgrade transaction).
|
|
37
|
+
* Return `null` to delete the record.
|
|
38
|
+
* Callback receives / returns app-level types (boolean, not 0|1).
|
|
39
|
+
*/
|
|
40
|
+
migrate(map: (row: InferSelect<TStore>) => InferSelect<TStore> | null | Promise<InferSelect<TStore> | null>): Promise<void>;
|
|
41
|
+
private collectWithCursor;
|
|
42
|
+
}
|