@prisma-idb/family-idb 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/bin/prisma-idb.d.mts +1 -0
  4. package/dist/bin/prisma-idb.mjs +13 -0
  5. package/dist/bin/prisma-idb.mjs.map +1 -0
  6. package/dist/chain-order-CaHXo5jz.mjs +44 -0
  7. package/dist/chain-order-CaHXo5jz.mjs.map +1 -0
  8. package/dist/cli-Dlaym_DD.mjs +342 -0
  9. package/dist/cli-Dlaym_DD.mjs.map +1 -0
  10. package/dist/contract-space-codegen--gfuyap2.mjs +128 -0
  11. package/dist/contract-space-codegen--gfuyap2.mjs.map +1 -0
  12. package/dist/exports/cli.d.mts +26 -0
  13. package/dist/exports/cli.d.mts.map +1 -0
  14. package/dist/exports/cli.mjs +2 -0
  15. package/dist/exports/config-types.d.mts +38 -0
  16. package/dist/exports/config-types.d.mts.map +1 -0
  17. package/dist/exports/config-types.mjs +66 -0
  18. package/dist/exports/config-types.mjs.map +1 -0
  19. package/dist/exports/contract-psl.d.mts +59 -0
  20. package/dist/exports/contract-psl.d.mts.map +1 -0
  21. package/dist/exports/contract-psl.mjs +97 -0
  22. package/dist/exports/contract-psl.mjs.map +1 -0
  23. package/dist/exports/contract-ts.d.mts +98 -0
  24. package/dist/exports/contract-ts.d.mts.map +1 -0
  25. package/dist/exports/contract-ts.mjs +275 -0
  26. package/dist/exports/contract-ts.mjs.map +1 -0
  27. package/dist/exports/control.d.mts +107 -0
  28. package/dist/exports/control.d.mts.map +1 -0
  29. package/dist/exports/control.mjs +573 -0
  30. package/dist/exports/control.mjs.map +1 -0
  31. package/dist/exports/pack.d.mts +10 -0
  32. package/dist/exports/pack.d.mts.map +1 -0
  33. package/dist/exports/pack.mjs +11 -0
  34. package/dist/exports/pack.mjs.map +1 -0
  35. package/dist/migration-plan-BWhd8BdV.mjs +330 -0
  36. package/dist/migration-plan-BWhd8BdV.mjs.map +1 -0
  37. package/dist/preflight-4jDCNvS0.mjs +119 -0
  38. package/dist/preflight-4jDCNvS0.mjs.map +1 -0
  39. package/dist/psl-interpreter-C0suaXu2.d.mts +45 -0
  40. package/dist/psl-interpreter-C0suaXu2.d.mts.map +1 -0
  41. package/dist/psl-interpreter-C6Q4okuO.mjs +809 -0
  42. package/dist/psl-interpreter-C6Q4okuO.mjs.map +1 -0
  43. package/dist/validate-BLnItEKs.mjs +48 -0
  44. package/dist/validate-BLnItEKs.mjs.map +1 -0
  45. package/package.json +64 -0
