@prisma-idb/client-idb 0.6.1 → 0.8.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 CHANGED
@@ -1,23 +1,36 @@
1
1
  # `@prisma-idb/client-idb`
2
2
 
3
- > Part of the [`@prisma-idb`](https://prisma-idb.dev/) driver stack for Prisma 8.
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
- **client-idb** is the ORM layer — the `idbOrm` typed query builder that end users and framework integrations call directly.
5
+ ```bash
6
+ npm install @prisma-idb/client-idb @prisma/orm-toolchain
7
+ ```
6
8
 
7
- ## Stack position
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
- ## Usage
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
- Consumed internally by [`@prisma-idb/family-idb`](https://www.npmjs.com/package/@prisma-idb/family-idb). You generally do not install this package directly — use `family-idb` as your entry point.
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
 
@@ -1,31 +1,9 @@
1
- import { b as IdbContract } from "./idb-orm-zCRkkD_D.mjs";
2
- import { a as IdbClientOptions, i as IdbClient, n as ManagedIdbClientOptions, o as createIdbClient, r as createManagedIdbClient, t as ManagedIdbClient } from "./managed-client-kdyHm72t.mjs";
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, MigrationOperationClass } from "@prisma/orm-framework/components/control";
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 combined `upgradeneeded`
54
- * transaction and one batched marker-write transaction (ADR 010). Each
55
- * space still gets its own marker row in `_prisma_next_marker`.
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. Apply the policy filter. Refuse if any destructive op was filtered
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
- * 6. Write every migrated space's marker in one batched readwrite tx.
79
- * 7. Hand back the typed `IdbClient`.
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 combined `upgradeneeded` transaction
103
- * (one IDB version bump total) followed by one batched marker-write
104
- * transaction covering every space that migrated. See ADR 010 for details.
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, type MigrationPolicy, autoMigrate, createAutoMigratingIdbClient, createIdbClient, createManagedAutoIdbClient, createManagedIdbClient };
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":";;;;;;;;;;;;;;;;;;;;;;;;UAqCiB;WACN,mCAAmC;WACnC;;;;;;;;;;;;;;;UAuBM,yBAAyB,kBAAkB;WACjD,eAAe,cAAc;WAC7B;;WAEA,SAAS;;WAET,UAAU;;;;;;;;;WASV,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyChB,6BAA6B,kBAAkB,aACnE,SAAS,yBAAyB,aACjC,QAAQ,UAAU;;;;;;;;;;;iBAyCC,YAAY;WAKvB,eAAe,cAAc;WAC7B;WACA,QAAQ,SAAS;WACjB,SAAS;WACT,aAAa,cAAc;IAClC;;;;;;;;;;;;;;;iBC5IY,2BAA2B,kBAAkB,aAC3D,SAAS,yBAAyB,aACjC,iBAAiB,UAAU"}
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"}
@@ -1,4 +1,4 @@
1
- import { n as createIdbClient, t as createManagedIdbClient } from "./managed-client-B_8JZM3h.mjs";
1
+ import { n as createIdbClient, t as createManagedIdbClient } from "./managed-client-DofL09P8.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. Apply the policy filter. Refuse if any destructive op was filtered
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
- * 6. Write every migrated space's marker in one batched readwrite tx.
65
- * 7. Hand back the typed `IdbClient`.
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 combined `upgradeneeded` transaction
110
- * (one IDB version bump total) followed by one batched marker-write
111
- * transaction covering every space that migrated. See ADR 010 for details.
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, policy, factory } = input;
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 { pendingOps, destructiveDropped } = await walkChain({
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 each pending package's ops in order. Applies the
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
- if (allowed.has(op.operationClass)) pendingOps.push(op);
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
@@ -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":"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"}
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-kdyHm72t.mjs";
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-B_8JZM3h.mjs";
1
+ import { n as createIdbClient, t as createManagedIdbClient } from "./managed-client-DofL09P8.mjs";
2
2
  export { createIdbClient, createManagedIdbClient };