@prisma-next/target-sqlite 0.5.0-dev.9 → 0.6.0-dev.1

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 (134) hide show
  1. package/dist/codec-ids-CYwMu3-4.d.mts +13 -0
  2. package/dist/codec-ids-CYwMu3-4.d.mts.map +1 -0
  3. package/dist/codec-ids-CuUxYcd0.mjs +13 -0
  4. package/dist/codec-ids-CuUxYcd0.mjs.map +1 -0
  5. package/dist/codec-ids.d.mts +2 -0
  6. package/dist/codec-ids.mjs +2 -0
  7. package/dist/codec-types-xLeyb_u4.d.mts +23 -0
  8. package/dist/codec-types-xLeyb_u4.d.mts.map +1 -0
  9. package/dist/codec-types.d.mts +3 -0
  10. package/dist/codec-types.mjs +2 -0
  11. package/dist/codecs-DEjc7dem.d.mts +203 -0
  12. package/dist/codecs-DEjc7dem.d.mts.map +1 -0
  13. package/dist/codecs-DVnHtVWW.mjs +220 -0
  14. package/dist/codecs-DVnHtVWW.mjs.map +1 -0
  15. package/dist/codecs.d.mts +2 -0
  16. package/dist/codecs.mjs +13 -0
  17. package/dist/codecs.mjs.map +1 -0
  18. package/dist/control.d.mts +4 -3
  19. package/dist/control.d.mts.map +1 -1
  20. package/dist/control.mjs +427 -5
  21. package/dist/control.mjs.map +1 -1
  22. package/dist/default-normalizer-3Fccw7yw.mjs +69 -0
  23. package/dist/default-normalizer-3Fccw7yw.mjs.map +1 -0
  24. package/dist/default-normalizer.d.mts +7 -0
  25. package/dist/default-normalizer.d.mts.map +1 -0
  26. package/dist/default-normalizer.mjs +2 -0
  27. package/dist/descriptor-meta-CE2Kbn9b.mjs +17 -0
  28. package/dist/descriptor-meta-CE2Kbn9b.mjs.map +1 -0
  29. package/dist/migration.d.mts +85 -0
  30. package/dist/migration.d.mts.map +1 -0
  31. package/dist/migration.mjs +49 -0
  32. package/dist/migration.mjs.map +1 -0
  33. package/dist/native-type-normalizer-BlN5XfD-.mjs +14 -0
  34. package/dist/native-type-normalizer-BlN5XfD-.mjs.map +1 -0
  35. package/dist/native-type-normalizer.d.mts +11 -0
  36. package/dist/native-type-normalizer.d.mts.map +1 -0
  37. package/dist/native-type-normalizer.mjs +2 -0
  38. package/dist/op-factory-call-DRKKURAO.mjs +279 -0
  39. package/dist/op-factory-call-DRKKURAO.mjs.map +1 -0
  40. package/dist/op-factory-call.d.mts +151 -0
  41. package/dist/op-factory-call.d.mts.map +1 -0
  42. package/dist/op-factory-call.mjs +2 -0
  43. package/dist/pack.d.mts +35 -1
  44. package/dist/pack.d.mts.map +1 -1
  45. package/dist/pack.mjs +2 -3
  46. package/dist/planner-A7dqS0u6.mjs +522 -0
  47. package/dist/planner-A7dqS0u6.mjs.map +1 -0
  48. package/dist/planner-produced-sqlite-migration-CI9LdXPr.d.mts +29 -0
  49. package/dist/planner-produced-sqlite-migration-CI9LdXPr.d.mts.map +1 -0
  50. package/dist/planner-produced-sqlite-migration-C_TzWbT0.mjs +110 -0
  51. package/dist/planner-produced-sqlite-migration-C_TzWbT0.mjs.map +1 -0
  52. package/dist/planner-produced-sqlite-migration.d.mts +2 -0
  53. package/dist/planner-produced-sqlite-migration.mjs +2 -0
  54. package/dist/planner-target-details-Bm71XPKb.mjs +15 -0
  55. package/dist/planner-target-details-Bm71XPKb.mjs.map +1 -0
  56. package/dist/planner-target-details-vhvZDWK1.d.mts +12 -0
  57. package/dist/planner-target-details-vhvZDWK1.d.mts.map +1 -0
  58. package/dist/planner-target-details.d.mts +2 -0
  59. package/dist/planner-target-details.mjs +2 -0
  60. package/dist/planner.d.mts +59 -0
  61. package/dist/planner.d.mts.map +1 -0
  62. package/dist/planner.mjs +2 -0
  63. package/dist/render-ops-CSRDT4YL.mjs +8 -0
  64. package/dist/render-ops-CSRDT4YL.mjs.map +1 -0
  65. package/dist/render-ops.d.mts +10 -0
  66. package/dist/render-ops.d.mts.map +1 -0
  67. package/dist/render-ops.mjs +2 -0
  68. package/dist/runtime.d.mts.map +1 -1
  69. package/dist/runtime.mjs +4 -8
  70. package/dist/runtime.mjs.map +1 -1
  71. package/dist/shared-qLsgTOZs.d.mts +69 -0
  72. package/dist/shared-qLsgTOZs.d.mts.map +1 -0
  73. package/dist/sql-utils-DhevMgef.mjs +35 -0
  74. package/dist/sql-utils-DhevMgef.mjs.map +1 -0
  75. package/dist/sql-utils.d.mts +22 -0
  76. package/dist/sql-utils.d.mts.map +1 -0
  77. package/dist/sql-utils.mjs +2 -0
  78. package/dist/sqlite-migration-BBJktVVw.mjs +16 -0
  79. package/dist/sqlite-migration-BBJktVVw.mjs.map +1 -0
  80. package/dist/sqlite-migration-DAb2NEX6.d.mts +17 -0
  81. package/dist/sqlite-migration-DAb2NEX6.d.mts.map +1 -0
  82. package/dist/statement-builders-Dne-LkAV.mjs +158 -0
  83. package/dist/statement-builders-Dne-LkAV.mjs.map +1 -0
  84. package/dist/statement-builders.d.mts +68 -0
  85. package/dist/statement-builders.d.mts.map +1 -0
  86. package/dist/statement-builders.mjs +2 -0
  87. package/dist/tables-D84zfPZI.mjs +403 -0
  88. package/dist/tables-D84zfPZI.mjs.map +1 -0
  89. package/package.json +33 -11
  90. package/src/core/authoring.ts +9 -0
  91. package/src/core/codec-helpers.ts +11 -0
  92. package/src/core/codec-ids.ts +13 -0
  93. package/src/core/codecs.ts +337 -0
  94. package/src/core/control-target.ts +53 -11
  95. package/src/core/default-normalizer.ts +92 -0
  96. package/src/core/descriptor-meta.ts +5 -1
  97. package/src/core/migrations/issue-planner.ts +586 -0
  98. package/src/core/migrations/op-factory-call.ts +369 -0
  99. package/src/core/migrations/operations/columns.ts +62 -0
  100. package/src/core/migrations/operations/data-transform.ts +51 -0
  101. package/src/core/migrations/operations/indexes.ts +52 -0
  102. package/src/core/migrations/operations/raw.ts +12 -0
  103. package/src/core/migrations/operations/shared.ts +120 -0
  104. package/src/core/migrations/operations/tables.ts +388 -0
  105. package/src/core/migrations/planner-ddl-builders.ts +142 -0
  106. package/src/core/migrations/planner-produced-sqlite-migration.ts +70 -0
  107. package/src/core/migrations/planner-strategies.ts +231 -0
  108. package/src/core/migrations/planner-target-details.ts +33 -0
  109. package/src/core/migrations/planner.ts +183 -0
  110. package/src/core/migrations/render-ops.ts +15 -0
  111. package/src/core/migrations/render-typescript.ts +91 -0
  112. package/src/core/migrations/runner.ts +724 -0
  113. package/src/core/migrations/sqlite-migration.ts +13 -0
  114. package/src/core/migrations/statement-builders.ts +212 -0
  115. package/src/core/native-type-normalizer.ts +9 -0
  116. package/src/core/registry.ts +11 -0
  117. package/src/core/runtime-target.ts +1 -3
  118. package/src/core/sql-utils.ts +47 -0
  119. package/src/exports/codec-ids.ts +13 -0
  120. package/src/exports/codec-types.ts +43 -0
  121. package/src/exports/codecs.ts +20 -0
  122. package/src/exports/control.ts +1 -0
  123. package/src/exports/default-normalizer.ts +1 -0
  124. package/src/exports/migration.ts +24 -0
  125. package/src/exports/native-type-normalizer.ts +1 -0
  126. package/src/exports/op-factory-call.ts +12 -0
  127. package/src/exports/planner-produced-sqlite-migration.ts +4 -0
  128. package/src/exports/planner-target-details.ts +2 -0
  129. package/src/exports/planner.ts +2 -0
  130. package/src/exports/render-ops.ts +1 -0
  131. package/src/exports/sql-utils.ts +1 -0
  132. package/src/exports/statement-builders.ts +12 -0
  133. package/dist/descriptor-meta-DbuuziYA.mjs +0 -14
  134. package/dist/descriptor-meta-DbuuziYA.mjs.map +0 -1
