@prisma-idb/client-idb 0.6.1 → 0.7.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/README.md +25 -12
- package/dist/client-auto.d.mts +20 -41
- package/dist/client-auto.d.mts.map +1 -1
- package/dist/client-auto.mjs +20 -41
- package/dist/client-auto.mjs.map +1 -1
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/{idb-orm-Cupnnwum.mjs → idb-orm-JBg6si7u.mjs} +469 -200
- package/dist/idb-orm-JBg6si7u.mjs.map +1 -0
- package/dist/{idb-orm-zCRkkD_D.d.mts → idb-orm-MOH1S3ES.d.mts} +93 -23
- package/dist/idb-orm-MOH1S3ES.d.mts.map +1 -0
- package/dist/{managed-client-B_8JZM3h.mjs → managed-client-BLdCyxUi.mjs} +3 -3
- package/dist/{managed-client-B_8JZM3h.mjs.map → managed-client-BLdCyxUi.mjs.map} +1 -1
- package/dist/{managed-client-kdyHm72t.d.mts → managed-client-CJD9lBx5.d.mts} +2 -2
- package/dist/{managed-client-kdyHm72t.d.mts.map → managed-client-CJD9lBx5.d.mts.map} +1 -1
- package/dist/orm.d.mts +2 -2
- package/dist/orm.d.mts.map +1 -1
- package/dist/orm.mjs +2 -2
- package/package.json +6 -6
- package/dist/idb-orm-Cupnnwum.mjs.map +0 -1
- package/dist/idb-orm-zCRkkD_D.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
# `@prisma-idb/client-idb`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A typed IndexedDB client for Prisma 8. Write a Prisma schema, plan migrations with the `prisma-idb` CLI, and query IndexedDB from the browser with chained, typed calls. The client applies pending migrations when it opens the database, and enforces foreign keys and `onDelete`/`onUpdate` actions like a SQL database.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
```bash
|
|
6
|
+
npm install @prisma-idb/client-idb @prisma/orm-toolchain
|
|
7
|
+
```
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
```ts
|
|
10
|
+
import { createAutoMigratingIdbClient } from "@prisma-idb/client-idb/client-auto";
|
|
11
|
+
import { contractSpace } from "./prisma/contract-space.generated";
|
|
8
12
|
|
|
13
|
+
const db = await createAutoMigratingIdbClient({ contractSpace, dbName: "my-app" });
|
|
14
|
+
|
|
15
|
+
await db.orm.todo.create({ id: crypto.randomUUID(), title: "Write docs", done: false, userId });
|
|
16
|
+
const open = await db.orm.todo.where({ done: false }).orderBy({ title: "asc" }).all();
|
|
9
17
|
```
|
|
10
|
-
family-idb (CLI / config)
|
|
11
|
-
client-idb ← you are here (ORM query builder)
|
|
12
|
-
runtime-idb (RuntimeCore)
|
|
13
|
-
adapter-idb (query AST → IDB plan)
|
|
14
|
-
driver-idb (window.indexedDB wrapper)
|
|
15
|
-
target-idb (identity + migrations)
|
|
16
|
-
```
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
`contract-space.generated.ts` comes from the build-time tools. The [Quick Start](https://prisma-idb.dev/docs/prisma-8/getting-started) sets them up.
|
|
20
|
+
|
|
21
|
+
## Entry points
|
|
22
|
+
|
|
23
|
+
| Import | Contains |
|
|
24
|
+
| ------------------------------------ | ----------------------------------------------------------------------------------------------- |
|
|
25
|
+
| `@prisma-idb/client-idb/client-auto` | `createAutoMigratingIdbClient`, `createManagedAutoIdbClient`: open the database and migrate it. |
|
|
26
|
+
| `@prisma-idb/client-idb/client` | `createIdbClient`, `createManagedIdbClient`: open an already-migrated database. |
|
|
27
|
+
| `@prisma-idb/client-idb/orm` | `idbOrm`, the accessor types, and the `and`, `or` and `not` filter helpers. |
|
|
28
|
+
|
|
29
|
+
## Documentation
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
- [Quick Start](https://prisma-idb.dev/docs/prisma-8/getting-started)
|
|
32
|
+
- [Client](https://prisma-idb.dev/docs/prisma-8/client)
|
|
33
|
+
- [API reference](https://prisma-idb.dev/docs/prisma-8/api)
|
|
21
34
|
|
|
22
35
|
## License
|
|
23
36
|
|
package/dist/client-auto.d.mts
CHANGED
|
@@ -1,31 +1,9 @@
|
|
|
1
|
-
import { b as IdbContract } from "./idb-orm-
|
|
2
|
-
import { a as IdbClientOptions, i as IdbClient, n as ManagedIdbClientOptions, o as createIdbClient, r as createManagedIdbClient, t as ManagedIdbClient } from "./managed-client-
|
|
1
|
+
import { b as IdbContract } from "./idb-orm-MOH1S3ES.mjs";
|
|
2
|
+
import { a as IdbClientOptions, i as IdbClient, n as ManagedIdbClientOptions, o as createIdbClient, r as createManagedIdbClient, t as ManagedIdbClient } from "./managed-client-CJD9lBx5.mjs";
|
|
3
3
|
import { Contract } from "@prisma/orm-framework/contract/types";
|
|
4
|
-
import { ContractSpace
|
|
4
|
+
import { ContractSpace } from "@prisma/orm-framework/components/control";
|
|
5
5
|
import { IdbExtensionSpace } from "@prisma-idb/family-idb/control";
|
|
6
6
|
//#region src/core/auto-migrate.d.ts
|
|
7
|
-
/**
|
|
8
|
-
* Migration policy for the browser-side apply path.
|
|
9
|
-
*
|
|
10
|
-
* Two knobs:
|
|
11
|
-
*
|
|
12
|
-
* - `allowedOperationClasses`: filter applied to each op's `operationClass`.
|
|
13
|
-
* Defaults to `['additive', 'widening']`. Anything outside this set is
|
|
14
|
-
* dropped before the upgrade transaction opens.
|
|
15
|
-
* - `onDestructive`: what to do if the planner emitted a destructive op
|
|
16
|
-
* that the filter just dropped. `'refuse'` (default) throws so the user
|
|
17
|
-
* sees the situation; `'allow'` re-includes destructive ops.
|
|
18
|
-
*
|
|
19
|
-
* Default is **safe**: a contract change that drops a store will refuse to
|
|
20
|
-
* apply unless the developer opts in. A user's local IDB can hold months
|
|
21
|
-
* of accumulated state (drafts, offline queue, cached content) and the
|
|
22
|
-
* spec explicitly calls out the silent-data-loss risk if destructive ops
|
|
23
|
-
* apply on every page load. See `FEEDBACKS.md` §4.
|
|
24
|
-
*/
|
|
25
|
-
interface MigrationPolicy {
|
|
26
|
-
readonly allowedOperationClasses?: readonly MigrationOperationClass[];
|
|
27
|
-
readonly onDestructive?: "refuse" | "allow";
|
|
28
|
-
}
|
|
29
7
|
/**
|
|
30
8
|
* Options for {@link createAutoMigratingIdbClient}.
|
|
31
9
|
*
|
|
@@ -42,17 +20,15 @@ interface MigrationPolicy {
|
|
|
42
20
|
interface AutoMigrateClientOptions<TContract extends IdbContract> {
|
|
43
21
|
readonly contractSpace: ContractSpace<TContract>;
|
|
44
22
|
readonly dbName: string;
|
|
45
|
-
/** Migration policy. Defaults to safe (additive + widening only, refuse destructive). */
|
|
46
|
-
readonly policy?: MigrationPolicy;
|
|
47
23
|
/** IDB factory override — primarily for tests. Defaults to `indexedDB`. */
|
|
48
24
|
readonly factory?: IDBFactory;
|
|
49
25
|
/**
|
|
50
26
|
* Additional contract spaces from IDB extensions.
|
|
51
27
|
*
|
|
52
28
|
* Every space with pending work — the application space plus each
|
|
53
|
-
* extension — is applied together in one
|
|
54
|
-
*
|
|
55
|
-
*
|
|
29
|
+
* extension — is applied together in one `upgradeneeded` transaction,
|
|
30
|
+
* which also writes every space's marker. Each space still gets its own
|
|
31
|
+
* marker row in `_prisma_next_marker`.
|
|
56
32
|
*/
|
|
57
33
|
readonly extensions?: ReadonlyArray<IdbExtensionSpace>;
|
|
58
34
|
}
|
|
@@ -69,14 +45,18 @@ interface AutoMigrateClientOptions<TContract extends IdbContract> {
|
|
|
69
45
|
* 3. Otherwise, walk `contractSpace.migrations` from the marker hash (or
|
|
70
46
|
* `null` for fresh) to `headRef.hash`, collecting each pending
|
|
71
47
|
* package's `ops` in chain order.
|
|
72
|
-
* 4.
|
|
73
|
-
* out and `onDestructive === 'refuse'`.
|
|
74
|
-
* 5. If `extensions` are configured, repeat steps 1–4 for each extension
|
|
48
|
+
* 4. If `extensions` are configured, repeat steps 1–3 for each extension
|
|
75
49
|
* space, then combine every space's pending ops into ONE reopen at
|
|
76
50
|
* `db.version + 1` so `upgradeneeded` fires once; apply every collected
|
|
77
|
-
* op (all spaces) inside that single version-change transaction
|
|
78
|
-
*
|
|
79
|
-
*
|
|
51
|
+
* op (all spaces) inside that single version-change transaction, which
|
|
52
|
+
* also writes every migrated space's marker.
|
|
53
|
+
* 5. Hand back the typed `IdbClient`.
|
|
54
|
+
*
|
|
55
|
+
* Every pending op is applied exactly as planned, destructive ones included.
|
|
56
|
+
* The developer reviewed them when running `prisma-idb migration plan`,
|
|
57
|
+
* which warns about any that delete data. Skipping some ops would leave the
|
|
58
|
+
* database claiming a schema it doesn't have, and refusing them would stop
|
|
59
|
+
* the app from opening for every user.
|
|
80
60
|
*
|
|
81
61
|
* **What does NOT run in the browser**:
|
|
82
62
|
*
|
|
@@ -99,16 +79,15 @@ declare function createAutoMigratingIdbClient<TContract extends IdbContract>(opt
|
|
|
99
79
|
* The migration loop. Exported for tests.
|
|
100
80
|
*
|
|
101
81
|
* Collects pending ops from the app space and every extension space, then
|
|
102
|
-
* applies all of them in a single
|
|
103
|
-
*
|
|
104
|
-
*
|
|
82
|
+
* applies all of them in a single `upgradeneeded` transaction (one IDB
|
|
83
|
+
* version bump total). The same transaction writes the marker of every
|
|
84
|
+
* space that migrated, so schema changes and markers commit together.
|
|
105
85
|
*
|
|
106
86
|
* @internal Prefer {@link createAutoMigratingIdbClient}.
|
|
107
87
|
*/
|
|
108
88
|
declare function autoMigrate(input: {
|
|
109
89
|
readonly contractSpace: ContractSpace<Contract>;
|
|
110
90
|
readonly dbName: string;
|
|
111
|
-
readonly policy: Required<MigrationPolicy>;
|
|
112
91
|
readonly factory: IDBFactory;
|
|
113
92
|
readonly extensions?: ReadonlyArray<IdbExtensionSpace>;
|
|
114
93
|
}): Promise<void>;
|
|
@@ -128,5 +107,5 @@ declare function autoMigrate(input: {
|
|
|
128
107
|
*/
|
|
129
108
|
declare function createManagedAutoIdbClient<TContract extends IdbContract>(options: AutoMigrateClientOptions<TContract>): ManagedIdbClient<IdbClient<TContract>>;
|
|
130
109
|
//#endregion
|
|
131
|
-
export { type AutoMigrateClientOptions, type IdbClient, type IdbClientOptions, type ManagedIdbClient, type ManagedIdbClientOptions,
|
|
110
|
+
export { type AutoMigrateClientOptions, type IdbClient, type IdbClientOptions, type ManagedIdbClient, type ManagedIdbClientOptions, autoMigrate, createAutoMigratingIdbClient, createIdbClient, createManagedAutoIdbClient, createManagedIdbClient };
|
|
132
111
|
//# sourceMappingURL=client-auto.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-auto.d.mts","names":[],"sources":["../src/core/auto-migrate.ts","../src/core/managed-auto-migrate.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-auto.d.mts","names":[],"sources":["../src/core/auto-migrate.ts","../src/core/managed-auto-migrate.ts"],"mappings":";;;;;;;;;;;;;;;;;;;UA4BiB,yBAAyB,kBAAkB;WACjD,eAAe,cAAc;WAC7B;;WAEA,UAAU;;;;;;;;;WASV,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6ChB,6BAA6B,kBAAkB,aACnE,SAAS,yBAAyB,aACjC,QAAQ,UAAU;;;;;;;;;;;iBAgCC,YAAY;WAKvB,eAAe,cAAc;WAC7B;WACA,SAAS;WACT,aAAa,cAAc;IAClC;;;;;;;;;;;;;;;iBClGY,2BAA2B,kBAAkB,aAC3D,SAAS,yBAAyB,aACjC,iBAAiB,UAAU"}
|
package/dist/client-auto.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createIdbClient, t as createManagedIdbClient } from "./managed-client-
|
|
1
|
+
import { n as createIdbClient, t as createManagedIdbClient } from "./managed-client-BLdCyxUi.mjs";
|
|
2
2
|
import { isIdbDdlOp, openAndUpgrade, readMarker } from "@prisma-idb/target-idb/runtime";
|
|
3
3
|
import { APP_SPACE_ID } from "@prisma/orm-framework/components/control";
|
|
4
4
|
import { canonicalizeJson } from "@prisma/orm-framework/components/utils";
|
|
@@ -38,10 +38,6 @@ async function computeMigrationHash(metadata, ops) {
|
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/core/auto-migrate.ts
|
|
41
|
-
const SAFE_POLICY = {
|
|
42
|
-
allowedOperationClasses: ["additive", "widening"],
|
|
43
|
-
onDestructive: "refuse"
|
|
44
|
-
};
|
|
45
41
|
/**
|
|
46
42
|
* Create a typed IDB client, applying any pending migrations from the bundled
|
|
47
43
|
* `contractSpace` first.
|
|
@@ -55,14 +51,18 @@ const SAFE_POLICY = {
|
|
|
55
51
|
* 3. Otherwise, walk `contractSpace.migrations` from the marker hash (or
|
|
56
52
|
* `null` for fresh) to `headRef.hash`, collecting each pending
|
|
57
53
|
* package's `ops` in chain order.
|
|
58
|
-
* 4.
|
|
59
|
-
* out and `onDestructive === 'refuse'`.
|
|
60
|
-
* 5. If `extensions` are configured, repeat steps 1–4 for each extension
|
|
54
|
+
* 4. If `extensions` are configured, repeat steps 1–3 for each extension
|
|
61
55
|
* space, then combine every space's pending ops into ONE reopen at
|
|
62
56
|
* `db.version + 1` so `upgradeneeded` fires once; apply every collected
|
|
63
|
-
* op (all spaces) inside that single version-change transaction
|
|
64
|
-
*
|
|
65
|
-
*
|
|
57
|
+
* op (all spaces) inside that single version-change transaction, which
|
|
58
|
+
* also writes every migrated space's marker.
|
|
59
|
+
* 5. Hand back the typed `IdbClient`.
|
|
60
|
+
*
|
|
61
|
+
* Every pending op is applied exactly as planned, destructive ones included.
|
|
62
|
+
* The developer reviewed them when running `prisma-idb migration plan`,
|
|
63
|
+
* which warns about any that delete data. Skipping some ops would leave the
|
|
64
|
+
* database claiming a schema it doesn't have, and refusing them would stop
|
|
65
|
+
* the app from opening for every user.
|
|
66
66
|
*
|
|
67
67
|
* **What does NOT run in the browser**:
|
|
68
68
|
*
|
|
@@ -82,11 +82,9 @@ const SAFE_POLICY = {
|
|
|
82
82
|
*/
|
|
83
83
|
async function createAutoMigratingIdbClient(options) {
|
|
84
84
|
const factory = options.factory ?? indexedDB;
|
|
85
|
-
const policy = mergePolicy(options.policy);
|
|
86
85
|
await autoMigrate({
|
|
87
86
|
contractSpace: options.contractSpace,
|
|
88
87
|
dbName: options.dbName,
|
|
89
|
-
policy,
|
|
90
88
|
factory,
|
|
91
89
|
...options.extensions !== void 0 ? { extensions: options.extensions } : {}
|
|
92
90
|
});
|
|
@@ -96,24 +94,18 @@ async function createAutoMigratingIdbClient(options) {
|
|
|
96
94
|
factory
|
|
97
95
|
});
|
|
98
96
|
}
|
|
99
|
-
function mergePolicy(p) {
|
|
100
|
-
return {
|
|
101
|
-
allowedOperationClasses: p?.allowedOperationClasses ?? SAFE_POLICY.allowedOperationClasses,
|
|
102
|
-
onDestructive: p?.onDestructive ?? SAFE_POLICY.onDestructive
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
97
|
/**
|
|
106
98
|
* The migration loop. Exported for tests.
|
|
107
99
|
*
|
|
108
100
|
* Collects pending ops from the app space and every extension space, then
|
|
109
|
-
* applies all of them in a single
|
|
110
|
-
*
|
|
111
|
-
*
|
|
101
|
+
* applies all of them in a single `upgradeneeded` transaction (one IDB
|
|
102
|
+
* version bump total). The same transaction writes the marker of every
|
|
103
|
+
* space that migrated, so schema changes and markers commit together.
|
|
112
104
|
*
|
|
113
105
|
* @internal Prefer {@link createAutoMigratingIdbClient}.
|
|
114
106
|
*/
|
|
115
107
|
async function autoMigrate(input) {
|
|
116
|
-
const { dbName,
|
|
108
|
+
const { dbName, factory } = input;
|
|
117
109
|
const spaces = [{
|
|
118
110
|
spaceId: APP_SPACE_ID,
|
|
119
111
|
contractSpace: input.contractSpace
|
|
@@ -130,25 +122,21 @@ async function autoMigrate(input) {
|
|
|
130
122
|
}
|
|
131
123
|
const { currentVersion: initialVersion } = await openAndReadMarker(dbName, factory, APP_SPACE_ID);
|
|
132
124
|
const pendingPerSpace = [];
|
|
133
|
-
let totalDestructiveDropped = 0;
|
|
134
125
|
for (const space of spaces) {
|
|
135
126
|
const targetHash = space.contractSpace.headRef.hash;
|
|
136
127
|
const { markerHash } = await openAndReadMarker(dbName, factory, space.spaceId);
|
|
137
128
|
if (markerHash === targetHash) continue;
|
|
138
|
-
const
|
|
129
|
+
const pendingOps = await walkChain({
|
|
139
130
|
markerHash,
|
|
140
131
|
headHash: targetHash,
|
|
141
|
-
migrations: space.contractSpace.migrations
|
|
142
|
-
policy
|
|
132
|
+
migrations: space.contractSpace.migrations
|
|
143
133
|
});
|
|
144
|
-
totalDestructiveDropped += destructiveDropped;
|
|
145
134
|
pendingPerSpace.push({
|
|
146
135
|
spaceId: space.spaceId,
|
|
147
136
|
ops: pendingOps,
|
|
148
137
|
storageHash: targetHash
|
|
149
138
|
});
|
|
150
139
|
}
|
|
151
|
-
if (totalDestructiveDropped > 0 && policy.onDestructive === "refuse") throw new Error(`Auto-migration refused: ${totalDestructiveDropped} destructive operation(s) in the pending chain would drop user data. To allow them, pass \`policy: { onDestructive: 'allow' }\` to createAutoMigratingIdbClient. Per-tab persistent state (drafts, offline queue, cached content) will be lost when destructive ops apply silently — review the change before opting in.`);
|
|
152
140
|
if (pendingPerSpace.length === 0) return;
|
|
153
141
|
const orderedPending = [...pendingPerSpace].sort((a, b) => {
|
|
154
142
|
if (a.spaceId === APP_SPACE_ID) return 1;
|
|
@@ -168,9 +156,7 @@ async function autoMigrate(input) {
|
|
|
168
156
|
}
|
|
169
157
|
/**
|
|
170
158
|
* Walk the migration chain from `markerHash` (or `null` for a fresh DB) to
|
|
171
|
-
* `headHash`, collecting
|
|
172
|
-
* policy filter on each op as it's added; returns the count of destructive
|
|
173
|
-
* ops that were dropped so the caller can refuse if the policy demands.
|
|
159
|
+
* `headHash`, collecting every pending package's ops in order.
|
|
174
160
|
*
|
|
175
161
|
* Throws on chain discontinuity (no package whose `from === cursor`) so
|
|
176
162
|
* misconfigured `contractSpace` inputs fail loudly rather than silently
|
|
@@ -179,9 +165,7 @@ async function autoMigrate(input) {
|
|
|
179
165
|
async function walkChain(input) {
|
|
180
166
|
const byFrom = /* @__PURE__ */ new Map();
|
|
181
167
|
for (const pkg of input.migrations) byFrom.set(pkg.metadata.from, pkg);
|
|
182
|
-
const allowed = new Set(input.policy.allowedOperationClasses);
|
|
183
168
|
const pendingOps = [];
|
|
184
|
-
let destructiveDropped = 0;
|
|
185
169
|
let cursor = input.markerHash;
|
|
186
170
|
const visited = /* @__PURE__ */ new Set();
|
|
187
171
|
while (cursor !== input.headHash) {
|
|
@@ -193,16 +177,11 @@ async function walkChain(input) {
|
|
|
193
177
|
if (computedHash !== next.metadata.migrationHash) throw new Error(`Migration package "${next.dirName}" failed integrity check: stored migrationHash ${next.metadata.migrationHash} does not match computed hash ${computedHash}. The ops may have been edited after the package was generated. Re-run \`prisma-idb migration plan\` to regenerate the package.`);
|
|
194
178
|
for (const op of next.ops) {
|
|
195
179
|
if (!isIdbDdlOp(op)) throw new Error(`Non-IDB operation found in migration package ${next.dirName}: ${JSON.stringify(op)}`);
|
|
196
|
-
|
|
197
|
-
else if (op.operationClass === "destructive") if (input.policy.onDestructive === "allow") pendingOps.push(op);
|
|
198
|
-
else destructiveDropped += 1;
|
|
180
|
+
pendingOps.push(op);
|
|
199
181
|
}
|
|
200
182
|
cursor = next.metadata.to;
|
|
201
183
|
}
|
|
202
|
-
return
|
|
203
|
-
pendingOps,
|
|
204
|
-
destructiveDropped
|
|
205
|
-
};
|
|
184
|
+
return pendingOps;
|
|
206
185
|
}
|
|
207
186
|
/**
|
|
208
187
|
* Open the database at its current local version (no version arg), read the
|
package/dist/client-auto.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-auto.mjs","names":[],"sources":["../src/core/migration-hash.ts","../src/core/auto-migrate.ts","../src/core/managed-auto-migrate.ts"],"sourcesContent":["import type { MigrationPackage } from \"@prisma/orm-framework/components/control\";\nimport { canonicalizeJson } from \"@prisma/orm-framework/components/utils\";\n\n/** Hex-encode the bytes of a digest buffer. */\nfunction toHex(buffer: ArrayBuffer): string {\n return Array.from(new Uint8Array(buffer), (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** SHA-256 → lowercase hex, via WebCrypto (`crypto.subtle`) — works in the browser. */\nasync function sha256Hex(input: string): Promise<string> {\n const digest = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(input));\n return toHex(digest);\n}\n\n/**\n * Browser-safe re-implementation of `computeMigrationHash` from\n * `@prisma/orm-toolchain/migration-tools/hash`.\n *\n * The framework version hashes with Node's `node:crypto` `createHash`, which\n * does not exist in the browser — so importing it into the runtime auto-migrate\n * integrity check (PLAN Issue #23 / ADR 199) throws `createHash is not a\n * function` on every client init and breaks the whole app. This version is\n * **byte-identical** to the framework's: it reuses the same `canonicalizeJson`\n * and the same nested SHA-256/hex scheme — strip `migrationHash` from the\n * metadata, hash the canonicalized metadata and ops separately, then hash\n * the canonicalized pair of those two hashes, as bare lowercase hex (no\n * `sha256:` prefix — dropped repo-wide at rc.4). Reusing the\n * identical canonicalization + algorithm guarantees the result matches the\n * `migrationHash` the CLI recorded, so the integrity check stays meaningful.\n *\n * `crypto.subtle.digest` is async, hence the `Promise` return (the framework's\n * Node version is synchronous). Callers in the async migration path await it.\n */\nexport async function computeMigrationHash(\n metadata: MigrationPackage[\"metadata\"],\n ops: MigrationPackage[\"ops\"]\n): Promise<string> {\n // v0.12.0 strips only `migrationHash` before hashing (`hints`/`labels` were\n // removed from the on-disk manifest schema entirely).\n const stripped: Record<string, unknown> = { ...metadata };\n delete stripped[\"migrationHash\"];\n const inner = await Promise.all([sha256Hex(canonicalizeJson(stripped)), sha256Hex(canonicalizeJson(ops))]);\n return sha256Hex(canonicalizeJson(inner));\n}\n","import type { Contract } from \"@prisma/orm-framework/contract/types\";\nimport type {\n ContractSpace,\n MigrationOperationClass,\n MigrationPackage,\n} from \"@prisma/orm-framework/components/control\";\nimport { APP_SPACE_ID } from \"@prisma/orm-framework/components/control\";\nimport type { IdbExtensionSpace } from \"@prisma-idb/family-idb/control\";\n// Browser-safe (WebCrypto) hash — the framework's `@prisma/orm-toolchain/migration-tools/hash`\n// uses `node:crypto` and throws in the browser (PLAN Issue #23 regression).\nimport { computeMigrationHash } from \"./migration-hash\";\n// Import from `./runtime` (not `./migration`) so `MigrationCLI` → `node:fs`\n// is not bundled into the browser client.\nimport { isIdbDdlOp, openAndUpgrade, readMarker, type IdbDdlOp } from \"@prisma-idb/target-idb/runtime\";\nimport { createIdbClient, type IdbClient } from \"./idb-client\";\nimport type { IdbContract } from \"./types\";\n\n// ── Public policy types ──────────────────────────────────────────────────────\n\n/**\n * Migration policy for the browser-side apply path.\n *\n * Two knobs:\n *\n * - `allowedOperationClasses`: filter applied to each op's `operationClass`.\n * Defaults to `['additive', 'widening']`. Anything outside this set is\n * dropped before the upgrade transaction opens.\n * - `onDestructive`: what to do if the planner emitted a destructive op\n * that the filter just dropped. `'refuse'` (default) throws so the user\n * sees the situation; `'allow'` re-includes destructive ops.\n *\n * Default is **safe**: a contract change that drops a store will refuse to\n * apply unless the developer opts in. A user's local IDB can hold months\n * of accumulated state (drafts, offline queue, cached content) and the\n * spec explicitly calls out the silent-data-loss risk if destructive ops\n * apply on every page load. See `FEEDBACKS.md` §4.\n */\nexport interface MigrationPolicy {\n readonly allowedOperationClasses?: readonly MigrationOperationClass[];\n readonly onDestructive?: \"refuse\" | \"allow\";\n}\n\nconst SAFE_POLICY: Required<MigrationPolicy> = {\n allowedOperationClasses: [\"additive\", \"widening\"],\n onDestructive: \"refuse\",\n};\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Options for {@link createAutoMigratingIdbClient}.\n *\n * `contractSpace` is the bundled artefact produced at design time by\n * `prisma-idb migration contract-space`. It carries the canonical\n * contract JSON, the ordered list of migration packages, and the head\n * ref the runtime walks toward.\n *\n * `extensions` is an optional list of additional contract spaces contributed\n * by IDB extensions (e.g. the sync extension). Each extension space migrates\n * independently of the application space and writes its own marker row keyed\n * by the extension's `spaceId`.\n */\nexport interface AutoMigrateClientOptions<TContract extends IdbContract> {\n readonly contractSpace: ContractSpace<TContract>;\n readonly dbName: string;\n /** Migration policy. Defaults to safe (additive + widening only, refuse destructive). */\n readonly policy?: MigrationPolicy;\n /** IDB factory override — primarily for tests. Defaults to `indexedDB`. */\n readonly factory?: IDBFactory;\n /**\n * Additional contract spaces from IDB extensions.\n *\n * Every space with pending work — the application space plus each\n * extension — is applied together in one combined `upgradeneeded`\n * transaction and one batched marker-write transaction (ADR 010). Each\n * space still gets its own marker row in `_prisma_next_marker`.\n */\n readonly extensions?: ReadonlyArray<IdbExtensionSpace>;\n}\n\n/**\n * Create a typed IDB client, applying any pending migrations from the bundled\n * `contractSpace` first.\n *\n * **What runs**:\n *\n * 1. Open the database at the current local version, read the marker from\n * `_prisma_next_marker`. (Null for a fresh database)\n * 2. If the marker hash equals `contractSpace.headRef.hash`, the database\n * is already at the target — return the client immediately.\n * 3. Otherwise, walk `contractSpace.migrations` from the marker hash (or\n * `null` for fresh) to `headRef.hash`, collecting each pending\n * package's `ops` in chain order.\n * 4. Apply the policy filter. Refuse if any destructive op was filtered\n * out and `onDestructive === 'refuse'`.\n * 5. If `extensions` are configured, repeat steps 1–4 for each extension\n * space, then combine every space's pending ops into ONE reopen at\n * `db.version + 1` so `upgradeneeded` fires once; apply every collected\n * op (all spaces) inside that single version-change transaction.\n * 6. Write every migrated space's marker in one batched readwrite tx.\n * 7. Hand back the typed `IdbClient`.\n *\n * **What does NOT run in the browser**:\n *\n * The planner does not ship to the browser. The differ does not run. Live-DB\n * schema introspection does not happen. All the planning was done once at\n * design time and is encoded in the bundled `ops.json` blobs inside\n * `contractSpace.migrations`.\n *\n * @example\n * ```ts\n * import { createAutoMigratingIdbClient } from '@prisma-idb/client-idb/client-auto';\n * import { contractSpace } from './prisma/contract-space.generated';\n *\n * const db = await createAutoMigratingIdbClient({ contractSpace, dbName: 'my-app' });\n * const users = await db.orm.users.all().toArray();\n * ```\n */\nexport async function createAutoMigratingIdbClient<TContract extends IdbContract>(\n options: AutoMigrateClientOptions<TContract>\n): Promise<IdbClient<TContract>> {\n const factory = options.factory ?? indexedDB;\n const policy = mergePolicy(options.policy);\n\n await autoMigrate({\n // The public `AutoMigrateClientOptions<TContract>` is generic over the\n // user's narrow IDB contract; the internal `autoMigrate` only consumes\n // chain-walking fields, so widen to `ContractSpace<Contract>` here.\n contractSpace: options.contractSpace as unknown as ContractSpace<Contract>,\n dbName: options.dbName,\n policy,\n factory,\n ...(options.extensions !== undefined ? { extensions: options.extensions } : {}),\n });\n\n return createIdbClient({\n contract: options.contractSpace.contractJson,\n dbName: options.dbName,\n factory,\n });\n}\n\nfunction mergePolicy(p?: MigrationPolicy): Required<MigrationPolicy> {\n return {\n allowedOperationClasses: p?.allowedOperationClasses ?? SAFE_POLICY.allowedOperationClasses,\n onDestructive: p?.onDestructive ?? SAFE_POLICY.onDestructive,\n };\n}\n\n// ── Core migration loop ──────────────────────────────────────────────────────\n\n/**\n * The migration loop. Exported for tests.\n *\n * Collects pending ops from the app space and every extension space, then\n * applies all of them in a single combined `upgradeneeded` transaction\n * (one IDB version bump total) followed by one batched marker-write\n * transaction covering every space that migrated. See ADR 010 for details.\n *\n * @internal Prefer {@link createAutoMigratingIdbClient}.\n */\nexport async function autoMigrate(input: {\n // `ContractSpace<Contract>` instead of `<unknown>` so the generic\n // constraint `TContract extends Contract` from the framework is satisfied.\n // The internal apply path only reads `headRef.hash` and `migrations`, so\n // the precise contract shape inside `contractJson` doesn't matter here.\n readonly contractSpace: ContractSpace<Contract>;\n readonly dbName: string;\n readonly policy: Required<MigrationPolicy>;\n readonly factory: IDBFactory;\n readonly extensions?: ReadonlyArray<IdbExtensionSpace>;\n}): Promise<void> {\n const { dbName, policy, factory } = input;\n\n // Order here only affects the destructive-op collection loop below, not the\n // final apply order (see the combined-apply step, which re-sorts to match\n // upstream ADR 212's extension-first convention).\n const spaces: Array<{ spaceId: string; contractSpace: ContractSpace<Contract> }> = [\n { spaceId: APP_SPACE_ID, contractSpace: input.contractSpace },\n ...(input.extensions ?? []),\n ];\n\n // Reject reserved/duplicate extension space IDs before touching the\n // database. Without this, two extensions sharing a spaceId would combine\n // their pending DDL and the upgrade would try to create the same stores\n // twice; an extension using APP_SPACE_ID would have its marker write\n // silently overwrite (or be overwritten by) the app space's marker.\n const seenSpaceIds = new Set<string>();\n for (const extension of input.extensions ?? []) {\n if (extension.spaceId === APP_SPACE_ID || seenSpaceIds.has(extension.spaceId)) {\n throw new Error(`Invalid duplicate or reserved extension space ID: \"${extension.spaceId}\"`);\n }\n seenSpaceIds.add(extension.spaceId);\n }\n\n // Descriptor self-consistency (upstream ADR 212): a space's pinned headRef\n // must match the hash actually embedded in its contractJson. Catches an\n // extension author who edited the contract source without regenerating\n // migrations/refs/head.json — fails loudly here instead of surfacing as a\n // confusing chain-walk error deep inside walkChain.\n for (const space of spaces) {\n const declaredHash = space.contractSpace.contractJson.storage.storageHash;\n const headHash = space.contractSpace.headRef.hash;\n if (declaredHash !== headHash) {\n throw new Error(\n `Contract space \"${space.spaceId}\" is internally inconsistent: ` +\n `contractJson.storage.storageHash (${declaredHash}) does not match ` +\n `headRef.hash (${headHash}). The contract source likely changed without ` +\n \"regenerating migrations/refs/head.json for this space — rebuild its migration chain.\"\n );\n }\n }\n\n // Read current DB version once (all spaces share the same IDB database).\n const { currentVersion: initialVersion } = await openAndReadMarker(dbName, factory, APP_SPACE_ID);\n\n // Collect pending work per space without applying yet, so we can surface\n // all destructive violations before touching the database.\n const pendingPerSpace: Array<{ spaceId: string; ops: IdbDdlOp[]; storageHash: string }> = [];\n let totalDestructiveDropped = 0;\n\n for (const space of spaces) {\n const targetHash = space.contractSpace.headRef.hash;\n const { markerHash } = await openAndReadMarker(dbName, factory, space.spaceId);\n if (markerHash === targetHash) continue;\n\n const { pendingOps, destructiveDropped } = await walkChain({\n markerHash,\n headHash: targetHash,\n migrations: space.contractSpace.migrations,\n policy,\n });\n totalDestructiveDropped += destructiveDropped;\n // Push whenever the marker is behind `targetHash` — even if every package\n // walked had zero ops (a hash-only \"bridge\" migration, e.g. re-emitting\n // the contract under a new hashing algorithm with no structural change).\n // Gating on `pendingOps.length > 0` here would skip the marker write\n // below for that space, and since nothing ever changes on a later\n // retry either, the marker gets stuck at the old hash forever — the\n // space never converges to `targetHash`, even though there was never\n // any actual work to do.\n pendingPerSpace.push({ spaceId: space.spaceId, ops: pendingOps, storageHash: targetHash });\n }\n\n // Refuse if any space had destructive ops dropped under refuse policy.\n if (totalDestructiveDropped > 0 && policy.onDestructive === \"refuse\") {\n throw new Error(\n `Auto-migration refused: ${totalDestructiveDropped} destructive operation(s) ` +\n \"in the pending chain would drop user data. To allow them, pass \" +\n \"`policy: { onDestructive: 'allow' }` to createAutoMigratingIdbClient. \" +\n \"Per-tab persistent state (drafts, offline queue, cached content) will \" +\n \"be lost when destructive ops apply silently — review the change before opting in.\"\n );\n }\n\n if (pendingPerSpace.length === 0) return;\n\n // Combine every pending space into ONE upgradeneeded transaction (one IDB\n // version bump total) and ONE batched marker-write transaction (ADR 010).\n // This gives true cross-space atomicity — a failure partway through no\n // longer leaves some spaces migrated and others not — and cuts the number\n // of versionchange/blocked cycles a multi-tab user hits on cold start from\n // N (one per space) to 1.\n //\n // DDL op order within the combined transaction is extensions\n // (alphabetical-by-spaceId) first, app-space last, matching upstream\n // ADR 212's convention. That ordering is safe here specifically because\n // marker writes happen in the separate phase-2 transaction below, which\n // only runs after every space's DDL — including the app space's\n // `_prisma_next_marker` creation — has already committed in phase 1.\n const orderedPending = [...pendingPerSpace].sort((a, b) => {\n if (a.spaceId === APP_SPACE_ID) return 1;\n if (b.spaceId === APP_SPACE_ID) return -1;\n return a.spaceId.localeCompare(b.spaceId);\n });\n\n await openAndUpgrade({\n factory,\n dbName,\n targetVersion: initialVersion + 1,\n ops: orderedPending.flatMap((space) => space.ops),\n markers: orderedPending.map((space) => ({ space: space.spaceId, storageHash: space.storageHash })),\n });\n}\n\ninterface WalkResult {\n readonly pendingOps: IdbDdlOp[];\n readonly destructiveDropped: number;\n}\n\n/**\n * Walk the migration chain from `markerHash` (or `null` for a fresh DB) to\n * `headHash`, collecting each pending package's ops in order. Applies the\n * policy filter on each op as it's added; returns the count of destructive\n * ops that were dropped so the caller can refuse if the policy demands.\n *\n * Throws on chain discontinuity (no package whose `from === cursor`) so\n * misconfigured `contractSpace` inputs fail loudly rather than silently\n * leaving the DB at an intermediate state.\n */\nasync function walkChain(input: {\n readonly markerHash: string | null;\n readonly headHash: string;\n readonly migrations: readonly MigrationPackage[];\n readonly policy: Required<MigrationPolicy>;\n}): Promise<WalkResult> {\n const byFrom = new Map<string | null, MigrationPackage>();\n for (const pkg of input.migrations) {\n byFrom.set(pkg.metadata.from, pkg);\n }\n\n const allowed = new Set(input.policy.allowedOperationClasses);\n const pendingOps: IdbDdlOp[] = [];\n let destructiveDropped = 0;\n let cursor: string | null = input.markerHash;\n const visited = new Set<string | null>();\n\n while (cursor !== input.headHash) {\n if (visited.has(cursor)) {\n throw new Error(\n `Auto-migration chain contains a cycle at hash ${JSON.stringify(cursor)}. ` +\n \"Re-run `prisma-idb migration contract-space` to rebuild a valid chain.\"\n );\n }\n visited.add(cursor);\n const next = byFrom.get(cursor);\n if (!next) {\n throw new Error(\n `Auto-migration chain broken: no migration package with from === ${JSON.stringify(cursor)}. ` +\n \"Verify that contract-space.generated.ts is up to date by re-running \" +\n \"`prisma-idb migration contract-space`.\"\n );\n }\n const computedHash = await computeMigrationHash(next.metadata, next.ops);\n if (computedHash !== next.metadata.migrationHash) {\n throw new Error(\n `Migration package \"${next.dirName}\" failed integrity check: ` +\n `stored migrationHash ${next.metadata.migrationHash} does not match ` +\n `computed hash ${computedHash}. ` +\n \"The ops may have been edited after the package was generated. \" +\n \"Re-run `prisma-idb migration plan` to regenerate the package.\"\n );\n }\n for (const op of next.ops) {\n if (!isIdbDdlOp(op)) {\n throw new Error(`Non-IDB operation found in migration package ${next.dirName}: ${JSON.stringify(op)}`);\n }\n if (allowed.has(op.operationClass)) {\n pendingOps.push(op);\n } else if (op.operationClass === \"destructive\") {\n if (input.policy.onDestructive === \"allow\") {\n pendingOps.push(op);\n } else {\n destructiveDropped += 1;\n }\n }\n // Other classes filtered silently.\n }\n cursor = next.metadata.to;\n }\n\n return { pendingOps, destructiveDropped };\n}\n\n/**\n * Open the database at its current local version (no version arg), read the\n * marker for `spaceId`, then close the connection. Returns the current integer\n * version so the caller can compute `currentVersion + 1` for the upgrade re-open.\n */\nfunction openAndReadMarker(\n dbName: string,\n factory: IDBFactory,\n spaceId: string\n): Promise<{ currentVersion: number; markerHash: string | null }> {\n return new Promise((resolve, reject) => {\n let req: IDBOpenDBRequest;\n try {\n req = factory.open(dbName);\n } catch (err) {\n reject(err);\n return;\n }\n\n req.onsuccess = () => {\n const db = req.result;\n const currentVersion = db.version;\n void (async () => {\n try {\n const record = await readMarker(db, spaceId);\n resolve({ currentVersion, markerHash: record?.storageHash ?? null });\n } catch (err) {\n reject(err);\n } finally {\n db.close();\n }\n })();\n };\n req.onerror = () => {\n reject(req.error ?? new Error(`IDB open failed while reading marker for \"${dbName}\"`));\n };\n });\n}\n","/**\n * `createManagedAutoIdbClient` — `createManagedIdbClient` pre-wired to\n * `createAutoMigratingIdbClient`. Composing those two by hand means writing\n * `dbName` twice, into two independent option bags with nothing tying them\n * together — `createManagedIdbClient`'s `dbName` is used only by `reset()`'s\n * `deleteDatabase` call, so if it ever drifts from the factory's own\n * `dbName` (typo, copy-paste into a second app), `reset()` silently deletes\n * the wrong database (or nothing) while the real one keeps its data. This\n * reads `dbName` (and a `factory` override, if set) once and threads it to\n * both layers, so they can't diverge.\n */\n\nimport { createAutoMigratingIdbClient } from \"./auto-migrate\";\nimport type { AutoMigrateClientOptions } from \"./auto-migrate\";\nimport type { IdbClient } from \"./idb-client\";\nimport { createManagedIdbClient } from \"./managed-client\";\nimport type { ManagedIdbClient } from \"./managed-client\";\nimport type { IdbContract } from \"./types\";\n\n/**\n * @example\n * ```ts\n * import { createManagedAutoIdbClient } from '@prisma-idb/client-idb/client-auto';\n *\n * const db = createManagedAutoIdbClient({ contractSpace, dbName: 'my-app' });\n *\n * const client = await db.get();\n * // ... on logout:\n * await db.reset();\n * ```\n */\nexport function createManagedAutoIdbClient<TContract extends IdbContract>(\n options: AutoMigrateClientOptions<TContract>\n): ManagedIdbClient<IdbClient<TContract>> {\n return createManagedIdbClient(() => createAutoMigratingIdbClient(options), {\n dbName: options.dbName,\n ...(options.factory !== undefined ? { idbFactory: options.factory } : {}),\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client-auto.mjs","names":[],"sources":["../src/core/migration-hash.ts","../src/core/auto-migrate.ts","../src/core/managed-auto-migrate.ts"],"sourcesContent":["import type { MigrationPackage } from \"@prisma/orm-framework/components/control\";\nimport { canonicalizeJson } from \"@prisma/orm-framework/components/utils\";\n\n/** Hex-encode the bytes of a digest buffer. */\nfunction toHex(buffer: ArrayBuffer): string {\n return Array.from(new Uint8Array(buffer), (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** SHA-256 → lowercase hex, via WebCrypto (`crypto.subtle`) — works in the browser. */\nasync function sha256Hex(input: string): Promise<string> {\n const digest = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(input));\n return toHex(digest);\n}\n\n/**\n * Browser-safe re-implementation of `computeMigrationHash` from\n * `@prisma/orm-toolchain/migration-tools/hash`.\n *\n * The framework version hashes with Node's `node:crypto` `createHash`, which\n * does not exist in the browser — so importing it into the runtime auto-migrate\n * integrity check (PLAN Issue #23 / ADR 199) throws `createHash is not a\n * function` on every client init and breaks the whole app. This version is\n * **byte-identical** to the framework's: it reuses the same `canonicalizeJson`\n * and the same nested SHA-256/hex scheme — strip `migrationHash` from the\n * metadata, hash the canonicalized metadata and ops separately, then hash\n * the canonicalized pair of those two hashes, as bare lowercase hex (no\n * `sha256:` prefix — dropped repo-wide at rc.4). Reusing the\n * identical canonicalization + algorithm guarantees the result matches the\n * `migrationHash` the CLI recorded, so the integrity check stays meaningful.\n *\n * `crypto.subtle.digest` is async, hence the `Promise` return (the framework's\n * Node version is synchronous). Callers in the async migration path await it.\n */\nexport async function computeMigrationHash(\n metadata: MigrationPackage[\"metadata\"],\n ops: MigrationPackage[\"ops\"]\n): Promise<string> {\n // v0.12.0 strips only `migrationHash` before hashing (`hints`/`labels` were\n // removed from the on-disk manifest schema entirely).\n const stripped: Record<string, unknown> = { ...metadata };\n delete stripped[\"migrationHash\"];\n const inner = await Promise.all([sha256Hex(canonicalizeJson(stripped)), sha256Hex(canonicalizeJson(ops))]);\n return sha256Hex(canonicalizeJson(inner));\n}\n","import type { Contract } from \"@prisma/orm-framework/contract/types\";\nimport type { ContractSpace, MigrationPackage } from \"@prisma/orm-framework/components/control\";\nimport { APP_SPACE_ID } from \"@prisma/orm-framework/components/control\";\nimport type { IdbExtensionSpace } from \"@prisma-idb/family-idb/control\";\n// Browser-safe (WebCrypto) hash — the framework's `@prisma/orm-toolchain/migration-tools/hash`\n// uses `node:crypto` and throws in the browser (PLAN Issue #23 regression).\nimport { computeMigrationHash } from \"./migration-hash\";\n// Import from `./runtime` (not `./migration`) so `MigrationCLI` → `node:fs`\n// is not bundled into the browser client.\nimport { isIdbDdlOp, openAndUpgrade, readMarker, type IdbDdlOp } from \"@prisma-idb/target-idb/runtime\";\nimport { createIdbClient, type IdbClient } from \"./idb-client\";\nimport type { IdbContract } from \"./types\";\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Options for {@link createAutoMigratingIdbClient}.\n *\n * `contractSpace` is the bundled artefact produced at design time by\n * `prisma-idb migration contract-space`. It carries the canonical\n * contract JSON, the ordered list of migration packages, and the head\n * ref the runtime walks toward.\n *\n * `extensions` is an optional list of additional contract spaces contributed\n * by IDB extensions (e.g. the sync extension). Each extension space migrates\n * independently of the application space and writes its own marker row keyed\n * by the extension's `spaceId`.\n */\nexport interface AutoMigrateClientOptions<TContract extends IdbContract> {\n readonly contractSpace: ContractSpace<TContract>;\n readonly dbName: string;\n /** IDB factory override — primarily for tests. Defaults to `indexedDB`. */\n readonly factory?: IDBFactory;\n /**\n * Additional contract spaces from IDB extensions.\n *\n * Every space with pending work — the application space plus each\n * extension — is applied together in one `upgradeneeded` transaction,\n * which also writes every space's marker. Each space still gets its own\n * marker row in `_prisma_next_marker`.\n */\n readonly extensions?: ReadonlyArray<IdbExtensionSpace>;\n}\n\n/**\n * Create a typed IDB client, applying any pending migrations from the bundled\n * `contractSpace` first.\n *\n * **What runs**:\n *\n * 1. Open the database at the current local version, read the marker from\n * `_prisma_next_marker`. (Null for a fresh database)\n * 2. If the marker hash equals `contractSpace.headRef.hash`, the database\n * is already at the target — return the client immediately.\n * 3. Otherwise, walk `contractSpace.migrations` from the marker hash (or\n * `null` for fresh) to `headRef.hash`, collecting each pending\n * package's `ops` in chain order.\n * 4. If `extensions` are configured, repeat steps 1–3 for each extension\n * space, then combine every space's pending ops into ONE reopen at\n * `db.version + 1` so `upgradeneeded` fires once; apply every collected\n * op (all spaces) inside that single version-change transaction, which\n * also writes every migrated space's marker.\n * 5. Hand back the typed `IdbClient`.\n *\n * Every pending op is applied exactly as planned, destructive ones included.\n * The developer reviewed them when running `prisma-idb migration plan`,\n * which warns about any that delete data. Skipping some ops would leave the\n * database claiming a schema it doesn't have, and refusing them would stop\n * the app from opening for every user.\n *\n * **What does NOT run in the browser**:\n *\n * The planner does not ship to the browser. The differ does not run. Live-DB\n * schema introspection does not happen. All the planning was done once at\n * design time and is encoded in the bundled `ops.json` blobs inside\n * `contractSpace.migrations`.\n *\n * @example\n * ```ts\n * import { createAutoMigratingIdbClient } from '@prisma-idb/client-idb/client-auto';\n * import { contractSpace } from './prisma/contract-space.generated';\n *\n * const db = await createAutoMigratingIdbClient({ contractSpace, dbName: 'my-app' });\n * const users = await db.orm.users.all().toArray();\n * ```\n */\nexport async function createAutoMigratingIdbClient<TContract extends IdbContract>(\n options: AutoMigrateClientOptions<TContract>\n): Promise<IdbClient<TContract>> {\n const factory = options.factory ?? indexedDB;\n\n await autoMigrate({\n // The public `AutoMigrateClientOptions<TContract>` is generic over the\n // user's narrow IDB contract; the internal `autoMigrate` only consumes\n // chain-walking fields, so widen to `ContractSpace<Contract>` here.\n contractSpace: options.contractSpace as unknown as ContractSpace<Contract>,\n dbName: options.dbName,\n factory,\n ...(options.extensions !== undefined ? { extensions: options.extensions } : {}),\n });\n\n return createIdbClient({\n contract: options.contractSpace.contractJson,\n dbName: options.dbName,\n factory,\n });\n}\n\n// ── Core migration loop ──────────────────────────────────────────────────────\n\n/**\n * The migration loop. Exported for tests.\n *\n * Collects pending ops from the app space and every extension space, then\n * applies all of them in a single `upgradeneeded` transaction (one IDB\n * version bump total). The same transaction writes the marker of every\n * space that migrated, so schema changes and markers commit together.\n *\n * @internal Prefer {@link createAutoMigratingIdbClient}.\n */\nexport async function autoMigrate(input: {\n // `ContractSpace<Contract>` instead of `<unknown>` so the generic\n // constraint `TContract extends Contract` from the framework is satisfied.\n // The internal apply path only reads `headRef.hash` and `migrations`, so\n // the precise contract shape inside `contractJson` doesn't matter here.\n readonly contractSpace: ContractSpace<Contract>;\n readonly dbName: string;\n readonly factory: IDBFactory;\n readonly extensions?: ReadonlyArray<IdbExtensionSpace>;\n}): Promise<void> {\n const { dbName, factory } = input;\n\n // Order here only affects the collection loop below, not the final apply\n // order (see the combined-apply step, which re-sorts to match upstream\n // ADR 212's extension-first convention).\n const spaces: Array<{ spaceId: string; contractSpace: ContractSpace<Contract> }> = [\n { spaceId: APP_SPACE_ID, contractSpace: input.contractSpace },\n ...(input.extensions ?? []),\n ];\n\n // Reject reserved/duplicate extension space IDs before touching the\n // database. Without this, two extensions sharing a spaceId would combine\n // their pending DDL and the upgrade would try to create the same stores\n // twice; an extension using APP_SPACE_ID would have its marker write\n // silently overwrite (or be overwritten by) the app space's marker.\n const seenSpaceIds = new Set<string>();\n for (const extension of input.extensions ?? []) {\n if (extension.spaceId === APP_SPACE_ID || seenSpaceIds.has(extension.spaceId)) {\n throw new Error(`Invalid duplicate or reserved extension space ID: \"${extension.spaceId}\"`);\n }\n seenSpaceIds.add(extension.spaceId);\n }\n\n // Descriptor self-consistency (upstream ADR 212): a space's pinned headRef\n // must match the hash actually embedded in its contractJson. Catches an\n // extension author who edited the contract source without regenerating\n // migrations/refs/head.json — fails loudly here instead of surfacing as a\n // confusing chain-walk error deep inside walkChain.\n for (const space of spaces) {\n const declaredHash = space.contractSpace.contractJson.storage.storageHash;\n const headHash = space.contractSpace.headRef.hash;\n if (declaredHash !== headHash) {\n throw new Error(\n `Contract space \"${space.spaceId}\" is internally inconsistent: ` +\n `contractJson.storage.storageHash (${declaredHash}) does not match ` +\n `headRef.hash (${headHash}). The contract source likely changed without ` +\n \"regenerating migrations/refs/head.json for this space — rebuild its migration chain.\"\n );\n }\n }\n\n // Read current DB version once (all spaces share the same IDB database).\n const { currentVersion: initialVersion } = await openAndReadMarker(dbName, factory, APP_SPACE_ID);\n\n // Collect pending work per space without applying yet, so a broken chain in\n // any space fails before the database is touched.\n const pendingPerSpace: Array<{ spaceId: string; ops: IdbDdlOp[]; storageHash: string }> = [];\n\n for (const space of spaces) {\n const targetHash = space.contractSpace.headRef.hash;\n const { markerHash } = await openAndReadMarker(dbName, factory, space.spaceId);\n if (markerHash === targetHash) continue;\n\n const pendingOps = await walkChain({\n markerHash,\n headHash: targetHash,\n migrations: space.contractSpace.migrations,\n });\n // Push whenever the marker is behind `targetHash` — even if every package\n // walked had zero ops (a hash-only \"bridge\" migration, e.g. re-emitting\n // the contract under a new hashing algorithm with no structural change).\n // Gating on `pendingOps.length > 0` here would skip the marker write\n // below for that space, and since nothing ever changes on a later\n // retry either, the marker gets stuck at the old hash forever — the\n // space never converges to `targetHash`, even though there was never\n // any actual work to do.\n pendingPerSpace.push({ spaceId: space.spaceId, ops: pendingOps, storageHash: targetHash });\n }\n\n if (pendingPerSpace.length === 0) return;\n\n // Combine every pending space into ONE upgradeneeded transaction (one IDB\n // version bump total), which also writes every space's marker. A failure\n // partway through rolls back all spaces' schema changes and markers, and a\n // multi-tab user hits one versionchange/blocked cycle on cold start instead\n // of one per space.\n //\n // DDL op order is extensions (alphabetical by spaceId) first, app space\n // last, matching upstream ADR 212's convention. That's safe even though the\n // app space creates `_prisma_next_marker`: openAndUpgrade writes the\n // markers only after every op has run.\n const orderedPending = [...pendingPerSpace].sort((a, b) => {\n if (a.spaceId === APP_SPACE_ID) return 1;\n if (b.spaceId === APP_SPACE_ID) return -1;\n return a.spaceId.localeCompare(b.spaceId);\n });\n\n await openAndUpgrade({\n factory,\n dbName,\n targetVersion: initialVersion + 1,\n ops: orderedPending.flatMap((space) => space.ops),\n markers: orderedPending.map((space) => ({ space: space.spaceId, storageHash: space.storageHash })),\n });\n}\n\n/**\n * Walk the migration chain from `markerHash` (or `null` for a fresh DB) to\n * `headHash`, collecting every pending package's ops in order.\n *\n * Throws on chain discontinuity (no package whose `from === cursor`) so\n * misconfigured `contractSpace` inputs fail loudly rather than silently\n * leaving the DB at an intermediate state.\n */\nasync function walkChain(input: {\n readonly markerHash: string | null;\n readonly headHash: string;\n readonly migrations: readonly MigrationPackage[];\n}): Promise<IdbDdlOp[]> {\n const byFrom = new Map<string | null, MigrationPackage>();\n for (const pkg of input.migrations) {\n byFrom.set(pkg.metadata.from, pkg);\n }\n\n const pendingOps: IdbDdlOp[] = [];\n let cursor: string | null = input.markerHash;\n const visited = new Set<string | null>();\n\n while (cursor !== input.headHash) {\n if (visited.has(cursor)) {\n throw new Error(\n `Auto-migration chain contains a cycle at hash ${JSON.stringify(cursor)}. ` +\n \"Re-run `prisma-idb migration contract-space` to rebuild a valid chain.\"\n );\n }\n visited.add(cursor);\n const next = byFrom.get(cursor);\n if (!next) {\n throw new Error(\n `Auto-migration chain broken: no migration package with from === ${JSON.stringify(cursor)}. ` +\n \"Verify that contract-space.generated.ts is up to date by re-running \" +\n \"`prisma-idb migration contract-space`.\"\n );\n }\n const computedHash = await computeMigrationHash(next.metadata, next.ops);\n if (computedHash !== next.metadata.migrationHash) {\n throw new Error(\n `Migration package \"${next.dirName}\" failed integrity check: ` +\n `stored migrationHash ${next.metadata.migrationHash} does not match ` +\n `computed hash ${computedHash}. ` +\n \"The ops may have been edited after the package was generated. \" +\n \"Re-run `prisma-idb migration plan` to regenerate the package.\"\n );\n }\n for (const op of next.ops) {\n if (!isIdbDdlOp(op)) {\n throw new Error(`Non-IDB operation found in migration package ${next.dirName}: ${JSON.stringify(op)}`);\n }\n pendingOps.push(op);\n }\n cursor = next.metadata.to;\n }\n\n return pendingOps;\n}\n\n/**\n * Open the database at its current local version (no version arg), read the\n * marker for `spaceId`, then close the connection. Returns the current integer\n * version so the caller can compute `currentVersion + 1` for the upgrade re-open.\n */\nfunction openAndReadMarker(\n dbName: string,\n factory: IDBFactory,\n spaceId: string\n): Promise<{ currentVersion: number; markerHash: string | null }> {\n return new Promise((resolve, reject) => {\n let req: IDBOpenDBRequest;\n try {\n req = factory.open(dbName);\n } catch (err) {\n reject(err);\n return;\n }\n\n req.onsuccess = () => {\n const db = req.result;\n const currentVersion = db.version;\n void (async () => {\n try {\n const record = await readMarker(db, spaceId);\n resolve({ currentVersion, markerHash: record?.storageHash ?? null });\n } catch (err) {\n reject(err);\n } finally {\n db.close();\n }\n })();\n };\n req.onerror = () => {\n reject(req.error ?? new Error(`IDB open failed while reading marker for \"${dbName}\"`));\n };\n });\n}\n","/**\n * `createManagedAutoIdbClient` — `createManagedIdbClient` pre-wired to\n * `createAutoMigratingIdbClient`. Composing those two by hand means writing\n * `dbName` twice, into two independent option bags with nothing tying them\n * together — `createManagedIdbClient`'s `dbName` is used only by `reset()`'s\n * `deleteDatabase` call, so if it ever drifts from the factory's own\n * `dbName` (typo, copy-paste into a second app), `reset()` silently deletes\n * the wrong database (or nothing) while the real one keeps its data. This\n * reads `dbName` (and a `factory` override, if set) once and threads it to\n * both layers, so they can't diverge.\n */\n\nimport { createAutoMigratingIdbClient } from \"./auto-migrate\";\nimport type { AutoMigrateClientOptions } from \"./auto-migrate\";\nimport type { IdbClient } from \"./idb-client\";\nimport { createManagedIdbClient } from \"./managed-client\";\nimport type { ManagedIdbClient } from \"./managed-client\";\nimport type { IdbContract } from \"./types\";\n\n/**\n * @example\n * ```ts\n * import { createManagedAutoIdbClient } from '@prisma-idb/client-idb/client-auto';\n *\n * const db = createManagedAutoIdbClient({ contractSpace, dbName: 'my-app' });\n *\n * const client = await db.get();\n * // ... on logout:\n * await db.reset();\n * ```\n */\nexport function createManagedAutoIdbClient<TContract extends IdbContract>(\n options: AutoMigrateClientOptions<TContract>\n): ManagedIdbClient<IdbClient<TContract>> {\n return createManagedIdbClient(() => createAutoMigratingIdbClient(options), {\n dbName: options.dbName,\n ...(options.factory !== undefined ? { idbFactory: options.factory } : {}),\n });\n}\n"],"mappings":";;;;;;AAIA,SAAS,MAAM,QAA6B;CAC1C,OAAO,MAAM,KAAK,IAAI,WAAW,MAAM,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;AACjG;;AAGA,eAAe,UAAU,OAAgC;CAEvD,OAAO,MAAM,MADQ,OAAO,OAAO,OAAO,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAAC,CACjE;AACrB;;;;;;;;;;;;;;;;;;;;AAqBA,eAAsB,qBACpB,UACA,KACiB;CAGjB,MAAM,WAAoC,EAAE,GAAG,SAAS;CACxD,OAAO,SAAS;CAChB,MAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC,UAAU,iBAAiB,QAAQ,CAAC,GAAG,UAAU,iBAAiB,GAAG,CAAC,CAAC,CAAC;CACzG,OAAO,UAAU,iBAAiB,KAAK,CAAC;AAC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC2CA,eAAsB,6BACpB,SAC+B;CAC/B,MAAM,UAAU,QAAQ,WAAW;CAEnC,MAAM,YAAY;EAIhB,eAAe,QAAQ;EACvB,QAAQ,QAAQ;EAChB;EACA,GAAI,QAAQ,eAAe,KAAA,IAAY,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;CAC/E,CAAC;CAED,OAAO,gBAAgB;EACrB,UAAU,QAAQ,cAAc;EAChC,QAAQ,QAAQ;EAChB;CACF,CAAC;AACH;;;;;;;;;;;AAcA,eAAsB,YAAY,OAShB;CAChB,MAAM,EAAE,QAAQ,YAAY;CAK5B,MAAM,SAA6E,CACjF;EAAE,SAAS;EAAc,eAAe,MAAM;CAAc,GAC5D,GAAI,MAAM,cAAc,CAAC,CAC3B;CAOA,MAAM,+BAAe,IAAI,IAAY;CACrC,KAAK,MAAM,aAAa,MAAM,cAAc,CAAC,GAAG;EAC9C,IAAI,UAAU,YAAY,gBAAgB,aAAa,IAAI,UAAU,OAAO,GAC1E,MAAM,IAAI,MAAM,sDAAsD,UAAU,QAAQ,EAAE;EAE5F,aAAa,IAAI,UAAU,OAAO;CACpC;CAOA,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,eAAe,MAAM,cAAc,aAAa,QAAQ;EAC9D,MAAM,WAAW,MAAM,cAAc,QAAQ;EAC7C,IAAI,iBAAiB,UACnB,MAAM,IAAI,MACR,mBAAmB,MAAM,QAAQ,kEACM,aAAa,iCACjC,SAAS,mIAE9B;CAEJ;CAGA,MAAM,EAAE,gBAAgB,mBAAmB,MAAM,kBAAkB,QAAQ,SAAS,YAAY;CAIhG,MAAM,kBAAoF,CAAC;CAE3F,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,MAAM,cAAc,QAAQ;EAC/C,MAAM,EAAE,eAAe,MAAM,kBAAkB,QAAQ,SAAS,MAAM,OAAO;EAC7E,IAAI,eAAe,YAAY;EAE/B,MAAM,aAAa,MAAM,UAAU;GACjC;GACA,UAAU;GACV,YAAY,MAAM,cAAc;EAClC,CAAC;EASD,gBAAgB,KAAK;GAAE,SAAS,MAAM;GAAS,KAAK;GAAY,aAAa;EAAW,CAAC;CAC3F;CAEA,IAAI,gBAAgB,WAAW,GAAG;CAYlC,MAAM,iBAAiB,CAAC,GAAG,eAAe,CAAC,CAAC,MAAM,GAAG,MAAM;EACzD,IAAI,EAAE,YAAY,cAAc,OAAO;EACvC,IAAI,EAAE,YAAY,cAAc,OAAO;EACvC,OAAO,EAAE,QAAQ,cAAc,EAAE,OAAO;CAC1C,CAAC;CAED,MAAM,eAAe;EACnB;EACA;EACA,eAAe,iBAAiB;EAChC,KAAK,eAAe,SAAS,UAAU,MAAM,GAAG;EAChD,SAAS,eAAe,KAAK,WAAW;GAAE,OAAO,MAAM;GAAS,aAAa,MAAM;EAAY,EAAE;CACnG,CAAC;AACH;;;;;;;;;AAUA,eAAe,UAAU,OAID;CACtB,MAAM,yBAAS,IAAI,IAAqC;CACxD,KAAK,MAAM,OAAO,MAAM,YACtB,OAAO,IAAI,IAAI,SAAS,MAAM,GAAG;CAGnC,MAAM,aAAyB,CAAC;CAChC,IAAI,SAAwB,MAAM;CAClC,MAAM,0BAAU,IAAI,IAAmB;CAEvC,OAAO,WAAW,MAAM,UAAU;EAChC,IAAI,QAAQ,IAAI,MAAM,GACpB,MAAM,IAAI,MACR,iDAAiD,KAAK,UAAU,MAAM,EAAE,2EAE1E;EAEF,QAAQ,IAAI,MAAM;EAClB,MAAM,OAAO,OAAO,IAAI,MAAM;EAC9B,IAAI,CAAC,MACH,MAAM,IAAI,MACR,mEAAmE,KAAK,UAAU,MAAM,EAAE,+GAG5F;EAEF,MAAM,eAAe,MAAM,qBAAqB,KAAK,UAAU,KAAK,GAAG;EACvE,IAAI,iBAAiB,KAAK,SAAS,eACjC,MAAM,IAAI,MACR,sBAAsB,KAAK,QAAQ,iDACT,KAAK,SAAS,cAAc,gCACnC,aAAa,gIAGlC;EAEF,KAAK,MAAM,MAAM,KAAK,KAAK;GACzB,IAAI,CAAC,WAAW,EAAE,GAChB,MAAM,IAAI,MAAM,gDAAgD,KAAK,QAAQ,IAAI,KAAK,UAAU,EAAE,GAAG;GAEvG,WAAW,KAAK,EAAE;EACpB;EACA,SAAS,KAAK,SAAS;CACzB;CAEA,OAAO;AACT;;;;;;AAOA,SAAS,kBACP,QACA,SACA,SACgE;CAChE,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,IAAI;EACJ,IAAI;GACF,MAAM,QAAQ,KAAK,MAAM;EAC3B,SAAS,KAAK;GACZ,OAAO,GAAG;GACV;EACF;EAEA,IAAI,kBAAkB;GACpB,MAAM,KAAK,IAAI;GACf,MAAM,iBAAiB,GAAG;GAC1B,CAAM,YAAY;IAChB,IAAI;KACF,MAAM,SAAS,MAAM,WAAW,IAAI,OAAO;KAC3C,QAAQ;MAAE;MAAgB,YAAY,QAAQ,eAAe;KAAK,CAAC;IACrE,SAAS,KAAK;KACZ,OAAO,GAAG;IACZ,UAAU;KACR,GAAG,MAAM;IACX;GACF,EAAA,CAAG;EACL;EACA,IAAI,gBAAgB;GAClB,OAAO,IAAI,yBAAS,IAAI,MAAM,6CAA6C,OAAO,EAAE,CAAC;EACvF;CACF,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;ACpSA,SAAgB,2BACd,SACwC;CACxC,OAAO,6BAA6B,6BAA6B,OAAO,GAAG;EACzE,QAAQ,QAAQ;EAChB,GAAI,QAAQ,YAAY,KAAA,IAAY,EAAE,YAAY,QAAQ,QAAQ,IAAI,CAAC;CACzE,CAAC;AACH"}
|
package/dist/client.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as IdbClientOptions, i as IdbClient, n as ManagedIdbClientOptions, o as createIdbClient, r as createManagedIdbClient, t as ManagedIdbClient } from "./managed-client-
|
|
1
|
+
import { a as IdbClientOptions, i as IdbClient, n as ManagedIdbClientOptions, o as createIdbClient, r as createManagedIdbClient, t as ManagedIdbClient } from "./managed-client-CJD9lBx5.mjs";
|
|
2
2
|
export { type IdbClient, type IdbClientOptions, type ManagedIdbClient, type ManagedIdbClientOptions, createIdbClient, createManagedIdbClient };
|
package/dist/client.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as createIdbClient, t as createManagedIdbClient } from "./managed-client-
|
|
1
|
+
import { n as createIdbClient, t as createManagedIdbClient } from "./managed-client-BLdCyxUi.mjs";
|
|
2
2
|
export { createIdbClient, createManagedIdbClient };
|