@prisma-next/family-sql 0.5.0-dev.61 → 0.5.0-dev.63

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.
@@ -20,6 +20,7 @@ import type {
20
20
  VerifyDatabaseSchemaResult,
21
21
  } from '@prisma-next/framework-components/control';
22
22
  import {
23
+ APP_SPACE_ID,
23
24
  SchemaTreeNode,
24
25
  VERIFY_CODE_HASH_MISMATCH,
25
26
  VERIFY_CODE_MARKER_MISSING,
@@ -355,7 +356,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
355
356
  const contractProfileHash = contract.profileHash;
356
357
  const contractTarget = contract.target;
357
358
 
358
- const marker = await getControlAdapter().readMarker(driver);
359
+ const marker = await getControlAdapter().readMarker(driver, APP_SPACE_ID);
359
360
 
360
361
  let missingCodecs: readonly string[] | undefined;
361
362
  let codecCoverageSkipped = false;
@@ -500,7 +501,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
500
501
  await driver.query(ensureSchemaStatement.sql, ensureSchemaStatement.params);
501
502
  await driver.query(ensureTableStatement.sql, ensureTableStatement.params);
502
503
 
503
- const existingMarker = await getControlAdapter().readMarker(driver);
504
+ const existingMarker = await getControlAdapter().readMarker(driver, APP_SPACE_ID);
504
505
 
505
506
  let markerCreated = false;
506
507
  let markerUpdated = false;
@@ -508,6 +509,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
508
509
 
509
510
  if (!existingMarker) {
510
511
  const write = writeContractMarker({
512
+ space: APP_SPACE_ID,
511
513
  storageHash: contractStorageHash,
512
514
  profileHash: contractProfileHash,
513
515
  contractJson: contractInput,
@@ -528,6 +530,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
528
530
  profileHash: existingProfileHash,
529
531
  };
530
532
  const write = writeContractMarker({
533
+ space: APP_SPACE_ID,
531
534
  storageHash: contractStorageHash,
532
535
  profileHash: contractProfileHash,
533
536
  contractJson: contractInput,
@@ -576,8 +579,9 @@ export function createSqlFamilyInstance<TTargetId extends string>(
576
579
  },
577
580
  async readMarker(options: {
578
581
  readonly driver: ControlDriverInstance<'sql', string>;
582
+ readonly space: string;
579
583
  }): Promise<ContractMarkerRecord | null> {
580
- return getControlAdapter().readMarker(options.driver);
584
+ return getControlAdapter().readMarker(options.driver, options.space);
581
585
  },
582
586
  async introspect(options: {
583
587
  readonly driver: ControlDriverInstance<'sql', string>;
@@ -98,6 +98,7 @@ export function createMigrationPlan<TTargetDetails>(
98
98
  ): SqlMigrationPlan<TTargetDetails> {
99
99
  return Object.freeze({
100
100
  targetId: options.targetId,
101
+ spaceId: options.spaceId,
101
102
  ...(options.origin !== undefined
102
103
  ? { origin: options.origin ? Object.freeze({ ...options.origin }) : null }
103
104
  : {}),
@@ -1,6 +1,7 @@
1
1
  import type { Contract } from '@prisma-next/contract/types';
2
2
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
3
3
  import type {
4
+ ContractSpace,
4
5
  ControlAdapterDescriptor,
5
6
  ControlDriverInstance,
6
7
  ControlExtensionDescriptor,
@@ -128,6 +129,20 @@ export interface SqlControlExtensionDescriptor<TTargetId extends string>
128
129
  extends ControlExtensionDescriptor<'sql', TTargetId> {
129
130
  readonly databaseDependencies?: ComponentDatabaseDependencies<unknown>;
130
131
  readonly queryOperations?: () => ReadonlyArray<SqlOperationDescriptor>;
132
+ /**
133
+ * Schema-contributing extensions opt into the per-space planner / runner /
134
+ * verifier by setting this field. Extensions without it are codec-only or
135
+ * query-ops-only — today's behaviour preserved.
136
+ *
137
+ * The shape comes from `@prisma-next/framework-components/control`
138
+ * (`ContractSpace`) — contract-space identity is a framework concept,
139
+ * not a SQL-specific one. The SQL family specialises the generic to
140
+ * `Contract<SqlStorage>` so descriptor authors continue to see a
141
+ * typed contract value.
142
+ *
143
+ * @see specs/framework-mechanism.spec.md § 1.
144
+ */
145
+ readonly contractSpace?: ContractSpace<Contract<SqlStorage>>;
131
146
  }
132
147
 
133
148
  export interface SqlControlAdapterDescriptor<TTargetId extends string>
@@ -182,6 +197,21 @@ export interface SqlMigrationPlanContractInfo {
182
197
  }
183
198
 
184
199
  export interface SqlMigrationPlan<TTargetDetails> extends MigrationPlan {
200
+ /**
201
+ * Contract space this plan applies to. The runner uses this to key the
202
+ * `prisma_contract.marker` row it writes/reads (`space = <spaceId>`),
203
+ * so per-extension plans hit per-extension marker rows instead of all
204
+ * collapsing onto the app's row.
205
+ *
206
+ * App-plan callers pass `APP_SPACE_ID` (`'app'`); per-extension plans
207
+ * pass the extension's space id. Required at every call site so the
208
+ * type system surfaces every place that needs to thread the value
209
+ * (rather than letting an `?? APP_SPACE_ID` fall-through silently
210
+ * collapse multi-space markers onto the `'app'` row).
211
+ *
212
+ * @see specs/framework-mechanism.spec.md § 2.
213
+ */
214
+ readonly spaceId: string;
185
215
  /**
186
216
  * Origin contract identity that the plan expects the database to currently be at.
187
217
  * If omitted or null, the runner skips origin validation entirely.
@@ -246,6 +276,14 @@ export interface SqlMigrationPlannerPlanOptions {
246
276
  readonly schema: SqlSchemaIR;
247
277
  readonly policy: MigrationOperationPolicy;
248
278
  readonly schemaName?: string;
279
+ /**
280
+ * Contract space the plan applies to. The planner stamps this onto
281
+ * the produced {@link SqlMigrationPlan.spaceId} so the runner keys
282
+ * the marker row by the right space. App-plan callers pass
283
+ * `APP_SPACE_ID`; per-extension callers pass the extension's space
284
+ * id.
285
+ */
286
+ readonly spaceId: string;
249
287
  /**
250
288
  * The "from" contract (state the planner assumes the database starts at),
251
289
  * or `null` for reconciliation flows that have no prior contract.
@@ -311,6 +349,7 @@ export interface SqlMigrationRunnerExecuteOptions<TTargetDetails> {
311
349
 
312
350
  export type SqlMigrationRunnerErrorCode =
313
351
  | 'DESTINATION_CONTRACT_MISMATCH'
352
+ | 'LEGACY_MARKER_SHAPE'
314
353
  | 'MARKER_ORIGIN_MISMATCH'
315
354
  | 'POLICY_VIOLATION'
316
355
  | 'PRECHECK_FAILED'
@@ -346,6 +385,10 @@ export interface SqlControlTargetDescriptor<TTargetId extends string, TTargetDet
346
385
 
347
386
  export interface CreateSqlMigrationPlanOptions<TTargetDetails> {
348
387
  readonly targetId: string;
388
+ /**
389
+ * Contract space this plan applies to. Mirrors {@link SqlMigrationPlan.spaceId}.
390
+ */
391
+ readonly spaceId: string;
349
392
  readonly origin?: SqlMigrationPlanContractInfo | null;
350
393
  readonly destination: SqlMigrationPlanContractInfo;
351
394
  readonly operations: readonly SqlMigrationPlanOperation<TTargetDetails>[];