package/dist/control.mjs CHANGED
@@ -1,17 +1,439 @@
1
- import { t as sqliteTargetDescriptorMeta } from "./descriptor-meta-DbuuziYA.mjs";
2
-
1
+ import { t as sqliteTargetDescriptorMeta } from "./descriptor-meta-CE2Kbn9b.mjs";
2
+ import { t as parseSqliteDefault } from "./default-normalizer-3Fccw7yw.mjs";
3
+ import { t as normalizeSqliteNativeType } from "./native-type-normalizer-BlN5XfD-.mjs";
4
+ import { d as renderDefaultLiteral } from "./tables-D84zfPZI.mjs";
5
+ import { n as createSqliteMigrationPlanner } from "./planner-A7dqS0u6.mjs";
6
+ import { a as buildLedgerInsertStatement, c as ensureMarkerTableStatement, i as MARKER_TABLE_NAME, l as readMarkerStatement, o as buildWriteMarkerStatements, s as ensureLedgerTableStatement } from "./statement-builders-Dne-LkAV.mjs";
7
+ import { contractToSchemaIR, runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
8
+ import { verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
9
+ import { notOk, ok, okVoid } from "@prisma-next/utils/result";
10
+ import { ifDefined } from "@prisma-next/utils/defined";
11
+ import { APP_SPACE_ID } from "@prisma-next/framework-components/control";
12
+ import { parseContractMarkerRow } from "@prisma-next/family-sql/verify";
13
+ //#region src/core/migrations/runner.ts
14
+ function createSqliteMigrationRunner(family) {
15
+ return new SqliteMigrationRunner(family);
16
+ }
17
+ var SqliteMigrationRunner = class {
18
+ family;
19
+ constructor(family) {
20
+ this.family = family;
21
+ }
22
+ async execute(options) {
23
+ const driver = options.driver;
24
+ const destinationCheck = this.ensurePlanMatchesDestinationContract(options.plan.destination, options.destinationContract);
25
+ if (!destinationCheck.ok) return destinationCheck;
26
+ const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);
27
+ if (!policyCheck.ok) return policyCheck;
28
+ const fkWasEnabled = await this.readForeignKeysEnabled(driver);
29
+ if (fkWasEnabled) await driver.query("PRAGMA foreign_keys = OFF");
30
+ try {
31
+ await this.beginExclusiveTransaction(driver);
32
+ let committed = false;
33
+ try {
34
+ const result = await this.executeOnConnection(options);
35
+ if (!result.ok) return result;
36
+ if (fkWasEnabled) {
37
+ const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);
38
+ if (!fkIntegrityCheck.ok) return fkIntegrityCheck;
39
+ }
40
+ await this.commitTransaction(driver);
41
+ committed = true;
42
+ return result;
43
+ } finally {
44
+ if (!committed) await this.rollbackTransaction(driver);
45
+ }
46
+ } finally {
47
+ if (fkWasEnabled) await driver.query("PRAGMA foreign_keys = ON");
48
+ }
49
+ }
50
+ /**
51
+ * Apply the plan against an already-open connection without managing
52
+ * the transaction lifecycle. The caller owns BEGIN/COMMIT/ROLLBACK
53
+ * and any connection-level setup (FK pragma toggle, FK integrity
54
+ * check). Used by the per-space runner orchestration to fan out
55
+ * across contract spaces inside one outer transaction.
56
+ */
57
+ async executeOnConnection(options) {
58
+ const driver = options.driver;
59
+ if (options.space !== void 0 && options.space !== options.plan.spaceId) throw new Error(`SqlMigrationRunner: options.space (${options.space}) does not match plan.spaceId (${options.plan.spaceId})`);
60
+ const space = options.plan.spaceId;
61
+ const destinationCheck = this.ensurePlanMatchesDestinationContract(options.plan.destination, options.destinationContract);
62
+ if (!destinationCheck.ok) return destinationCheck;
63
+ const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);
64
+ if (!policyCheck.ok) return policyCheck;
65
+ const ensureResult = await this.ensureControlTables(driver);
66
+ if (!ensureResult.ok) return ensureResult;
67
+ const existingMarker = await this.readMarker(driver, space);
68
+ const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);
69
+ if (!markerCheck.ok) return markerCheck;
70
+ const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);
71
+ const isSelfEdge = options.plan.origin?.storageHash === options.plan.destination.storageHash;
72
+ const skipOperations = markerAtDestination && options.plan.origin != null && !isSelfEdge;
73
+ let operationsExecuted;
74
+ let executedOperations;
75
+ if (skipOperations) {
76
+ operationsExecuted = 0;
77
+ executedOperations = [];
78
+ } else {
79
+ const applyResult = await this.applyPlan(driver, options);
80
+ if (!applyResult.ok) return applyResult;
81
+ operationsExecuted = applyResult.value.operationsExecuted;
82
+ executedOperations = applyResult.value.executedOperations;
83
+ }
84
+ if (space === APP_SPACE_ID) {
85
+ const schemaIR = await this.family.introspect({
86
+ driver,
87
+ contract: options.destinationContract
88
+ });
89
+ const schemaVerifyResult = verifySqlSchema({
90
+ contract: options.destinationContract,
91
+ schema: schemaIR,
92
+ strict: options.strictVerification ?? true,
93
+ context: options.context ?? {},
94
+ typeMetadataRegistry: this.family.typeMetadataRegistry,
95
+ frameworkComponents: options.frameworkComponents,
96
+ normalizeDefault: parseSqliteDefault,
97
+ normalizeNativeType: normalizeSqliteNativeType
98
+ });
99
+ if (!schemaVerifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", schemaVerifyResult.summary, {
100
+ why: "The resulting database schema does not satisfy the destination contract.",
101
+ meta: { issues: schemaVerifyResult.schema.issues }
102
+ });
103
+ }
104
+ const incomingInvariants = options.plan.providedInvariants;
105
+ const existingInvariants = new Set(existingMarker?.invariants ?? []);
106
+ const incomingIsSubsetOfExisting = incomingInvariants.every((id) => existingInvariants.has(id));
107
+ if (!(isSelfEdge && operationsExecuted === 0 && incomingIsSubsetOfExisting)) {
108
+ await this.upsertMarker(driver, options, existingMarker, space);
109
+ await this.recordLedgerEntry(driver, options, existingMarker, executedOperations);
110
+ }
111
+ return runnerSuccess({
112
+ operationsPlanned: options.plan.operations.length,
113
+ operationsExecuted
114
+ });
115
+ }
116
+ async executeAcrossSpaces(options) {
117
+ const driver = options.driver;
118
+ const perSpaceOptions = options.perSpaceOptions;
119
+ if (perSpaceOptions.length === 0) return ok({ perSpaceResults: [] });
120
+ const fkWasEnabled = await this.readForeignKeysEnabled(driver);
121
+ if (fkWasEnabled) await driver.query("PRAGMA foreign_keys = OFF");
122
+ try {
123
+ await this.beginExclusiveTransaction(driver);
124
+ let committed = false;
125
+ try {
126
+ const perSpaceResults = [];
127
+ let lastProcessedSpace;
128
+ for (const spaceOptions of perSpaceOptions) {
129
+ const space = spaceOptions.space ?? spaceOptions.plan.spaceId;
130
+ const result = await this.executeOnConnection({
131
+ ...spaceOptions,
132
+ driver,
133
+ space
134
+ });
135
+ if (!result.ok) return notOk({
136
+ ...result.failure,
137
+ failingSpace: space
138
+ });
139
+ perSpaceResults.push({
140
+ space,
141
+ value: result.value
142
+ });
143
+ lastProcessedSpace = space;
144
+ }
145
+ if (fkWasEnabled) {
146
+ const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);
147
+ if (!fkIntegrityCheck.ok) return notOk({
148
+ ...fkIntegrityCheck.failure,
149
+ failingSpace: lastProcessedSpace ?? APP_SPACE_ID
150
+ });
151
+ }
152
+ await this.commitTransaction(driver);
153
+ committed = true;
154
+ return ok({ perSpaceResults });
155
+ } finally {
156
+ if (!committed) await this.rollbackTransaction(driver);
157
+ }
158
+ } finally {
159
+ if (fkWasEnabled) await driver.query("PRAGMA foreign_keys = ON");
160
+ }
161
+ }
162
+ async readForeignKeysEnabled(driver) {
163
+ return (await driver.query("PRAGMA foreign_keys")).rows[0]?.foreign_keys === 1;
164
+ }
165
+ async verifyForeignKeyIntegrity(driver) {
166
+ const result = await driver.query("PRAGMA foreign_key_check");
167
+ if (result.rows.length === 0) return okVoid();
168
+ return runnerFailure("FOREIGN_KEY_VIOLATION", `Foreign key integrity check failed after migration: ${result.rows.length} violation(s).`, {
169
+ why: "PRAGMA foreign_key_check reported violations after applying recreate-table operations.",
170
+ meta: { violations: result.rows }
171
+ });
172
+ }
173
+ async applyPlan(driver, options) {
174
+ const checks = options.executionChecks;
175
+ const runPrechecks = checks?.prechecks !== false;
176
+ const runPostchecks = checks?.postchecks !== false;
177
+ const runIdempotency = checks?.idempotencyChecks !== false;
178
+ let operationsExecuted = 0;
179
+ const executedOperations = [];
180
+ for (const operation of options.plan.operations) {
181
+ options.callbacks?.onOperationStart?.(operation);
182
+ try {
183
+ if (runPostchecks && runIdempotency) {
184
+ if (await this.expectationsAreSatisfied(driver, operation.postcheck)) {
185
+ executedOperations.push(this.createSkipRecord(operation));
186
+ continue;
187
+ }
188
+ }
189
+ if (runPrechecks) {
190
+ const precheckResult = await this.runExpectationSteps(driver, operation.precheck, operation, "precheck");
191
+ if (!precheckResult.ok) return precheckResult;
192
+ }
193
+ const executeResult = await this.runExecuteSteps(driver, operation.execute, operation);
194
+ if (!executeResult.ok) return executeResult;
195
+ if (runPostchecks) {
196
+ const postcheckResult = await this.runExpectationSteps(driver, operation.postcheck, operation, "postcheck");
197
+ if (!postcheckResult.ok) return postcheckResult;
198
+ }
199
+ executedOperations.push(operation);
200
+ operationsExecuted += 1;
201
+ } finally {
202
+ options.callbacks?.onOperationComplete?.(operation);
203
+ }
204
+ }
205
+ return ok({
206
+ operationsExecuted,
207
+ executedOperations
208
+ });
209
+ }
210
+ async ensureControlTables(driver) {
211
+ const legacyDetection = await this.detectLegacyMarkerShape(driver);
212
+ if (!legacyDetection.ok) return legacyDetection;
213
+ await this.executeStatement(driver, ensureMarkerTableStatement);
214
+ await this.executeStatement(driver, ensureLedgerTableStatement);
215
+ return okVoid();
216
+ }
217
+ async detectLegacyMarkerShape(driver) {
218
+ const tableInfo = await driver.query(`PRAGMA table_info("${MARKER_TABLE_NAME}")`);
219
+ if (tableInfo.rows.length === 0) return okVoid();
220
+ const columns = new Set(tableInfo.rows.map((row) => row.name));
221
+ if (columns.has("space")) return okVoid();
222
+ return runnerFailure("LEGACY_MARKER_SHAPE", `Legacy marker-table shape detected on ${MARKER_TABLE_NAME} (no \`space\` column). Prisma Next is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. Drop \`${MARKER_TABLE_NAME}\` and re-run \`dbInit\` to reinitialise from a clean baseline.`, { meta: {
223
+ table: MARKER_TABLE_NAME,
224
+ columns: [...columns].sort()
225
+ } });
226
+ }
227
+ async readMarker(driver, space) {
228
+ const stmt = readMarkerStatement(space);
229
+ try {
230
+ const row = (await driver.query(stmt.sql, stmt.params)).rows[0];
231
+ if (!row) return null;
232
+ const invariants = typeof row.invariants === "string" ? JSON.parse(row.invariants) : row.invariants;
233
+ return parseContractMarkerRow({
234
+ ...row,
235
+ invariants
236
+ });
237
+ } catch (error) {
238
+ if (error instanceof Error && error.message.includes("no such table")) return null;
239
+ throw error;
240
+ }
241
+ }
242
+ async runExpectationSteps(driver, steps, operation, phase) {
243
+ for (const step of steps) {
244
+ const result = await driver.query(step.sql, step.params ?? []);
245
+ if (!this.stepResultIsTrue(result.rows)) return runnerFailure(phase === "precheck" ? "PRECHECK_FAILED" : "POSTCHECK_FAILED", `Operation ${operation.id} failed during ${phase}: ${step.description}`, { meta: {
246
+ operationId: operation.id,
247
+ phase,
248
+ stepDescription: step.description
249
+ } });
250
+ }
251
+ return okVoid();
252
+ }
253
+ async runExecuteSteps(driver, steps, operation) {
254
+ for (const step of steps) try {
255
+ await driver.query(step.sql, step.params ?? []);
256
+ } catch (error) {
257
+ const message = error instanceof Error ? error.message : String(error);
258
+ return runnerFailure("EXECUTION_FAILED", `Operation ${operation.id} failed during execution: ${step.description}`, {
259
+ why: message,
260
+ meta: {
261
+ operationId: operation.id,
262
+ stepDescription: step.description,
263
+ sql: step.sql
264
+ }
265
+ });
266
+ }
267
+ return okVoid();
268
+ }
269
+ stepResultIsTrue(rows) {
270
+ if (!rows || rows.length === 0) return false;
271
+ const firstRow = rows[0];
272
+ const firstValue = firstRow ? Object.values(firstRow)[0] : void 0;
273
+ if (typeof firstValue === "number") return firstValue !== 0;
274
+ if (typeof firstValue === "boolean") return firstValue;
275
+ if (typeof firstValue === "string") {
276
+ const lower = firstValue.toLowerCase();
277
+ if (lower === "true" || lower === "1") return true;
278
+ if (lower === "false" || lower === "0") return false;
279
+ return firstValue.length > 0;
280
+ }
281
+ return Boolean(firstValue);
282
+ }
283
+ async expectationsAreSatisfied(driver, steps) {
284
+ if (steps.length === 0) return false;
285
+ for (const step of steps) {
286
+ const result = await driver.query(step.sql, step.params ?? []);
287
+ if (!this.stepResultIsTrue(result.rows)) return false;
288
+ }
289
+ return true;
290
+ }
291
+ createSkipRecord(operation) {
292
+ return Object.freeze({
293
+ id: operation.id,
294
+ label: operation.label,
295
+ ...ifDefined("summary", operation.summary),
296
+ operationClass: operation.operationClass,
297
+ target: operation.target,
298
+ precheck: Object.freeze([]),
299
+ execute: Object.freeze([]),
300
+ postcheck: Object.freeze([...operation.postcheck]),
301
+ meta: Object.freeze({
302
+ ...operation.meta ?? {},
303
+ runner: Object.freeze({
304
+ skipped: true,
305
+ reason: "postcheck_pre_satisfied"
306
+ })
307
+ })
308
+ });
309
+ }
310
+ markerMatchesDestination(marker, plan) {
311
+ if (!marker) return false;
312
+ if (marker.storageHash !== plan.destination.storageHash) return false;
313
+ if (plan.destination.profileHash && marker.profileHash !== plan.destination.profileHash) return false;
314
+ return true;
315
+ }
316
+ enforcePolicyCompatibility(policy, operations) {
317
+ const allowedClasses = new Set(policy.allowedOperationClasses);
318
+ for (const operation of operations) if (!allowedClasses.has(operation.operationClass)) return runnerFailure("POLICY_VIOLATION", `Operation ${operation.id} has class "${operation.operationClass}" which is not allowed by policy.`, {
319
+ why: `Policy only allows: ${policy.allowedOperationClasses.join(", ")}.`,
320
+ meta: {
321
+ operationId: operation.id,
322
+ operationClass: operation.operationClass,
323
+ allowedClasses: policy.allowedOperationClasses
324
+ }
325
+ });
326
+ return okVoid();
327
+ }
328
+ ensureMarkerCompatibility(marker, plan) {
329
+ const origin = plan.origin ?? null;
330
+ if (!origin) return okVoid();
331
+ if (!marker) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Missing contract marker: expected origin storage hash ${origin.storageHash}.`, { meta: { expectedOriginStorageHash: origin.storageHash } });
332
+ if (marker.storageHash !== origin.storageHash) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Existing contract marker (${marker.storageHash}) does not match plan origin (${origin.storageHash}).`, { meta: {
333
+ markerStorageHash: marker.storageHash,
334
+ expectedOriginStorageHash: origin.storageHash
335
+ } });
336
+ if (origin.profileHash && marker.profileHash !== origin.profileHash) return runnerFailure("MARKER_ORIGIN_MISMATCH", `Existing contract marker profile hash (${marker.profileHash}) does not match plan origin profile hash (${origin.profileHash}).`, { meta: {
337
+ markerProfileHash: marker.profileHash,
338
+ expectedOriginProfileHash: origin.profileHash
339
+ } });
340
+ return okVoid();
341
+ }
342
+ ensurePlanMatchesDestinationContract(destination, contract) {
343
+ if (destination.storageHash !== contract.storage.storageHash) return runnerFailure("DESTINATION_CONTRACT_MISMATCH", `Plan destination storage hash (${destination.storageHash}) does not match provided contract storage hash (${contract.storage.storageHash}).`, { meta: {
344
+ planStorageHash: destination.storageHash,
345
+ contractStorageHash: contract.storage.storageHash
346
+ } });
347
+ if (destination.profileHash && contract.profileHash && destination.profileHash !== contract.profileHash) return runnerFailure("DESTINATION_CONTRACT_MISMATCH", `Plan destination profile hash (${destination.profileHash}) does not match provided contract profile hash (${contract.profileHash}).`, { meta: {
348
+ planProfileHash: destination.profileHash,
349
+ contractProfileHash: contract.profileHash
350
+ } });
351
+ return okVoid();
352
+ }
353
+ async upsertMarker(driver, options, existingMarker, space) {
354
+ const merged = new Set(existingMarker?.invariants ?? []);
355
+ for (const inv of options.plan.providedInvariants) merged.add(inv);
356
+ const invariants = Array.from(merged).sort();
357
+ const writeStatements = buildWriteMarkerStatements({
358
+ space,
359
+ storageHash: options.plan.destination.storageHash,
360
+ profileHash: options.plan.destination.profileHash ?? options.destinationContract.profileHash ?? options.plan.destination.storageHash,
361
+ contractJson: options.destinationContract,
362
+ canonicalVersion: null,
363
+ meta: {},
364
+ invariants
365
+ });
366
+ const statement = existingMarker ? writeStatements.update : writeStatements.insert;
367
+ await this.executeStatement(driver, statement);
368
+ }
369
+ async recordLedgerEntry(driver, options, existingMarker, executedOperations) {
370
+ const ledgerStatement = buildLedgerInsertStatement({
371
+ originStorageHash: existingMarker?.storageHash ?? null,
372
+ originProfileHash: existingMarker?.profileHash ?? null,
373
+ destinationStorageHash: options.plan.destination.storageHash,
374
+ destinationProfileHash: options.plan.destination.profileHash ?? options.destinationContract.profileHash ?? options.plan.destination.storageHash,
375
+ contractJsonBefore: existingMarker?.contractJson ?? null,
376
+ contractJsonAfter: options.destinationContract,
377
+ operations: executedOperations
378
+ });
379
+ await this.executeStatement(driver, ledgerStatement);
380
+ }
381
+ async beginExclusiveTransaction(driver) {
382
+ await driver.query("BEGIN EXCLUSIVE");
383
+ }
384
+ async commitTransaction(driver) {
385
+ await driver.query("COMMIT");
386
+ }
387
+ async rollbackTransaction(driver) {
388
+ await driver.query("ROLLBACK");
389
+ }
390
+ async executeStatement(driver, statement) {
391
+ if (statement.params.length > 0) {
392
+ await driver.query(statement.sql, statement.params);
393
+ return;
394
+ }
395
+ await driver.query(statement.sql);
396
+ }
397
+ };
398
+ //#endregion
3
399
  //#region src/core/control-target.ts