@@ -0,0 +1,573 @@
1
+ import { t as validateContract } from "../validate-BLnItEKs.mjs";
2
+ import { VERIFY_CODE_SCHEMA_FAILURE, VERIFY_CODE_TARGET_MISMATCH } from "@prisma/orm-framework/components/control";
3
+ //#region src/core/emission.ts
4
+ /**
5
+ * Converts a JavaScript primitive or plain object into a TypeScript type-literal
6
+ * string. Arrays become `readonly [...]` tuples; objects become `{ readonly k: v }`
7
+ * type literals; strings are single-quoted with escaping.
8
+ */
9
+ function serializeValue(value) {
10
+ if (value === null) return "null";
11
+ if (value === void 0) return "undefined";
12
+ if (typeof value === "string") return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
13
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
14
+ if (typeof value === "bigint") return `${value}n`;
15
+ if (Array.isArray(value)) return `readonly [${value.map((v) => serializeValue(v)).join(", ")}]`;
16
+ if (typeof value === "object") {
17
+ const entries = [];
18
+ for (const [k, v] of Object.entries(value)) entries.push(`readonly ${serializeObjectKey(k)}: ${serializeValue(v)}`);
19
+ return `{ ${entries.join("; ")} }`;
20
+ }
21
+ return "unknown";
22
+ }
23
+ /**
24
+ * Converts an object key to a safe TypeScript identifier. If the key is already a
25
+ * valid identifier it is returned as-is; otherwise it is wrapped in single-quoted
26
+ * string literal form.
27
+ */
28
+ function serializeObjectKey(key) {
29
+ if (/^[$A-Z_a-z][$\w]*$/.test(key)) return key;
30
+ return serializeValue(key);
31
+ }
32
+ /**
33
+ * IDB family emission plugin.
34
+ *
35
+ * Registered as `emission` on {@link IdbFamilyDescriptor}. The Prisma 8 emitter
36
+ * calls these methods when generating `contract.d.ts` for any schema that targets the
37
+ * IDB family. Each method returns a raw TypeScript source string that the emitter
38
+ * splices into the generated file at the appropriate location.
39
+ *
40
+ * @see `generateContractDts` in `@prisma/orm-toolchain`.
41
+ */
42
+ const idbEmission = {
43
+ id: "idb",
44
+ /**
45
+ * Serializes the full `storage` section of the contract into a TypeScript type
46
+ * literal. The result is used as the first generic argument of `ContractType<...>`
47
+ * in the generated `contract.d.ts`.
48
+ *
49
+ * For IDB the storage shape is:
50
+ * ```ts
51
+ * { readonly stores: { readonly <storeName>: { readonly keyPath: '...'; ... }; ... };
52
+ * readonly storageHash: <storageHashTypeName> }
53
+ * ```
54
+ *
55
+ * @param contract - The resolved Prisma contract.
56
+ * @param storageHashTypeName - Emitter-provided name of the `StorageHash` type alias
57
+ * to embed (e.g. `'StorageHash'`).
58
+ */
59
+ generateStorageType(contract, storageHashTypeName) {
60
+ const storage = contract.storage;
61
+ const stores = [];
62
+ for (const [storeName, store] of Object.entries(storage.stores).sort(([a], [b]) => a.localeCompare(b))) {
63
+ const storeParts = [`readonly keyPath: ${serializeValue(store.keyPath)}`];
64
+ if (store.autoIncrement !== void 0) storeParts.push(`readonly autoIncrement: ${store.autoIncrement}`);
65
+ const indexes = store.indexes ?? {};
66
+ if (Object.keys(indexes).length > 0) {
67
+ const indexEntries = [];
68
+ for (const [indexName, index] of Object.entries(indexes).sort(([a], [b]) => a.localeCompare(b))) {
69
+ const indexParts = [`readonly keyPath: ${serializeValue(index.keyPath)}`, `readonly unique: ${index.unique}`];
70
+ if (index.multiEntry !== void 0) indexParts.push(`readonly multiEntry: ${index.multiEntry}`);
71
+ indexEntries.push(`readonly ${serializeObjectKey(indexName)}: { ${indexParts.join("; ")} }`);
72
+ }
73
+ storeParts.push(`readonly indexes: { ${indexEntries.join("; ")} }`);
74
+ } else storeParts.push(`readonly indexes: Record<string, never>`);
75
+ stores.push(`readonly ${serializeObjectKey(storeName)}: { ${storeParts.join("; ")} }`);
76
+ }
77
+ const storesType = stores.length > 0 ? `{ ${stores.join("; ")} }` : "Record<string, never>";
78
+ const nsEntries = [];
79
+ for (const [nsId, ns] of Object.entries(storage.namespaces ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
80
+ const entriesObj = ns.entries ?? {};
81
+ const entriesType = Object.keys(entriesObj).length === 0 ? "Record<string, never>" : serializeValue(entriesObj);
82
+ nsEntries.push(`readonly ${serializeObjectKey(nsId)}: { readonly id: ${serializeValue(ns.id)}; readonly entries: ${entriesType} }`);
83
+ }
84
+ return `{ readonly stores: ${storesType}; readonly namespaces: ${nsEntries.length > 0 ? `{ ${nsEntries.join("; ")} }` : "Record<string, never>"}; readonly storageHash: ${storageHashTypeName} }`;
85
+ },
86
+ /**
87
+ * Serializes the per-model storage metadata into a TypeScript type literal.
88
+ * The result is used as the `storage` field of the model's entry in the
89
+ * generated `models` type.
90
+ *
91
+ * For IDB, each model maps to exactly one object store:
92
+ * ```ts
93
+ * { readonly storeName: '<name>'; readonly keyPath: '<field>' }
94
+ * ```
95
+ *
96
+ * @param _modelName - The Prisma model name (unused; provided for API symmetry).
97
+ * @param model - The resolved `ContractModel` whose `storage` is cast to
98
+ * {@link IdbModelStorage}.
99
+ */
100
+ generateModelStorageType(_modelName, model) {
101
+ const idbModel = model;
102
+ return [`{ readonly storeName: ${serializeValue(idbModel.storage.storeName)}`, `readonly keyPath: ${serializeValue(idbModel.storage.keyPath)} }`].join("; ");
103
+ },
104
+ /**
105
+ * Returns the `import type` lines prepended to `contract.d.ts` that bring
106
+ * IDB-family types into scope.
107
+ *
108
+ * Imports {@link IdbContractWithTypeMaps} (the phantom wrapper used by
109
+ * {@link getContractWrapper}) and {@link IdbTypeMaps} (used by
110
+ * {@link getTypeMapsExpression}).
111
+ */
112
+ getFamilyImports() {
113
+ return ["import type { IdbContractWithTypeMaps, IdbTypeMaps } from '@prisma-idb/target-idb/pack';"];
114
+ },
115
+ /**
116
+ * Returns additional type alias declarations appended to `contract.d.ts`
117
+ * after the codec and operation type aliases.
118
+ *
119
+ * For IDB this exports `LaneCodecTypes` (used by the generated client to
120
+ * look up codec input/output pairs) as a simple alias of the assembled
121
+ * `CodecTypes`. IDB has no query-operation types, so no further aliases
122
+ * are needed.
123
+ */
124
+ getFamilyTypeAliases() {
125
+ return "export type LaneCodecTypes = CodecTypes;";
126
+ },
127
+ /**
128
+ * Returns the TypeScript expression for the `TypeMaps<...>` generic
129
+ * instantiation written into `contract.d.ts`.
130
+ *
131
+ * IDB has no operation types or query-operation types, so the expression
132
+ * uses the three-argument form of {@link IdbTypeMaps}.
133
+ */
134
+ getTypeMapsExpression() {
135
+ return "IdbTypeMaps<CodecTypes, FieldOutputTypes, FieldInputTypes>";
136
+ },
137
+ /**
138
+ * Returns the final `export type Contract = ...` declaration and convenience
139
+ * re-exports derived from it.
140
+ *
141
+ * @param contractBaseName - Emitter-provided name of the base contract type
142
+ * (always `'ContractBase'`).
143
+ * @param typeMapsName - Emitter-provided name of the assembled TypeMaps type
144
+ * (always `'TypeMaps'`).
145
+ */
146
+ getContractWrapper(contractBaseName, typeMapsName) {
147
+ return [
148
+ `export type Contract = IdbContractWithTypeMaps<${contractBaseName}, ${typeMapsName}>;`,
149
+ "",
150
+ "export type Stores = Contract['storage']['stores'];"
151
+ ].join("\n");
152
+ }
153
+ };
154
+ //#endregion
155
+ //#region src/core/schema-verify.ts
156
+ function passNode(kind, name, contractPath, children = []) {
157
+ return {
158
+ status: "pass",
159
+ kind,
160
+ name,
161
+ contractPath,
162
+ code: "ok",
163
+ message: `${name} matches`,
164
+ expected: null,
165
+ actual: null,
166
+ children
167
+ };
168
+ }
169
+ function failNode(kind, name, contractPath, code, message, expected, actual, children = []) {
170
+ return {
171
+ status: "fail",
172
+ kind,
173
+ name,
174
+ contractPath,
175
+ code,
176
+ message,
177
+ expected,
178
+ actual,
179
+ children
180
+ };
181
+ }
182
+ function warnNode(kind, name, contractPath, code, message, expected, actual, children = []) {
183
+ return {
184
+ status: "warn",
185
+ kind,
186
+ name,
187
+ contractPath,
188
+ code,
189
+ message,
190
+ expected,
191
+ actual,
192
+ children
193
+ };
194
+ }
195
+ function countStatuses(nodes) {
196
+ let pass = 0, warn = 0, fail = 0, totalNodes = 0;
197
+ const stack = [...nodes];
198
+ while (stack.length > 0) {
199
+ const node = stack.pop();
200
+ totalNodes++;
201
+ if (node.status === "pass") pass++;
202
+ else if (node.status === "warn") warn++;
203
+ else fail++;
204
+ stack.push(...node.children);
205
+ }
206
+ return {
207
+ pass,
208
+ warn,
209
+ fail,
210
+ totalNodes
211
+ };
212
+ }
213
+ function verifyIndex(indexName, contractIndex, actualIndex, storeName, storePath, issues) {
214
+ const indexPath = `${storePath}.indexes.${indexName}`;
215
+ if (actualIndex === void 0) {
216
+ const msg = `Index "${indexName}" defined in contract is missing from manifest schema`;
217
+ issues.push({
218
+ kind: "missing_column",
219
+ table: storeName,
220
+ column: indexName,
221
+ message: msg,
222
+ path: [storeName, indexName]
223
+ });
224
+ return failNode("index", indexName, indexPath, "missing_column", msg, contractIndex, void 0);
225
+ }
226
+ const children = [];
227
+ if (contractIndex.keyPath !== actualIndex.keyPath) {
228
+ const msg = `Index "${indexName}" keyPath mismatch: expected "${contractIndex.keyPath}", got "${actualIndex.keyPath}"`;
229
+ issues.push({
230
+ kind: "index_mismatch",
231
+ table: storeName,
232
+ indexOrConstraint: indexName,
233
+ message: msg,
234
+ path: [storeName, indexName]
235
+ });
236
+ children.push(failNode("field", "keyPath", `${indexPath}.keyPath`, "index_mismatch", msg, contractIndex.keyPath, actualIndex.keyPath));
237
+ } else children.push(passNode("field", "keyPath", `${indexPath}.keyPath`));
238
+ if ((contractIndex.unique ?? false) !== (actualIndex.unique ?? false)) {
239
+ const msg = `Index "${indexName}" unique mismatch: expected ${contractIndex.unique}, got ${actualIndex.unique}`;
240
+ issues.push({
241
+ kind: "index_mismatch",
242
+ table: storeName,
243
+ indexOrConstraint: indexName,
244
+ message: msg,
245
+ path: [storeName, indexName]
246
+ });
247
+ children.push(failNode("field", "unique", `${indexPath}.unique`, "index_mismatch", msg, contractIndex.unique, actualIndex.unique));
248
+ } else children.push(passNode("field", "unique", `${indexPath}.unique`));
249
+ const contractME = contractIndex.multiEntry ?? false;
250
+ const actualME = actualIndex.multiEntry ?? false;
251
+ if (contractME !== actualME) {
252
+ const msg = `Index "${indexName}" multiEntry mismatch: expected ${contractME}, got ${actualME}`;
253
+ issues.push({
254
+ kind: "index_mismatch",
255
+ table: storeName,
256
+ indexOrConstraint: indexName,
257
+ message: msg,
258
+ path: [storeName, indexName]
259
+ });
260
+ children.push(failNode("field", "multiEntry", `${indexPath}.multiEntry`, "index_mismatch", msg, contractME, actualME));
261
+ } else if (contractME) children.push(passNode("field", "multiEntry", `${indexPath}.multiEntry`));
262
+ if (children.some((c) => c.status === "fail")) return failNode("index", indexName, indexPath, "index_mismatch", `Index "${indexName}" has mismatches`, null, null, children);
263
+ return passNode("index", indexName, indexPath, children);
264
+ }
265
+ function verifyStore(storeName, contractStore, actualStore, strict, issues) {
266
+ const storePath = `storage.stores.${storeName}`;
267
+ if (actualStore === void 0) {
268
+ const msg = `Object store "${storeName}" defined in contract is missing from manifest schema`;
269
+ issues.push({
270
+ kind: "missing_table",
271
+ table: storeName,
272
+ message: msg,
273
+ path: [storeName]
274
+ });
275
+ return failNode("collection", storeName, storePath, "missing_table", msg, contractStore, void 0);
276
+ }
277
+ const children = [];
278
+ if (contractStore.keyPath !== actualStore.keyPath) {
279
+ const msg = `Store "${storeName}" keyPath mismatch: expected "${contractStore.keyPath}", got "${actualStore.keyPath}"`;
280
+ issues.push({
281
+ kind: "primary_key_mismatch",
282
+ table: storeName,
283
+ message: msg,
284
+ path: [storeName]
285
+ });
286
+ children.push(failNode("field", "keyPath", `${storePath}.keyPath`, "primary_key_mismatch", msg, contractStore.keyPath, actualStore.keyPath));
287
+ } else children.push(passNode("field", "keyPath", `${storePath}.keyPath`));
288
+ const contractAI = contractStore.autoIncrement ?? false;
289
+ const actualAI = actualStore.autoIncrement ?? false;
290
+ if (contractAI !== actualAI) {
291
+ const msg = `Store "${storeName}" autoIncrement mismatch: expected ${contractAI}, got ${actualAI}`;
292
+ issues.push({
293
+ kind: "type_mismatch",
294
+ table: storeName,
295
+ message: msg,
296
+ path: [storeName]
297
+ });
298
+ children.push(failNode("field", "autoIncrement", `${storePath}.autoIncrement`, "type_mismatch", msg, contractAI, actualAI));
299
+ } else if (contractAI) children.push(passNode("field", "autoIncrement", `${storePath}.autoIncrement`));
300
+ const contractIndexes = contractStore.indexes ?? {};
301
+ const actualIndexes = actualStore.indexes ?? {};
302
+ for (const [indexName, contractIndex] of Object.entries(contractIndexes)) {
303
+ const actualIndex = actualIndexes[indexName];
304
+ children.push(verifyIndex(indexName, contractIndex, actualIndex, storeName, storePath, issues));
305
+ }
306
+ for (const indexName of Object.keys(actualIndexes)) if (!(indexName in contractIndexes)) {
307
+ const msg = `Index "${indexName}" exists in manifest but is not in contract`;
308
+ if (strict) {
309
+ issues.push({
310
+ kind: "extra_index",
311
+ table: storeName,
312
+ indexOrConstraint: indexName,
313
+ message: msg,
314
+ path: [storeName, indexName]
315
+ });
316
+ children.push(failNode("index", indexName, `${storePath}.indexes.${indexName}`, "extra_index", msg, void 0, actualIndexes[indexName]));
317
+ } else children.push(warnNode("index", indexName, `${storePath}.indexes.${indexName}`, "extra_index", msg, void 0, actualIndexes[indexName]));
318
+ }
319
+ if (children.some((c) => c.status === "fail")) return failNode("collection", storeName, storePath, "schema_mismatch", `Store "${storeName}" has schema issues`, null, null, children);
320
+ if (children.some((c) => c.status === "warn")) return {
321
+ status: "warn",
322
+ kind: "collection",
323
+ name: storeName,
324
+ contractPath: storePath,
325
+ code: "ok",
326
+ message: `Store "${storeName}" has warnings`,
327
+ expected: null,
328
+ actual: null,
329
+ children
330
+ };
331
+ return passNode("collection", storeName, storePath, children);
332
+ }
333
+ /**
334
+ * Pure, synchronous schema verification for IndexedDB.
335
+ *
336
+ * Compares the stores and indexes defined in the contract against the manifest
337
+ * schema (which represents the actual IndexedDB database). Returns a
338
+ * {@link VerifyDatabaseSchemaResult} that callers can inspect for issues.
339
+ *
340
+ * Does not perform any I/O — all inputs must already be available.
341
+ *
342
+ * @param contract - Validated IDB contract (what we expect the schema to be).
343
+ * @param schema - Schema IR from the manifest (what the schema actually is).
344
+ * @param strict - When `true`, extra stores/indexes in the manifest are failures.
345
+ * @param options - Optional context paths for metadata / error reporting.
346
+ */
347
+ function verifyIdbSchema(contract, schema, strict) {
348
+ const start = Date.now();
349
+ const issues = [];
350
+ const storeNodes = [];
351
+ const contractStores = contract.storage.stores;
352
+ const actualStores = schema.stores;
353
+ for (const [storeName, contractStore] of Object.entries(contractStores)) {
354
+ const actualStore = actualStores[storeName];
355
+ storeNodes.push(verifyStore(storeName, contractStore, actualStore, strict, issues));
356
+ }
357
+ for (const [storeName, actualStore] of Object.entries(actualStores)) if (!(storeName in contractStores)) {
358
+ const msg = `Object store "${storeName}" exists in manifest but is not in contract`;
359
+ if (strict) {
360
+ issues.push({
361
+ kind: "extra_table",
362
+ table: storeName,
363
+ message: msg,
364
+ path: [storeName]
365
+ });
366
+ storeNodes.push(failNode("collection", storeName, `storage.stores.${storeName}`, "extra_table", msg, void 0, actualStore));
367
+ } else storeNodes.push(warnNode("collection", storeName, `storage.stores.${storeName}`, "extra_table", msg, void 0, actualStore));
368
+ }
369
+ const root = {
370
+ status: storeNodes.some((n) => n.status === "fail") ? "fail" : storeNodes.some((n) => n.status === "warn") ? "warn" : "pass",
371
+ kind: "root",
372
+ name: "idb",
373
+ contractPath: "storage.stores",
374
+ code: issues.length === 0 ? "ok" : "schema_mismatch",
375
+ message: issues.length === 0 ? "All stores and indexes match" : `${issues.length} schema issue(s) found`,
376
+ expected: null,
377
+ actual: null,
378
+ children: storeNodes
379
+ };
380
+ const counts = countStatuses([root, ...storeNodes]);
381
+ const ok = root.status !== "fail";
382
+ const storageHash = contract.storage.storageHash;
383
+ const profileHash = contract.profileHash;
384
+ const contractField = profileHash !== void 0 ? {
385
+ storageHash,
386
+ profileHash
387
+ } : { storageHash };
388
+ const metaField = { strict };
389
+ const sharedResult = {
390
+ summary: ok ? "Schema verification passed" : `Schema verification failed: ${issues.length} issue(s)`,
391
+ contract: contractField,
392
+ target: { expected: "idb" },
393
+ schema: {
394
+ issues,
395
+ root,
396
+ counts
397
+ },
398
+ meta: metaField,
399
+ timings: { total: Date.now() - start }
400
+ };
401
+ if (ok) return {
402
+ ok: true,
403
+ ...sharedResult
404
+ };
405
+ return {
406
+ ok: false,
407
+ code: VERIFY_CODE_SCHEMA_FAILURE,
408
+ ...sharedResult
409
+ };
410
+ }
411
+ //#endregion
412
+ //#region src/core/control-instance.ts
413
+ const REFUSAL_CODE = "IDB-CLI-UNSUPPORTED";
414
+ /**
415
+ * Single-string refusal message baked into `summary` because the framework
416
+ * `VerifyDatabaseResult` / `SignDatabaseResult` `meta` field is strict-shaped
417
+ * (`{ contractPath, configPath? }`) and doesn't accept extra explanation
418
+ * fields. The summary is the only free-form text field on every result.
419
+ */
420
+ function refusalSummary(action) {
421
+ return `IndexedDB cannot be ${action} from the CLI. IndexedDB only exists in the browser; the CLI runs in Node.js, so there is no live database for it to inspect or update. Author migrations with \`prisma-idb migration plan\`, validate the chain with \`prisma-idb migration preflight\`, and let \`createAutoMigratingIdbClient\` apply them the next time the app opens in a browser.`;
422
+ }
423
+ function contractInfo(storageHash, profileHash) {
424
+ return profileHash !== void 0 ? {
425
+ storageHash,
426
+ profileHash
427
+ } : { storageHash };
428
+ }
429
+ function verifyMeta(contractPath, configPath) {
430
+ return configPath !== void 0 ? {
431
+ contractPath,
432
+ configPath
433
+ } : { contractPath };
434
+ }
435
+ function signMeta(contractPath, configPath) {
436
+ return configPath !== void 0 ? {
437
+ contractPath,
438
+ configPath
439
+ } : { contractPath };
440
+ }
441
+ /**
442
+ * Creates an IDB control family instance for the given control stack.
443
+ *
444
+ * **CLI surface — refusals**: IndexedDB is a browser API, so the CLI cannot
445
+ * read or write the live database. Every method that would normally talk to a
446
+ * database (`verify`, `sign`, `readMarker`, `readAllMarkers`, `introspect`)
447
+ * returns a structured refusal pointing the user at the contract-space
448
+ * authoring + preflight workflow.
449
+ *
450
+ * The CLI-side `db init`, `db update`, and `db verify` commands therefore
451
+ * surface a uniform `IDB-CLI-UNSUPPORTED` envelope rather than silently
452
+ * succeeding.
453
+ *
454
+ * **Active surface**: `deserializeContract` (pure) and `verifySchema` (pure
455
+ * function over an in-memory `IdbSchemaIR`) continue to work — neither
456
+ * needs a live database.
457
+ *
458
+ * @param _stack - The assembled control stack (unused; IDB has no adapter/extension layer).
459
+ */
460
+ function createIdbFamilyInstance(_stack) {
461
+ return {
462
+ familyId: "idb",
463
+ deserializeContract(contractJson) {
464
+ return validateContract(contractJson);
465
+ },
466
+ async verify(options) {
467
+ const start = Date.now();
468
+ const contract = validateContract(options.contract);
469
+ const storageHash = contract.storage.storageHash;
470
+ const profileHash = contract.profileHash;
471
+ if (options.expectedTargetId !== "idb") return {
472
+ ok: false,
473
+ code: VERIFY_CODE_TARGET_MISMATCH,
474
+ summary: `Target mismatch: expected "idb", got "${options.expectedTargetId}"`,
475
+ contract: contractInfo(storageHash, profileHash),
476
+ target: {
477
+ expected: options.expectedTargetId,
478
+ actual: "idb"
479
+ },
480
+ meta: verifyMeta(options.contractPath, options.configPath),
481
+ timings: { total: Date.now() - start }
482
+ };
483
+ return {
484
+ ok: false,
485
+ code: REFUSAL_CODE,
486
+ summary: refusalSummary("verified"),
487
+ contract: contractInfo(storageHash, profileHash),
488
+ target: {
489
+ expected: "idb",
490
+ actual: "idb"
491
+ },
492
+ meta: verifyMeta(options.contractPath, options.configPath),
493
+ timings: { total: Date.now() - start }
494
+ };
495
+ },
496
+ verifySchema(options) {
497
+ return verifyIdbSchema(validateContract(options.contract), options.schema, options.strict);
498
+ },
499
+ async sign(options) {
500
+ const start = Date.now();
501
+ const contract = validateContract(options.contract);
502
+ const storageHash = contract.storage.storageHash;
503
+ const profileHash = contract.profileHash ?? "";
504
+ return {
505
+ ok: false,
506
+ summary: refusalSummary("signed"),
507
+ contract: contractInfo(storageHash, profileHash),
508
+ target: {
509
+ expected: "idb",
510
+ actual: "idb"
511
+ },
512
+ marker: {
513
+ created: false,
514
+ updated: false
515
+ },
516
+ meta: signMeta(options.contractPath, options.configPath),
517
+ timings: { total: Date.now() - start }
518
+ };
519
+ },
520
+ async readMarker(_options) {
521
+ return null;
522
+ },
523
+ async readAllMarkers(_options) {
524
+ return /* @__PURE__ */ new Map();
525
+ },
526
+ async readLedger(_options) {
527
+ return [];
528
+ },
529
+ async introspect(_options) {
530
+ return { stores: {} };
531
+ }
532
+ };
533
+ }
534
+ //#endregion
535
+ //#region src/core/control-descriptor.ts
536
+ /**
537
+ * IDB family descriptor — the control-plane entry point for the IDB family.
538
+ *
539
+ * Registered in a Prisma 8 config file under the `family` key:
540
+ * ```ts
541
+ * import idb from '@prisma-idb/family-idb/control';
542
+ * export default defineConfig({ family: idb, ... });
543
+ * ```
544
+ *
545
+ * **Responsibilities:**
546
+ * - Carries the {@link idbEmission} plugin used by `prisma contract emit`
547
+ * to generate `contract.d.ts`.
548
+ * - Acts as a factory: `create(stack)` returns an {@link IdbControlFamilyInstance}
549
+ * with domain-action methods consumed by the CLI.
550
+ */
551
+ var IdbFamilyDescriptor = class {
552
+ kind = "family";
553
+ id = "idb";
554
+ familyId = "idb";
555
+ version = "0.0.1";
556
+ emission = idbEmission;
557
+ /**
558
+ * Creates an {@link IdbControlFamilyInstance} for the given control stack.
559
+ *
560
+ * The instance is a plain object whose methods implement the CLI domain
561
+ * actions (validateContract, verify, sign, etc.).
562
+ */
563
+ create(stack) {
564
+ return createIdbFamilyInstance(stack);
565
+ }
566
+ };
567
+ //#endregion
568
+ //#region src/exports/control.ts
569
+ var control_default = new IdbFamilyDescriptor();
570
+ //#endregion
571
+ export { control_default as default };
572
+
573
+ //# sourceMappingURL=control.mjs.map