@prisma-next/sql-contract-psl 0.12.0-dev.60 → 0.12.0-dev.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/provider.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as interpretPslDocumentToSqlContract } from "./interpreter-1VmrYYbi.mjs";
1
+ import { t as interpretPslDocumentToSqlContract } from "./interpreter-B5_yovSP.mjs";
2
2
  import { ifDefined } from "@prisma-next/utils/defined";
3
3
  import { notOk, ok } from "@prisma-next/utils/result";
4
4
  import { parsePslDocument } from "@prisma-next/psl-parser";
@@ -69,6 +69,7 @@ function prismaContract(schemaPath, options) {
69
69
  authoringContributions: context.authoringContributions,
70
70
  scalarTypeDescriptors,
71
71
  ...ifDefined("composedExtensionPacks", context.composedExtensionPacks.length > 0 ? [...context.composedExtensionPacks] : void 0),
72
+ composedExtensionContracts: context.composedExtensionContracts,
72
73
  ...ifDefined("composedExtensionPackRefs", options.composedExtensionPackRefs?.length ? options.composedExtensionPackRefs : void 0),
73
74
  controlMutationDefaults: context.controlMutationDefaults,
74
75
  ...ifDefined("createNamespace", options.createNamespace)
@@ -1 +1 @@
1
- {"version":3,"file":"provider.mjs","names":[],"sources":["../src/provider.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { ContractConfig } from '@prisma-next/config/config-types';\nimport { applySpecifierDefaultControlPolicy } from '@prisma-next/contract/apply-specifier-default-control-policy';\nimport type { ControlPolicy } from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';\nimport type { Namespace } from '@prisma-next/framework-components/ir';\nimport { parsePslDocument } from '@prisma-next/psl-parser';\nimport type { SqlNamespaceTablesInput } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { basename, extname } from 'pathe';\nimport { interpretPslDocumentToSqlContract } from './interpreter';\nimport type { ColumnDescriptor } from './psl-column-resolution';\n\nexport interface PrismaContractOptions {\n readonly output?: string;\n readonly target: TargetPackRef<'sql', string>;\n readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql', string>[];\n readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;\n readonly defaultControlPolicy?: ControlPolicy;\n}\n\n/**\n * Derives the emit output path from the schema input path so artefacts land\n * colocated with the source (e.g. `src/contract/schema.prisma` →\n * `src/contract/contract.json`). The provider owns this because it is the\n * only layer that knows the input path; the upstream `normalizeContractConfig`\n * default is a last-resort fallback for providers that don't carry one.\n */\nfunction defaultOutputFromSchemaPath(schemaPath: string): string {\n const ext = extname(schemaPath);\n if (ext.length === 0) return `${schemaPath}.json`;\n const base = schemaPath.slice(0, -ext.length);\n // PSL schemas commonly use `schema.prisma`; the emitted JSON is called\n // `contract.json` to mirror the rest of the toolchain, not `schema.json`.\n // Match only the exact basename `schema` so files like `my-schema.prisma`\n // are not silently rewritten to `my-contract.json`.\n if (basename(base) === 'schema') {\n return `${base.slice(0, -'schema'.length)}contract.json`;\n }\n return `${base}.json`;\n}\n\nfunction buildColumnDescriptorMap(\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n codecLookup: CodecLookup,\n): ReadonlyMap<string, ColumnDescriptor> {\n const result = new Map<string, ColumnDescriptor>();\n for (const [typeName, codecId] of scalarTypeDescriptors) {\n const nativeType = codecLookup.targetTypesFor(codecId)?.[0];\n if (nativeType === undefined) continue;\n result.set(typeName, { codecId, nativeType });\n }\n return result;\n}\n\nexport function prismaContract(schemaPath: string, options: PrismaContractOptions): ContractConfig {\n return {\n source: {\n inputs: [schemaPath],\n load: async (context) => {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n 'prismaContract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.',\n );\n }\n let schema: string;\n try {\n schema = await readFile(absoluteSchemaPath, 'utf-8');\n } catch (error) {\n const message = String(error);\n return notOk({\n summary: `Failed to read Prisma schema at \"${schemaPath}\"`,\n diagnostics: [\n {\n code: 'PSL_SCHEMA_READ_FAILED',\n message,\n sourceId: schemaPath,\n },\n ],\n meta: { schemaPath, absoluteSchemaPath, cause: message },\n });\n }\n\n const document = parsePslDocument({\n schema,\n sourceId: schemaPath,\n });\n\n const scalarTypeDescriptors = buildColumnDescriptorMap(\n context.scalarTypeDescriptors,\n context.codecLookup,\n );\n\n const interpreted = interpretPslDocumentToSqlContract({\n document,\n target: options.target,\n authoringContributions: context.authoringContributions,\n scalarTypeDescriptors,\n ...ifDefined(\n 'composedExtensionPacks',\n context.composedExtensionPacks.length > 0\n ? [...context.composedExtensionPacks]\n : undefined,\n ),\n ...ifDefined(\n 'composedExtensionPackRefs',\n options.composedExtensionPackRefs?.length\n ? options.composedExtensionPackRefs\n : undefined,\n ),\n controlMutationDefaults: context.controlMutationDefaults,\n ...ifDefined('createNamespace', options.createNamespace),\n });\n if (!interpreted.ok) {\n return interpreted;\n }\n\n return ok(\n applySpecifierDefaultControlPolicy(interpreted.value, options.defaultControlPolicy),\n );\n },\n },\n output: options.output ?? defaultOutputFromSchemaPath(schemaPath),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAAS,4BAA4B,YAA4B;CAC/D,MAAM,MAAM,QAAQ,UAAU;CAC9B,IAAI,IAAI,WAAW,GAAG,OAAO,GAAG,WAAW;CAC3C,MAAM,OAAO,WAAW,MAAM,GAAG,CAAC,IAAI,MAAM;CAK5C,IAAI,SAAS,IAAI,MAAM,UACrB,OAAO,GAAG,KAAK,MAAM,GAAG,EAAgB,EAAE;CAE5C,OAAO,GAAG,KAAK;AACjB;AAEA,SAAS,yBACP,uBACA,aACuC;CACvC,MAAM,yBAAS,IAAI,IAA8B;CACjD,KAAK,MAAM,CAAC,UAAU,YAAY,uBAAuB;EACvD,MAAM,aAAa,YAAY,eAAe,OAAO,CAAC,GAAG;EACzD,IAAI,eAAe,KAAA,GAAW;EAC9B,OAAO,IAAI,UAAU;GAAE;GAAS;EAAW,CAAC;CAC9C;CACA,OAAO;AACT;AAEA,SAAgB,eAAe,YAAoB,SAAgD;CACjG,OAAO;EACL,QAAQ;GACN,QAAQ,CAAC,UAAU;GACnB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,sBAAsB,QAAQ;IACrC,IAAI,uBAAuB,KAAA,GACzB,MAAM,IAAI,MACR,kIACF;IAEF,IAAI;IACJ,IAAI;KACF,SAAS,MAAM,SAAS,oBAAoB,OAAO;IACrD,SAAS,OAAO;KACd,MAAM,UAAU,OAAO,KAAK;KAC5B,OAAO,MAAM;MACX,SAAS,oCAAoC,WAAW;MACxD,aAAa,CACX;OACE,MAAM;OACN;OACA,UAAU;MACZ,CACF;MACA,MAAM;OAAE;OAAY;OAAoB,OAAO;MAAQ;KACzD,CAAC;IACH;IAEA,MAAM,WAAW,iBAAiB;KAChC;KACA,UAAU;IACZ,CAAC;IAED,MAAM,wBAAwB,yBAC5B,QAAQ,uBACR,QAAQ,WACV;IAEA,MAAM,cAAc,kCAAkC;KACpD;KACA,QAAQ,QAAQ;KAChB,wBAAwB,QAAQ;KAChC;KACA,GAAG,UACD,0BACA,QAAQ,uBAAuB,SAAS,IACpC,CAAC,GAAG,QAAQ,sBAAsB,IAClC,KAAA,CACN;KACA,GAAG,UACD,6BACA,QAAQ,2BAA2B,SAC/B,QAAQ,4BACR,KAAA,CACN;KACA,yBAAyB,QAAQ;KACjC,GAAG,UAAU,mBAAmB,QAAQ,eAAe;IACzD,CAAC;IACD,IAAI,CAAC,YAAY,IACf,OAAO;IAGT,OAAO,GACL,mCAAmC,YAAY,OAAO,QAAQ,oBAAoB,CACpF;GACF;EACF;EACA,QAAQ,QAAQ,UAAU,4BAA4B,UAAU;CAClE;AACF"}
1
+ {"version":3,"file":"provider.mjs","names":[],"sources":["../src/provider.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { ContractConfig } from '@prisma-next/config/config-types';\nimport { applySpecifierDefaultControlPolicy } from '@prisma-next/contract/apply-specifier-default-control-policy';\nimport type { ControlPolicy } from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';\nimport type { Namespace } from '@prisma-next/framework-components/ir';\nimport { parsePslDocument } from '@prisma-next/psl-parser';\nimport type { SqlNamespaceTablesInput } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { basename, extname } from 'pathe';\nimport { interpretPslDocumentToSqlContract } from './interpreter';\nimport type { ColumnDescriptor } from './psl-column-resolution';\n\nexport interface PrismaContractOptions {\n readonly output?: string;\n readonly target: TargetPackRef<'sql', string>;\n readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql', string>[];\n readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;\n readonly defaultControlPolicy?: ControlPolicy;\n}\n\n/**\n * Derives the emit output path from the schema input path so artefacts land\n * colocated with the source (e.g. `src/contract/schema.prisma` →\n * `src/contract/contract.json`). The provider owns this because it is the\n * only layer that knows the input path; the upstream `normalizeContractConfig`\n * default is a last-resort fallback for providers that don't carry one.\n */\nfunction defaultOutputFromSchemaPath(schemaPath: string): string {\n const ext = extname(schemaPath);\n if (ext.length === 0) return `${schemaPath}.json`;\n const base = schemaPath.slice(0, -ext.length);\n // PSL schemas commonly use `schema.prisma`; the emitted JSON is called\n // `contract.json` to mirror the rest of the toolchain, not `schema.json`.\n // Match only the exact basename `schema` so files like `my-schema.prisma`\n // are not silently rewritten to `my-contract.json`.\n if (basename(base) === 'schema') {\n return `${base.slice(0, -'schema'.length)}contract.json`;\n }\n return `${base}.json`;\n}\n\nfunction buildColumnDescriptorMap(\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n codecLookup: CodecLookup,\n): ReadonlyMap<string, ColumnDescriptor> {\n const result = new Map<string, ColumnDescriptor>();\n for (const [typeName, codecId] of scalarTypeDescriptors) {\n const nativeType = codecLookup.targetTypesFor(codecId)?.[0];\n if (nativeType === undefined) continue;\n result.set(typeName, { codecId, nativeType });\n }\n return result;\n}\n\nexport function prismaContract(schemaPath: string, options: PrismaContractOptions): ContractConfig {\n return {\n source: {\n inputs: [schemaPath],\n load: async (context) => {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n 'prismaContract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.',\n );\n }\n let schema: string;\n try {\n schema = await readFile(absoluteSchemaPath, 'utf-8');\n } catch (error) {\n const message = String(error);\n return notOk({\n summary: `Failed to read Prisma schema at \"${schemaPath}\"`,\n diagnostics: [\n {\n code: 'PSL_SCHEMA_READ_FAILED',\n message,\n sourceId: schemaPath,\n },\n ],\n meta: { schemaPath, absoluteSchemaPath, cause: message },\n });\n }\n\n const document = parsePslDocument({\n schema,\n sourceId: schemaPath,\n });\n\n const scalarTypeDescriptors = buildColumnDescriptorMap(\n context.scalarTypeDescriptors,\n context.codecLookup,\n );\n\n const interpreted = interpretPslDocumentToSqlContract({\n document,\n target: options.target,\n authoringContributions: context.authoringContributions,\n scalarTypeDescriptors,\n ...ifDefined(\n 'composedExtensionPacks',\n context.composedExtensionPacks.length > 0\n ? [...context.composedExtensionPacks]\n : undefined,\n ),\n composedExtensionContracts: context.composedExtensionContracts,\n ...ifDefined(\n 'composedExtensionPackRefs',\n options.composedExtensionPackRefs?.length\n ? options.composedExtensionPackRefs\n : undefined,\n ),\n controlMutationDefaults: context.controlMutationDefaults,\n ...ifDefined('createNamespace', options.createNamespace),\n });\n if (!interpreted.ok) {\n return interpreted;\n }\n\n return ok(\n applySpecifierDefaultControlPolicy(interpreted.value, options.defaultControlPolicy),\n );\n },\n },\n output: options.output ?? defaultOutputFromSchemaPath(schemaPath),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAAS,4BAA4B,YAA4B;CAC/D,MAAM,MAAM,QAAQ,UAAU;CAC9B,IAAI,IAAI,WAAW,GAAG,OAAO,GAAG,WAAW;CAC3C,MAAM,OAAO,WAAW,MAAM,GAAG,CAAC,IAAI,MAAM;CAK5C,IAAI,SAAS,IAAI,MAAM,UACrB,OAAO,GAAG,KAAK,MAAM,GAAG,EAAgB,EAAE;CAE5C,OAAO,GAAG,KAAK;AACjB;AAEA,SAAS,yBACP,uBACA,aACuC;CACvC,MAAM,yBAAS,IAAI,IAA8B;CACjD,KAAK,MAAM,CAAC,UAAU,YAAY,uBAAuB;EACvD,MAAM,aAAa,YAAY,eAAe,OAAO,CAAC,GAAG;EACzD,IAAI,eAAe,KAAA,GAAW;EAC9B,OAAO,IAAI,UAAU;GAAE;GAAS;EAAW,CAAC;CAC9C;CACA,OAAO;AACT;AAEA,SAAgB,eAAe,YAAoB,SAAgD;CACjG,OAAO;EACL,QAAQ;GACN,QAAQ,CAAC,UAAU;GACnB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,sBAAsB,QAAQ;IACrC,IAAI,uBAAuB,KAAA,GACzB,MAAM,IAAI,MACR,kIACF;IAEF,IAAI;IACJ,IAAI;KACF,SAAS,MAAM,SAAS,oBAAoB,OAAO;IACrD,SAAS,OAAO;KACd,MAAM,UAAU,OAAO,KAAK;KAC5B,OAAO,MAAM;MACX,SAAS,oCAAoC,WAAW;MACxD,aAAa,CACX;OACE,MAAM;OACN;OACA,UAAU;MACZ,CACF;MACA,MAAM;OAAE;OAAY;OAAoB,OAAO;MAAQ;KACzD,CAAC;IACH;IAEA,MAAM,WAAW,iBAAiB;KAChC;KACA,UAAU;IACZ,CAAC;IAED,MAAM,wBAAwB,yBAC5B,QAAQ,uBACR,QAAQ,WACV;IAEA,MAAM,cAAc,kCAAkC;KACpD;KACA,QAAQ,QAAQ;KAChB,wBAAwB,QAAQ;KAChC;KACA,GAAG,UACD,0BACA,QAAQ,uBAAuB,SAAS,IACpC,CAAC,GAAG,QAAQ,sBAAsB,IAClC,KAAA,CACN;KACA,4BAA4B,QAAQ;KACpC,GAAG,UACD,6BACA,QAAQ,2BAA2B,SAC/B,QAAQ,4BACR,KAAA,CACN;KACA,yBAAyB,QAAQ;KACjC,GAAG,UAAU,mBAAmB,QAAQ,eAAe;IACzD,CAAC;IACD,IAAI,CAAC,YAAY,IACf,OAAO;IAGT,OAAO,GACL,mCAAmC,YAAY,OAAO,QAAQ,oBAAoB,CACpF;GACF;EACF;EACA,QAAQ,QAAQ,UAAU,4BAA4B,UAAU;CAClE;AACF"}
package/package.json CHANGED
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "name": "@prisma-next/sql-contract-psl",
3
- "version": "0.12.0-dev.60",
3
+ "version": "0.12.0-dev.61",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "PSL-to-SQL ContractIR interpreter for Prisma Next",
8
8
  "dependencies": {
9
- "@prisma-next/config": "0.12.0-dev.60",
10
- "@prisma-next/contract": "0.12.0-dev.60",
11
- "@prisma-next/framework-components": "0.12.0-dev.60",
12
- "@prisma-next/psl-parser": "0.12.0-dev.60",
13
- "@prisma-next/sql-contract": "0.12.0-dev.60",
14
- "@prisma-next/sql-contract-ts": "0.12.0-dev.60",
15
- "@prisma-next/utils": "0.12.0-dev.60",
9
+ "@prisma-next/config": "0.12.0-dev.61",
10
+ "@prisma-next/contract": "0.12.0-dev.61",
11
+ "@prisma-next/framework-components": "0.12.0-dev.61",
12
+ "@prisma-next/psl-parser": "0.12.0-dev.61",
13
+ "@prisma-next/sql-contract": "0.12.0-dev.61",
14
+ "@prisma-next/sql-contract-ts": "0.12.0-dev.61",
15
+ "@prisma-next/utils": "0.12.0-dev.61",
16
16
  "pathe": "^2.0.3"
17
17
  },
18
18
  "devDependencies": {
19
- "@prisma-next/contract-authoring": "0.12.0-dev.60",
20
- "@prisma-next/test-utils": "0.12.0-dev.60",
21
- "@prisma-next/tsconfig": "0.12.0-dev.60",
22
- "@prisma-next/tsdown": "0.12.0-dev.60",
19
+ "@prisma-next/contract-authoring": "0.12.0-dev.61",
20
+ "@prisma-next/test-utils": "0.12.0-dev.61",
21
+ "@prisma-next/tsconfig": "0.12.0-dev.61",
22
+ "@prisma-next/tsdown": "0.12.0-dev.61",
23
23
  "arktype": "^2.2.0",
24
24
  "tsdown": "0.22.1",
25
25
  "typescript": "5.9.3",
@@ -102,6 +102,16 @@ export interface InterpretPslDocumentToSqlContractInput {
102
102
  readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql', string>[];
103
103
  readonly controlMutationDefaults?: ControlMutationDefaults;
104
104
  readonly authoringContributions?: AuthoringContributions;
105
+ /**
106
+ * Extension contracts keyed by space ID. Required for cross-space FK
107
+ * resolution. A composed space must have an entry here; if the space ID
108
+ * appears in `composedExtensionPacks` but is absent from this map, the
109
+ * interpreter emits `PSL_UNKNOWN_CONTRACT_SPACE` and fails fast — there
110
+ * is no silent fallback. If a space's contract is present but the
111
+ * referenced model or namespace is not found in it, the interpreter
112
+ * emits `PSL_UNKNOWN_CROSS_SPACE_TARGET`.
113
+ */
114
+ readonly composedExtensionContracts: ReadonlyMap<string, Contract>;
105
115
  /**
106
116
  * Target-supplied `Namespace` factory threaded into
107
117
  * `buildSqlContractFromDefinition` for the contract's
@@ -589,6 +599,8 @@ interface BuildModelNodeInput {
589
599
  readonly enumTypeDescriptors: Map<string, ColumnDescriptor>;
590
600
  readonly namedTypeDescriptors: Map<string, ColumnDescriptor>;
591
601
  readonly composedExtensions: Set<string>;
602
+ /** Extension contracts keyed by space ID for cross-space FK table-name resolution. */
603
+ readonly composedExtensionContracts: ReadonlyMap<string, Contract>;
592
604
  readonly familyId: string;
593
605
  readonly targetId: string;
594
606
  readonly authoringContributions: AuthoringContributions | undefined;
@@ -989,8 +1001,9 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
989
1001
  // Cross-contract-space relation: the target model lives in a different contract space
990
1002
  // identified by `typeContractSpaceId` (e.g. `supabase:auth.User`).
991
1003
  if (fieldTypeContractSpaceId !== undefined) {
992
- // Fail fast if the space is not in the composed extension packs (AC5 PSL half).
993
- if (!input.composedExtensions.has(fieldTypeContractSpaceId)) {
1004
+ // Fail fast if the space has no entry in composedExtensionContracts (AC5 PSL half).
1005
+ const extContractForSpace = input.composedExtensionContracts.get(fieldTypeContractSpaceId);
1006
+ if (extContractForSpace === undefined) {
994
1007
  diagnostics.push({
995
1008
  code: 'PSL_UNKNOWN_CONTRACT_SPACE',
996
1009
  message: `Relation field "${model.name}.${relationAttribute.field.name}" references contract space "${fieldTypeContractSpaceId}" which is not declared in extensionPacks. Add "${fieldTypeContractSpaceId}" to extensionPacks in prisma-next.config.ts.`,
@@ -1076,13 +1089,33 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
1076
1089
  // no-namespace form is used (e.g. `supabase:User` → AC3).
1077
1090
  const crossTargetNamespaceId = fieldTypeNamespaceId ?? '__unbound__';
1078
1091
 
1079
- // Target table name: the interpreter cannot resolve `User users` because it has no
1080
- // access to the extension contract (only a Set<string> of space names is available).
1081
- // Use `fieldTypeName.toLowerCase()` as a symbolic fallback — the same convention the TS
1082
- // builder uses (`targetModelName.toLowerCase()`) when `targetTableName` is absent.
1083
- // Physical table resolution against the extension contract is deferred to the aggregate
1084
- // stage (M3), which has access to the full extension contract.
1085
- const crossTargetTableName = fieldTypeName.toLowerCase();
1092
+ // Target table name: resolved from the extension contract. The get() check above
1093
+ // guarantees extContractForSpace is defined here; if the model or namespace is not
1094
+ // found in it, emit PSL_UNKNOWN_CROSS_SPACE_TARGET (user typo).
1095
+ const extContract = extContractForSpace;
1096
+ const resolvedTable =
1097
+ extContract.domain.namespaces[crossTargetNamespaceId]?.models[fieldTypeName]?.storage[
1098
+ 'table'
1099
+ ];
1100
+ if (typeof resolvedTable !== 'string') {
1101
+ const availableModels =
1102
+ Object.keys(extContract.domain.namespaces[crossTargetNamespaceId]?.models ?? {}).join(
1103
+ ', ',
1104
+ ) || '(none)';
1105
+ diagnostics.push({
1106
+ code: 'PSL_UNKNOWN_CROSS_SPACE_TARGET',
1107
+ message: `Relation field "${model.name}.${relationAttribute.field.name}" references model "${fieldTypeName}" in namespace "${crossTargetNamespaceId}" of space "${fieldTypeContractSpaceId}", but that model was not found in the extension contract. Available models: ${availableModels}`,
1108
+ sourceId,
1109
+ span: relationAttribute.field.span,
1110
+ data: {
1111
+ space: fieldTypeContractSpaceId,
1112
+ namespace: crossTargetNamespaceId,
1113
+ model: fieldTypeName,
1114
+ },
1115
+ });
1116
+ continue;
1117
+ }
1118
+ const crossTargetTableName = resolvedTable;
1086
1119
 
1087
1120
  foreignKeyNodes.push({
1088
1121
  columns: localColumns,
@@ -1895,6 +1928,8 @@ export function interpretPslDocumentToSqlContract(
1895
1928
  const modelNames = new Set(models.map((model) => model.name));
1896
1929
  const compositeTypeNames = new Set(compositeTypes.map((ct) => ct.name));
1897
1930
  const composedExtensions = new Set(input.composedExtensionPacks ?? []);
1931
+ const composedExtensionContracts: ReadonlyMap<string, Contract> =
1932
+ input.composedExtensionContracts;
1898
1933
  const defaultFunctionRegistry: ControlMutationDefaultRegistry =
1899
1934
  input.controlMutationDefaults?.defaultFunctionRegistry ?? new Map();
1900
1935
  const generatorDescriptors = input.controlMutationDefaults?.generatorDescriptors ?? [];
@@ -1980,6 +2015,7 @@ export function interpretPslDocumentToSqlContract(
1980
2015
  enumTypeDescriptors: allEnumTypeDescriptors,
1981
2016
  namedTypeDescriptors: namedTypeResult.namedTypeDescriptors,
1982
2017
  composedExtensions,
2018
+ composedExtensionContracts,
1983
2019
  familyId: input.target.familyId,
1984
2020
  targetId: input.target.targetId,
1985
2021
  authoringContributions: input.authoringContributions,
package/src/provider.ts CHANGED
@@ -105,6 +105,7 @@ export function prismaContract(schemaPath: string, options: PrismaContractOption
105
105
  ? [...context.composedExtensionPacks]
106
106
  : undefined,
107
107
  ),
108
+ composedExtensionContracts: context.composedExtensionContracts,
108
109
  ...ifDefined(
109
110
  'composedExtensionPackRefs',
110
111
  options.composedExtensionPackRefs?.length