400
+ function sqliteRenderDefault(def, _column) {
401
+ if (def.kind === "function") {
402
+ if (def.expression === "now()") return "datetime('now')";
403
+ return def.expression;
404
+ }
405
+ return renderDefaultLiteral(def.value);
406
+ }
4
407
  const sqliteControlTargetDescriptor = {
5
408
  ...sqliteTargetDescriptorMeta,
409
+ migrations: {
410
+ createPlanner(_family) {
411
+ return createSqliteMigrationPlanner();
412
+ },
413
+ createRunner(family) {
414
+ return createSqliteMigrationRunner(family);
415
+ },
416
+ contractToSchema(contract, _frameworkComponents) {
417
+ return contractToSchemaIR(contract, {
418
+ annotationNamespace: "sqlite",
419
+ renderDefault: sqliteRenderDefault
420
+ });
421
+ }
422
+ },
6
423
  create() {
7
424
  return {
8
425
  familyId: "sql",
9
426
  targetId: "sqlite"
10
427
  };
428
+ },
429
+ createPlanner(_family) {
430
+ return createSqliteMigrationPlanner();
431
+ },
432
+ createRunner(family) {
433
+ return createSqliteMigrationRunner(family);
11
434
  }
12
435
  };
13
- var control_target_default = sqliteControlTargetDescriptor;
14
-
15
436
  //#endregion
