@prisma-next/sql-contract-psl 0.12.0-dev.60 → 0.12.0-dev.62
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/index.d.mts +10 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{interpreter-1VmrYYbi.mjs → interpreter-B5_yovSP.mjs} +23 -3
- package/dist/interpreter-B5_yovSP.mjs.map +1 -0
- package/dist/provider.mjs +2 -1
- package/dist/provider.mjs.map +1 -1
- package/package.json +12 -12
- package/src/interpreter.ts +45 -9
- package/src/provider.ts +1 -0
- package/dist/interpreter-1VmrYYbi.mjs.map +0 -1
package/dist/provider.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as interpretPslDocumentToSqlContract } from "./interpreter-
|
|
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)
|
package/dist/provider.mjs.map
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "0.12.0-dev.62",
|
|
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.
|
|
10
|
-
"@prisma-next/contract": "0.12.0-dev.
|
|
11
|
-
"@prisma-next/framework-components": "0.12.0-dev.
|
|
12
|
-
"@prisma-next/psl-parser": "0.12.0-dev.
|
|
13
|
-
"@prisma-next/sql-contract": "0.12.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract-ts": "0.12.0-dev.
|
|
15
|
-
"@prisma-next/utils": "0.12.0-dev.
|
|
9
|
+
"@prisma-next/config": "0.12.0-dev.62",
|
|
10
|
+
"@prisma-next/contract": "0.12.0-dev.62",
|
|
11
|
+
"@prisma-next/framework-components": "0.12.0-dev.62",
|
|
12
|
+
"@prisma-next/psl-parser": "0.12.0-dev.62",
|
|
13
|
+
"@prisma-next/sql-contract": "0.12.0-dev.62",
|
|
14
|
+
"@prisma-next/sql-contract-ts": "0.12.0-dev.62",
|
|
15
|
+
"@prisma-next/utils": "0.12.0-dev.62",
|
|
16
16
|
"pathe": "^2.0.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@prisma-next/contract-authoring": "0.12.0-dev.
|
|
20
|
-
"@prisma-next/test-utils": "0.12.0-dev.
|
|
21
|
-
"@prisma-next/tsconfig": "0.12.0-dev.
|
|
22
|
-
"@prisma-next/tsdown": "0.12.0-dev.
|
|
19
|
+
"@prisma-next/contract-authoring": "0.12.0-dev.62",
|
|
20
|
+
"@prisma-next/test-utils": "0.12.0-dev.62",
|
|
21
|
+
"@prisma-next/tsconfig": "0.12.0-dev.62",
|
|
22
|
+
"@prisma-next/tsdown": "0.12.0-dev.62",
|
|
23
23
|
"arktype": "^2.2.0",
|
|
24
24
|
"tsdown": "0.22.1",
|
|
25
25
|
"typescript": "5.9.3",
|
package/src/interpreter.ts
CHANGED
|
@@ -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
|
|
993
|
-
|
|
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:
|
|
1080
|
-
//
|
|
1081
|
-
//
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
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
|