16
- export { control_target_default as default };
437
+ export { sqliteControlTargetDescriptor as default };
438
+
17
439
  //# sourceMappingURL=control.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"control.mjs","names":["sqliteControlTargetDescriptor: ControlTargetDescriptor<\n 'sql',\n 'sqlite',\n ControlTargetInstance<'sql', 'sqlite'>\n>"],"sources":["../src/core/control-target.ts"],"sourcesContent":["import type {\n ControlTargetDescriptor,\n ControlTargetInstance,\n} from '@prisma-next/framework-components/control';\nimport { sqliteTargetDescriptorMeta } from './descriptor-meta';\n\nconst sqliteControlTargetDescriptor: ControlTargetDescriptor<\n 'sql',\n 'sqlite',\n ControlTargetInstance<'sql', 'sqlite'>\n> = {\n ...sqliteTargetDescriptorMeta,\n create(): ControlTargetInstance<'sql', 'sqlite'> {\n return { familyId: 'sql', targetId: 'sqlite' };\n },\n};\n\nexport default sqliteControlTargetDescriptor;\n"],"mappings":";;;AAMA,MAAMA,gCAIF;CACF,GAAG;CACH,SAAiD;AAC/C,SAAO;GAAE,UAAU;GAAO,UAAU;GAAU;;CAEjD;AAED,6BAAe"}
1
+ {"version":3,"file":"control.mjs","names":[],"sources":["../src/core/migrations/runner.ts","../src/core/control-target.ts"],"sourcesContent":["import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n MultiSpaceRunnerResult,\n SqlControlFamilyInstance,\n SqlMigrationPlanContractInfo,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationRunner,\n SqlMigrationRunnerExecuteOptions,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerResult,\n SqlMigrationRunnerSuccessValue,\n} from '@prisma-next/family-sql/control';\nimport { runnerFailure, runnerSuccess } from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport { type ContractMarkerRow, parseContractMarkerRow } from '@prisma-next/family-sql/verify';\nimport type { ControlDriverInstance } from '@prisma-next/framework-components/control';\nimport { APP_SPACE_ID } from '@prisma-next/framework-components/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok, okVoid } from '@prisma-next/utils/result';\nimport { parseSqliteDefault } from '../default-normalizer';\nimport { normalizeSqliteNativeType } from '../native-type-normalizer';\nimport type { SqlitePlanTargetDetails } from './planner-target-details';\nimport {\n buildLedgerInsertStatement,\n buildWriteMarkerStatements,\n ensureLedgerTableStatement,\n ensureMarkerTableStatement,\n MARKER_TABLE_NAME,\n readMarkerStatement,\n type SqlStatement,\n} from './statement-builders';\n\nexport function createSqliteMigrationRunner(\n family: SqlControlFamilyInstance,\n): SqlMigrationRunner<SqlitePlanTargetDetails> {\n return new SqliteMigrationRunner(family);\n}\n\nclass SqliteMigrationRunner implements SqlMigrationRunner<SqlitePlanTargetDetails> {\n constructor(private readonly family: SqlControlFamilyInstance) {}\n\n async execute(\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n ): Promise<SqlMigrationRunnerResult> {\n const driver = options.driver;\n\n const destinationCheck = this.ensurePlanMatchesDestinationContract(\n options.plan.destination,\n options.destinationContract,\n );\n if (!destinationCheck.ok) return destinationCheck;\n\n const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);\n if (!policyCheck.ok) return policyCheck;\n\n // SQLite recreate-table drops and rebuilds the table. If foreign_keys is ON,\n // dropping a referenced parent cascade-deletes child rows; we must disable FK\n // enforcement for the duration of the migration and validate integrity before\n // committing. PRAGMA foreign_keys is a no-op inside a transaction, so toggle\n // around BEGIN/COMMIT.\n const fkWasEnabled = await this.readForeignKeysEnabled(driver);\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = OFF');\n }\n\n try {\n await this.beginExclusiveTransaction(driver);\n let committed = false;\n try {\n const result = await this.executeOnConnection(options);\n if (!result.ok) return result;\n\n if (fkWasEnabled) {\n const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);\n if (!fkIntegrityCheck.ok) return fkIntegrityCheck;\n }\n\n await this.commitTransaction(driver);\n committed = true;\n return result;\n } finally {\n if (!committed) {\n await this.rollbackTransaction(driver);\n }\n }\n } finally {\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = ON');\n }\n }\n }\n\n /**\n * Apply the plan against an already-open connection without managing\n * the transaction lifecycle. The caller owns BEGIN/COMMIT/ROLLBACK\n * and any connection-level setup (FK pragma toggle, FK integrity\n * check). Used by the per-space runner orchestration to fan out\n * across contract spaces inside one outer transaction.\n */\n async executeOnConnection(\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n ): Promise<SqlMigrationRunnerResult> {\n const driver = options.driver;\n if (options.space !== undefined && options.space !== options.plan.spaceId) {\n throw new Error(\n `SqlMigrationRunner: options.space (${options.space}) does not match plan.spaceId (${options.plan.spaceId})`,\n );\n }\n const space = options.plan.spaceId;\n\n const destinationCheck = this.ensurePlanMatchesDestinationContract(\n options.plan.destination,\n options.destinationContract,\n );\n if (!destinationCheck.ok) return destinationCheck;\n\n const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);\n if (!policyCheck.ok) return policyCheck;\n\n const ensureResult = await this.ensureControlTables(driver);\n if (!ensureResult.ok) return ensureResult;\n const existingMarker = await this.readMarker(driver, space);\n\n const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);\n if (!markerCheck.ok) return markerCheck;\n\n const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);\n const isSelfEdge = options.plan.origin?.storageHash === options.plan.destination.storageHash;\n const skipOperations = markerAtDestination && options.plan.origin != null && !isSelfEdge;\n\n let operationsExecuted: number;\n let executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[];\n\n if (skipOperations) {\n operationsExecuted = 0;\n executedOperations = [];\n } else {\n const applyResult = await this.applyPlan(driver, options);\n if (!applyResult.ok) return applyResult;\n operationsExecuted = applyResult.value.operationsExecuted;\n executedOperations = applyResult.value.executedOperations;\n }\n\n if (space === APP_SPACE_ID) {\n const schemaIR = await this.family.introspect({\n driver,\n contract: options.destinationContract,\n });\n\n const schemaVerifyResult = verifySqlSchema({\n contract: options.destinationContract,\n schema: schemaIR,\n strict: options.strictVerification ?? true,\n context: options.context ?? {},\n typeMetadataRegistry: this.family.typeMetadataRegistry,\n frameworkComponents: options.frameworkComponents,\n normalizeDefault: parseSqliteDefault,\n normalizeNativeType: normalizeSqliteNativeType,\n });\n if (!schemaVerifyResult.ok) {\n return runnerFailure('SCHEMA_VERIFY_FAILED', schemaVerifyResult.summary, {\n why: 'The resulting database schema does not satisfy the destination contract.',\n meta: { issues: schemaVerifyResult.schema.issues },\n });\n }\n }\n\n // Self-edge no-op detection: see Postgres runner for the rationale\n // (kept symmetric across both targets).\n const incomingInvariants = options.plan.providedInvariants;\n const existingInvariants = new Set(existingMarker?.invariants ?? []);\n const incomingIsSubsetOfExisting = incomingInvariants.every((id) => existingInvariants.has(id));\n const isSelfEdgeNoOp = isSelfEdge && operationsExecuted === 0 && incomingIsSubsetOfExisting;\n\n if (!isSelfEdgeNoOp) {\n await this.upsertMarker(driver, options, existingMarker, space);\n await this.recordLedgerEntry(driver, options, existingMarker, executedOperations);\n }\n\n return runnerSuccess({\n operationsPlanned: options.plan.operations.length,\n operationsExecuted,\n });\n }\n\n async executeAcrossSpaces(options: {\n readonly driver: ControlDriverInstance<'sql', string>;\n readonly perSpaceOptions: ReadonlyArray<\n SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>\n >;\n }): Promise<MultiSpaceRunnerResult> {\n const driver = options.driver;\n const perSpaceOptions = options.perSpaceOptions;\n\n if (perSpaceOptions.length === 0) {\n return ok({ perSpaceResults: [] });\n }\n\n // FK pragma toggle and the FK integrity check both span the outer\n // transaction — see `execute(...)` for the full rationale.\n const fkWasEnabled = await this.readForeignKeysEnabled(driver);\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = OFF');\n }\n\n try {\n await this.beginExclusiveTransaction(driver);\n let committed = false;\n try {\n const perSpaceResults: Array<{\n space: string;\n value: SqlMigrationRunnerSuccessValue;\n }> = [];\n let lastProcessedSpace: string | undefined;\n for (const spaceOptions of perSpaceOptions) {\n const space = spaceOptions.space ?? spaceOptions.plan.spaceId;\n const result = await this.executeOnConnection({ ...spaceOptions, driver, space });\n if (!result.ok) {\n return notOk({ ...result.failure, failingSpace: space });\n }\n perSpaceResults.push({ space, value: result.value });\n lastProcessedSpace = space;\n }\n\n if (fkWasEnabled) {\n const fkIntegrityCheck = await this.verifyForeignKeyIntegrity(driver);\n if (!fkIntegrityCheck.ok) {\n // Post-loop integrity violations cannot be attributed to a\n // single per-space step (the cumulative effect of all\n // applied plans was needed to reveal the broken\n // reference). Surface the last successfully-applied space\n // so operators can investigate from the most recent\n // migration first.\n return notOk({\n ...fkIntegrityCheck.failure,\n failingSpace: lastProcessedSpace ?? APP_SPACE_ID,\n });\n }\n }\n\n await this.commitTransaction(driver);\n committed = true;\n return ok({ perSpaceResults });\n } finally {\n if (!committed) {\n await this.rollbackTransaction(driver);\n }\n }\n } finally {\n if (fkWasEnabled) {\n await driver.query('PRAGMA foreign_keys = ON');\n }\n }\n }\n\n private async readForeignKeysEnabled(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<boolean> {\n const result = await driver.query<{ foreign_keys: number }>('PRAGMA foreign_keys');\n const row = result.rows[0];\n return row?.foreign_keys === 1;\n }\n\n private async verifyForeignKeyIntegrity(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n const result = await driver.query<Record<string, unknown>>('PRAGMA foreign_key_check');\n if (result.rows.length === 0) {\n return okVoid();\n }\n return runnerFailure(\n 'FOREIGN_KEY_VIOLATION',\n `Foreign key integrity check failed after migration: ${result.rows.length} violation(s).`,\n {\n why: 'PRAGMA foreign_key_check reported violations after applying recreate-table operations.',\n meta: { violations: result.rows },\n },\n );\n }\n\n private async applyPlan(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n ): Promise<\n Result<\n {\n readonly operationsExecuted: number;\n readonly executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[];\n },\n SqlMigrationRunnerFailure\n >\n > {\n const checks = options.executionChecks;\n const runPrechecks = checks?.prechecks !== false;\n const runPostchecks = checks?.postchecks !== false;\n const runIdempotency = checks?.idempotencyChecks !== false;\n\n let operationsExecuted = 0;\n const executedOperations: Array<SqlMigrationPlanOperation<SqlitePlanTargetDetails>> = [];\n\n for (const operation of options.plan.operations) {\n options.callbacks?.onOperationStart?.(operation);\n try {\n if (runPostchecks && runIdempotency) {\n const postcheckAlreadySatisfied = await this.expectationsAreSatisfied(\n driver,\n operation.postcheck,\n );\n if (postcheckAlreadySatisfied) {\n executedOperations.push(this.createSkipRecord(operation));\n continue;\n }\n }\n\n if (runPrechecks) {\n const precheckResult = await this.runExpectationSteps(\n driver,\n operation.precheck,\n operation,\n 'precheck',\n );\n if (!precheckResult.ok) {\n return precheckResult;\n }\n }\n\n const executeResult = await this.runExecuteSteps(driver, operation.execute, operation);\n if (!executeResult.ok) {\n return executeResult;\n }\n\n if (runPostchecks) {\n const postcheckResult = await this.runExpectationSteps(\n driver,\n operation.postcheck,\n operation,\n 'postcheck',\n );\n if (!postcheckResult.ok) {\n return postcheckResult;\n }\n }\n\n executedOperations.push(operation);\n operationsExecuted += 1;\n } finally {\n options.callbacks?.onOperationComplete?.(operation);\n }\n }\n return ok({ operationsExecuted, executedOperations });\n }\n\n private async ensureControlTables(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n // Pre-1.0 zero-range guardrail: detect a pre-cleanup single-row\n // marker table (no `space` column) and surface a structured failure\n // rather than silently rebuilding the table into the per-space\n // shape. See `specs/framework-mechanism.spec.md § 2`.\n const legacyDetection = await this.detectLegacyMarkerShape(driver);\n if (!legacyDetection.ok) {\n return legacyDetection;\n }\n await this.executeStatement(driver, ensureMarkerTableStatement);\n await this.executeStatement(driver, ensureLedgerTableStatement);\n return okVoid();\n }\n\n private async detectLegacyMarkerShape(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n const tableInfo = await driver.query<{ name: string }>(\n `PRAGMA table_info(\"${MARKER_TABLE_NAME}\")`,\n );\n if (tableInfo.rows.length === 0) {\n return okVoid();\n }\n const columns = new Set(tableInfo.rows.map((row) => row.name));\n if (columns.has('space')) {\n return okVoid();\n }\n return runnerFailure(\n 'LEGACY_MARKER_SHAPE',\n `Legacy marker-table shape detected on ${MARKER_TABLE_NAME} (no \\`space\\` column). ` +\n 'Prisma Next is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. ' +\n `Drop \\`${MARKER_TABLE_NAME}\\` and re-run \\`dbInit\\` to reinitialise from a clean baseline.`,\n {\n meta: {\n table: MARKER_TABLE_NAME,\n columns: [...columns].sort(),\n },\n },\n );\n }\n\n private async readMarker(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n space: string,\n ): Promise<ContractMarkerRecord | null> {\n const stmt = readMarkerStatement(space);\n try {\n const result = await driver.query<ContractMarkerRow>(stmt.sql, stmt.params);\n const row = result.rows[0];\n if (!row) return null;\n // SQLite stores arrays as JSON-encoded TEXT (no native array type), so\n // the driver returns `invariants` as a string. Decode before delegating\n // to the shared row schema, which expects `string[]`.\n const invariants =\n typeof row.invariants === 'string'\n ? (JSON.parse(row.invariants) as unknown)\n : row.invariants;\n return parseContractMarkerRow({ ...row, invariants });\n } catch (error) {\n // Table might not exist yet\n if (error instanceof Error && error.message.includes('no such table')) {\n return null;\n }\n throw error;\n }\n }\n\n private async runExpectationSteps(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n phase: 'precheck' | 'postcheck',\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n const result = await driver.query(step.sql, step.params ?? []);\n if (!this.stepResultIsTrue(result.rows)) {\n const code = phase === 'precheck' ? 'PRECHECK_FAILED' : 'POSTCHECK_FAILED';\n return runnerFailure(\n code,\n `Operation ${operation.id} failed during ${phase}: ${step.description}`,\n {\n meta: {\n operationId: operation.id,\n phase,\n stepDescription: step.description,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private async runExecuteSteps(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n try {\n await driver.query(step.sql, step.params ?? []);\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return runnerFailure(\n 'EXECUTION_FAILED',\n `Operation ${operation.id} failed during execution: ${step.description}`,\n {\n why: message,\n meta: {\n operationId: operation.id,\n stepDescription: step.description,\n sql: step.sql,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private stepResultIsTrue(rows: readonly Record<string, unknown>[]): boolean {\n if (!rows || rows.length === 0) {\n return false;\n }\n const firstRow = rows[0];\n const firstValue = firstRow ? Object.values(firstRow)[0] : undefined;\n if (typeof firstValue === 'number') {\n return firstValue !== 0;\n }\n if (typeof firstValue === 'boolean') {\n return firstValue;\n }\n if (typeof firstValue === 'string') {\n const lower = firstValue.toLowerCase();\n if (lower === 'true' || lower === '1') return true;\n if (lower === 'false' || lower === '0') return false;\n return firstValue.length > 0;\n }\n return Boolean(firstValue);\n }\n\n private async expectationsAreSatisfied(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n ): Promise<boolean> {\n if (steps.length === 0) {\n return false;\n }\n for (const step of steps) {\n const result = await driver.query(step.sql, step.params ?? []);\n if (!this.stepResultIsTrue(result.rows)) {\n return false;\n }\n }\n return true;\n }\n\n private createSkipRecord(\n operation: SqlMigrationPlanOperation<SqlitePlanTargetDetails>,\n ): SqlMigrationPlanOperation<SqlitePlanTargetDetails> {\n return Object.freeze({\n id: operation.id,\n label: operation.label,\n ...ifDefined('summary', operation.summary),\n operationClass: operation.operationClass,\n target: operation.target,\n precheck: Object.freeze([]),\n execute: Object.freeze([]),\n postcheck: Object.freeze([...operation.postcheck]),\n meta: Object.freeze({\n ...(operation.meta ?? {}),\n runner: Object.freeze({ skipped: true, reason: 'postcheck_pre_satisfied' }),\n }),\n });\n }\n\n private markerMatchesDestination(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['plan'],\n ): boolean {\n if (!marker) return false;\n if (marker.storageHash !== plan.destination.storageHash) return false;\n if (plan.destination.profileHash && marker.profileHash !== plan.destination.profileHash) {\n return false;\n }\n return true;\n }\n\n private enforcePolicyCompatibility(\n policy: MigrationOperationPolicy,\n operations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[],\n ): Result<void, SqlMigrationRunnerFailure> {\n const allowedClasses = new Set(policy.allowedOperationClasses);\n for (const operation of operations) {\n if (!allowedClasses.has(operation.operationClass)) {\n return runnerFailure(\n 'POLICY_VIOLATION',\n `Operation ${operation.id} has class \"${operation.operationClass}\" which is not allowed by policy.`,\n {\n why: `Policy only allows: ${policy.allowedOperationClasses.join(', ')}.`,\n meta: {\n operationId: operation.id,\n operationClass: operation.operationClass,\n allowedClasses: policy.allowedOperationClasses,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private ensureMarkerCompatibility(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['plan'],\n ): Result<void, SqlMigrationRunnerFailure> {\n const origin = plan.origin ?? null;\n if (!origin) {\n return okVoid();\n }\n if (!marker) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Missing contract marker: expected origin storage hash ${origin.storageHash}.`,\n { meta: { expectedOriginStorageHash: origin.storageHash } },\n );\n }\n if (marker.storageHash !== origin.storageHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker (${marker.storageHash}) does not match plan origin (${origin.storageHash}).`,\n {\n meta: {\n markerStorageHash: marker.storageHash,\n expectedOriginStorageHash: origin.storageHash,\n },\n },\n );\n }\n if (origin.profileHash && marker.profileHash !== origin.profileHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker profile hash (${marker.profileHash}) does not match plan origin profile hash (${origin.profileHash}).`,\n {\n meta: {\n markerProfileHash: marker.profileHash,\n expectedOriginProfileHash: origin.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private ensurePlanMatchesDestinationContract(\n destination: SqlMigrationPlanContractInfo,\n contract: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['destinationContract'],\n ): Result<void, SqlMigrationRunnerFailure> {\n if (destination.storageHash !== contract.storage.storageHash) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination storage hash (${destination.storageHash}) does not match provided contract storage hash (${contract.storage.storageHash}).`,\n {\n meta: {\n planStorageHash: destination.storageHash,\n contractStorageHash: contract.storage.storageHash,\n },\n },\n );\n }\n if (\n destination.profileHash &&\n contract.profileHash &&\n destination.profileHash !== contract.profileHash\n ) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination profile hash (${destination.profileHash}) does not match provided contract profile hash (${contract.profileHash}).`,\n {\n meta: {\n planProfileHash: destination.profileHash,\n contractProfileHash: contract.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private async upsertMarker(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n space: string,\n ): Promise<void> {\n // SQLite has no native array type, so we can't merge invariants in SQL\n // the way Postgres does. Merge client-side under the runner's\n // BEGIN EXCLUSIVE — sort + dedupe so the JSON-encoded value is stable.\n const merged = new Set<string>(existingMarker?.invariants ?? []);\n for (const inv of options.plan.providedInvariants) merged.add(inv);\n const invariants = Array.from(merged).sort();\n const writeStatements = buildWriteMarkerStatements({\n space,\n storageHash: options.plan.destination.storageHash,\n profileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.storageHash,\n contractJson: options.destinationContract,\n canonicalVersion: null,\n meta: {},\n invariants,\n });\n const statement = existingMarker ? writeStatements.update : writeStatements.insert;\n await this.executeStatement(driver, statement);\n }\n\n private async recordLedgerEntry(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n executedOperations: readonly SqlMigrationPlanOperation<SqlitePlanTargetDetails>[],\n ): Promise<void> {\n const ledgerStatement = buildLedgerInsertStatement({\n originStorageHash: existingMarker?.storageHash ?? null,\n originProfileHash: existingMarker?.profileHash ?? null,\n destinationStorageHash: options.plan.destination.storageHash,\n destinationProfileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.storageHash,\n contractJsonBefore: existingMarker?.contractJson ?? null,\n contractJsonAfter: options.destinationContract,\n operations: executedOperations,\n });\n await this.executeStatement(driver, ledgerStatement);\n }\n\n private async beginExclusiveTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('BEGIN EXCLUSIVE');\n }\n\n private async commitTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('COMMIT');\n }\n\n private async rollbackTransaction(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('ROLLBACK');\n }\n\n private async executeStatement(\n driver: SqlMigrationRunnerExecuteOptions<SqlitePlanTargetDetails>['driver'],\n statement: SqlStatement,\n ): Promise<void> {\n if (statement.params.length > 0) {\n await driver.query(statement.sql, statement.params);\n return;\n }\n await driver.query(statement.sql);\n }\n}\n","import type { ColumnDefault, Contract } from '@prisma-next/contract/types';\nimport type {\n SqlControlFamilyInstance,\n SqlControlTargetDescriptor,\n} from '@prisma-next/family-sql/control';\nimport { contractToSchemaIR } from '@prisma-next/family-sql/control';\nimport type {\n ControlTargetInstance,\n MigrationPlanner,\n MigrationRunner,\n} from '@prisma-next/framework-components/control';\nimport type { SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';\nimport { sqliteTargetDescriptorMeta } from './descriptor-meta';\nimport { createSqliteMigrationPlanner } from './migrations/planner';\nimport { renderDefaultLiteral } from './migrations/planner-ddl-builders';\nimport type { SqlitePlanTargetDetails } from './migrations/planner-target-details';\nimport { createSqliteMigrationRunner } from './migrations/runner';\n\nfunction sqliteRenderDefault(def: ColumnDefault, _column: StorageColumn): string {\n if (def.kind === 'function') {\n if (def.expression === 'now()') {\n return \"datetime('now')\";\n }\n return def.expression;\n }\n return renderDefaultLiteral(def.value);\n}\n\nconst sqliteControlTargetDescriptor: SqlControlTargetDescriptor<'sqlite', SqlitePlanTargetDetails> =\n {\n ...sqliteTargetDescriptorMeta,\n migrations: {\n createPlanner(_family: SqlControlFamilyInstance): MigrationPlanner<'sql', 'sqlite'> {\n return createSqliteMigrationPlanner();\n },\n createRunner(family) {\n return createSqliteMigrationRunner(family) as MigrationRunner<'sql', 'sqlite'>;\n },\n contractToSchema(contract, _frameworkComponents) {\n return contractToSchemaIR(contract as Contract<SqlStorage> | null, {\n annotationNamespace: 'sqlite',\n renderDefault: sqliteRenderDefault,\n });\n },\n },\n create(): ControlTargetInstance<'sql', 'sqlite'> {\n return {\n familyId: 'sql',\n targetId: 'sqlite',\n };\n },\n createPlanner(_family: SqlControlFamilyInstance) {\n return createSqliteMigrationPlanner();\n },\n createRunner(family) {\n return createSqliteMigrationRunner(family);\n },\n };\n\nexport default sqliteControlTargetDescriptor;\n"],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ //#region src/core/default-normalizer.ts
2
+ const NULL_PATTERN = /^NULL$/i;
3
+ const INTEGER_PATTERN = /^-?\d+$/;
4
+ const REAL_PATTERN = /^-?\d+\.\d+(?:[eE][+-]?\d+)?$/;
5
+ const HEX_PATTERN = /^0[xX][\dA-Fa-f]+$/;
6
+ const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'$/;
7
+ function isNumericLiteral(value) {
8
+ return INTEGER_PATTERN.test(value) || REAL_PATTERN.test(value) || HEX_PATTERN.test(value);
9
+ }
10
+ /**
11
+ * Strips a single matched wrapping pair of outer parens from `s`. Conservative:
12
+ * only strips when the leading `(` is matched by the trailing `)` (so
13
+ * `(a) + (b)` is returned unchanged). Mirrors SQLite's own
14
+ * `pragma_table_info.dflt_value` normalization for expression defaults, and
15
+ * is shared with the recreate-table postcheck builder so both sides agree
16
+ * on the canonical form.
17
+ */
18
+ function stripOuterParens(s) {
19
+ if (!s.startsWith("(") || !s.endsWith(")")) return s;
20
+ let depth = 0;
21
+ for (let i = 0; i < s.length; i++) if (s[i] === "(") depth += 1;
22
+ else if (s[i] === ")") {
23
+ depth -= 1;
24
+ if (depth === 0 && i < s.length - 1) return s;
25
+ }
26
+ return s.slice(1, -1);
27
+ }
28
+ function parseSqliteDefault(rawDefault, nativeType) {
29
+ let trimmed = rawDefault.trim();
30
+ while (true) {
31
+ const stripped = stripOuterParens(trimmed).trim();
32
+ if (stripped === trimmed) break;
33
+ trimmed = stripped;
34
+ }
35
+ const lower = trimmed.toLowerCase();
36
+ if (lower === "current_timestamp" || lower === "datetime('now')" || lower === "datetime(\"now\")") return {
37
+ kind: "function",
38
+ expression: "now()"
39
+ };
40
+ if (NULL_PATTERN.test(trimmed)) return {
41
+ kind: "literal",
42
+ value: null
43
+ };
44
+ if (isNumericLiteral(trimmed)) {
45
+ const num = Number(trimmed);
46
+ if (!Number.isFinite(num)) return void 0;
47
+ if (nativeType?.toLowerCase() === "integer" && !Number.isSafeInteger(num)) return {
48
+ kind: "literal",
49
+ value: trimmed
50
+ };
51
+ return {
52
+ kind: "literal",
53
+ value: num
54
+ };
55
+ }
56
+ const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);
57
+ if (stringMatch?.[1] !== void 0) return {
58
+ kind: "literal",
59
+ value: stringMatch[1].replace(/''/g, "'")
60
+ };
61
+ return {
62
+ kind: "function",
63
+ expression: trimmed
64
+ };
65
+ }
66
+ //#endregion
67
+ export { stripOuterParens as n, parseSqliteDefault as t };
68
+
69
+ //# sourceMappingURL=default-normalizer-3Fccw7yw.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-normalizer-3Fccw7yw.mjs","names":[],"sources":["../src/core/default-normalizer.ts"],"sourcesContent":["/**\n * Normalizes SQLite's stored default expressions back into the\n * `ColumnDefault` shape the verifier compares against. Lives target-side\n * (mirroring Postgres's `target-postgres/src/core/default-normalizer.ts`)\n * so both the control adapter (`SqliteControlAdapter.introspect`) and the\n * planner / runner schema-verify path can consume it without\n * `target-sqlite` reaching into `adapter-sqlite`.\n */\n\nimport type { ColumnDefault } from '@prisma-next/contract/types';\n\nconst NULL_PATTERN = /^NULL$/i;\nconst INTEGER_PATTERN = /^-?\\d+$/;\nconst REAL_PATTERN = /^-?\\d+\\.\\d+(?:[eE][+-]?\\d+)?$/;\nconst HEX_PATTERN = /^0[xX][\\dA-Fa-f]+$/;\nconst STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'$/;\n\nfunction isNumericLiteral(value: string): boolean {\n return INTEGER_PATTERN.test(value) || REAL_PATTERN.test(value) || HEX_PATTERN.test(value);\n}\n\n/**\n * Strips a single matched wrapping pair of outer parens from `s`. Conservative:\n * only strips when the leading `(` is matched by the trailing `)` (so\n * `(a) + (b)` is returned unchanged). Mirrors SQLite's own\n * `pragma_table_info.dflt_value` normalization for expression defaults, and\n * is shared with the recreate-table postcheck builder so both sides agree\n * on the canonical form.\n */\nexport function stripOuterParens(s: string): string {\n if (!s.startsWith('(') || !s.endsWith(')')) return s;\n let depth = 0;\n for (let i = 0; i < s.length; i++) {\n if (s[i] === '(') depth += 1;\n else if (s[i] === ')') {\n depth -= 1;\n if (depth === 0 && i < s.length - 1) return s;\n }\n }\n return s.slice(1, -1);\n}\n\nexport function parseSqliteDefault(\n rawDefault: string,\n nativeType?: string,\n): ColumnDefault | undefined {\n let trimmed = rawDefault.trim();\n\n // Strip outer parentheses that SQLite adds around expressions. Iterate to\n // fixpoint so accidental double-wrapping (e.g. `((expr))`) collapses too.\n while (true) {\n const stripped = stripOuterParens(trimmed).trim();\n if (stripped === trimmed) break;\n trimmed = stripped;\n }\n\n // SQLite has several spellings for \"current timestamp\" — `CURRENT_TIMESTAMP`\n // (keyword) and `datetime('now')` / `datetime(\"now\")` (function call). The\n // contract authoring side canonicalizes `dbgenerated(\"CURRENT_TIMESTAMP\")`\n // (and friends) to `now()` via `lowerDbgenerated`; mirror that here so a\n // schema produced by either spelling round-trips to the same canonical\n // form for verification.\n const lower = trimmed.toLowerCase();\n if (lower === 'current_timestamp' || lower === \"datetime('now')\" || lower === 'datetime(\"now\")') {\n return { kind: 'function', expression: 'now()' };\n }\n\n if (NULL_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: null };\n }\n\n // SQLite integers are 64-bit, so values outside the JS safe-integer range can't\n // be faithfully represented as `number`. Mirror `parsePostgresDefault`'s bigint\n // handling: parse as JS `number` when safe, fall back to the raw text otherwise.\n if (isNumericLiteral(trimmed)) {\n const num = Number(trimmed);\n if (!Number.isFinite(num)) return undefined;\n if (nativeType?.toLowerCase() === 'integer' && !Number.isSafeInteger(num)) {\n return { kind: 'literal', value: trimmed };\n }\n return { kind: 'literal', value: num };\n }\n\n const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);\n if (stringMatch?.[1] !== undefined) {\n const unescaped = stringMatch[1].replace(/''/g, \"'\");\n return { kind: 'literal', value: unescaped };\n }\n\n // Unrecognized expression — preserve as function\n return { kind: 'function', expression: trimmed };\n}\n"],"mappings":";AAWA,MAAM,eAAe;AACrB,MAAM,kBAAkB;AACxB,MAAM,eAAe;AACrB,MAAM,cAAc;AACpB,MAAM,yBAAyB;AAE/B,SAAS,iBAAiB,OAAwB;CAChD,OAAO,gBAAgB,KAAK,MAAM,IAAI,aAAa,KAAK,MAAM,IAAI,YAAY,KAAK,MAAM;;;;;;;;;;AAW3F,SAAgB,iBAAiB,GAAmB;CAClD,IAAI,CAAC,EAAE,WAAW,IAAI,IAAI,CAAC,EAAE,SAAS,IAAI,EAAE,OAAO;CACnD,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAC5B,IAAI,EAAE,OAAO,KAAK,SAAS;MACtB,IAAI,EAAE,OAAO,KAAK;EACrB,SAAS;EACT,IAAI,UAAU,KAAK,IAAI,EAAE,SAAS,GAAG,OAAO;;CAGhD,OAAO,EAAE,MAAM,GAAG,GAAG;;AAGvB,SAAgB,mBACd,YACA,YAC2B;CAC3B,IAAI,UAAU,WAAW,MAAM;CAI/B,OAAO,MAAM;EACX,MAAM,WAAW,iBAAiB,QAAQ,CAAC,MAAM;EACjD,IAAI,aAAa,SAAS;EAC1B,UAAU;;CASZ,MAAM,QAAQ,QAAQ,aAAa;CACnC,IAAI,UAAU,uBAAuB,UAAU,qBAAqB,UAAU,qBAC5E,OAAO;EAAE,MAAM;EAAY,YAAY;EAAS;CAGlD,IAAI,aAAa,KAAK,QAAQ,EAC5B,OAAO;EAAE,MAAM;EAAW,OAAO;EAAM;CAMzC,IAAI,iBAAiB,QAAQ,EAAE;EAC7B,MAAM,MAAM,OAAO,QAAQ;EAC3B,IAAI,CAAC,OAAO,SAAS,IAAI,EAAE,OAAO,KAAA;EAClC,IAAI,YAAY,aAAa,KAAK,aAAa,CAAC,OAAO,cAAc,IAAI,EACvE,OAAO;GAAE,MAAM;GAAW,OAAO;GAAS;EAE5C,OAAO;GAAE,MAAM;GAAW,OAAO;GAAK;;CAGxC,MAAM,cAAc,QAAQ,MAAM,uBAAuB;CACzD,IAAI,cAAc,OAAO,KAAA,GAEvB,OAAO;EAAE,MAAM;EAAW,OADR,YAAY,GAAG,QAAQ,OAAO,IACN;EAAE;CAI9C,OAAO;EAAE,MAAM;EAAY,YAAY;EAAS"}
@@ -0,0 +1,7 @@
1
+ import { ColumnDefault } from "@prisma-next/contract/types";
2
+
3
+ //#region src/core/default-normalizer.d.ts
4
+ declare function parseSqliteDefault(rawDefault: string, nativeType?: string): ColumnDefault | undefined;
5
+ //#endregion
6
+ export { parseSqliteDefault };
7
+ //# sourceMappingURL=default-normalizer.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-normalizer.d.mts","names":[],"sources":["../src/core/default-normalizer.ts"],"mappings":";;;iBA0CgB,kBAAA,CACd,UAAA,UACA,UAAA,YACC,aAAA"}
@@ -0,0 +1,2 @@
1
+ import { t as parseSqliteDefault } from "./default-normalizer-3Fccw7yw.mjs";
2
+ export { parseSqliteDefault };
@@ -0,0 +1,17 @@
1
+ import { temporalAuthoringPresets } from "@prisma-next/family-sql/control";
2
+ const sqliteTargetDescriptorMeta = {
3
+ kind: "target",
4
+ familyId: "sql",
5
+ targetId: "sqlite",
6
+ id: "sqlite",
7
+ version: "0.0.1",
8
+ capabilities: {},
9
+ authoring: { field: { temporal: temporalAuthoringPresets({
10
+ codecId: "sqlite/datetime@1",
11
+ nativeType: "text"
12
+ }) } }
13
+ };
14
+ //#endregion
15
+ export { sqliteTargetDescriptorMeta as t };
16
+
17
+ //# sourceMappingURL=descriptor-meta-CE2Kbn9b.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor-meta-CE2Kbn9b.mjs","names":[],"sources":["../src/core/authoring.ts","../src/core/descriptor-meta.ts"],"sourcesContent":["import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';\nimport type { AuthoringFieldNamespace } from '@prisma-next/framework-components/authoring';\n\nexport const sqliteAuthoringFieldPresets = {\n temporal: temporalAuthoringPresets({\n codecId: 'sqlite/datetime@1',\n nativeType: 'text',\n }),\n} as const satisfies AuthoringFieldNamespace;\n","import type { CodecTypes } from '../exports/codec-types';\nimport { sqliteAuthoringFieldPresets } from './authoring';\n\nconst sqliteTargetDescriptorMetaBase = {\n kind: 'target',\n familyId: 'sql',\n targetId: 'sqlite',\n id: 'sqlite',\n version: '0.0.1',\n capabilities: {},\n authoring: {\n field: sqliteAuthoringFieldPresets,\n },\n} as const;\n\nexport const sqliteTargetDescriptorMeta: typeof sqliteTargetDescriptorMetaBase & {\n readonly __codecTypes?: CodecTypes;\n} = sqliteTargetDescriptorMetaBase;\n"],"mappings":";ACeA,MAAa,6BAET;CAbF,MAAM;CACN,UAAU;CACV,UAAU;CACV,IAAI;CACJ,SAAS;CACT,cAAc,EAAE;CAChB,WAAW,EACT,OAAO,EDPT,UAAU,yBAAyB;EACjC,SAAS;EACT,YAAY;EACb,CAAC,ECIO,EACR;CAKC"}