@prisma-idb/family-idb 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/bin/prisma-idb.d.mts +1 -0
- package/dist/bin/prisma-idb.mjs +13 -0
- package/dist/bin/prisma-idb.mjs.map +1 -0
- package/dist/chain-order-CaHXo5jz.mjs +44 -0
- package/dist/chain-order-CaHXo5jz.mjs.map +1 -0
- package/dist/cli-Dlaym_DD.mjs +342 -0
- package/dist/cli-Dlaym_DD.mjs.map +1 -0
- package/dist/contract-space-codegen--gfuyap2.mjs +128 -0
- package/dist/contract-space-codegen--gfuyap2.mjs.map +1 -0
- package/dist/exports/cli.d.mts +26 -0
- package/dist/exports/cli.d.mts.map +1 -0
- package/dist/exports/cli.mjs +2 -0
- package/dist/exports/config-types.d.mts +38 -0
- package/dist/exports/config-types.d.mts.map +1 -0
- package/dist/exports/config-types.mjs +66 -0
- package/dist/exports/config-types.mjs.map +1 -0
- package/dist/exports/contract-psl.d.mts +59 -0
- package/dist/exports/contract-psl.d.mts.map +1 -0
- package/dist/exports/contract-psl.mjs +97 -0
- package/dist/exports/contract-psl.mjs.map +1 -0
- package/dist/exports/contract-ts.d.mts +98 -0
- package/dist/exports/contract-ts.d.mts.map +1 -0
- package/dist/exports/contract-ts.mjs +275 -0
- package/dist/exports/contract-ts.mjs.map +1 -0
- package/dist/exports/control.d.mts +107 -0
- package/dist/exports/control.d.mts.map +1 -0
- package/dist/exports/control.mjs +573 -0
- package/dist/exports/control.mjs.map +1 -0
- package/dist/exports/pack.d.mts +10 -0
- package/dist/exports/pack.d.mts.map +1 -0
- package/dist/exports/pack.mjs +11 -0
- package/dist/exports/pack.mjs.map +1 -0
- package/dist/migration-plan-BWhd8BdV.mjs +330 -0
- package/dist/migration-plan-BWhd8BdV.mjs.map +1 -0
- package/dist/preflight-4jDCNvS0.mjs +119 -0
- package/dist/preflight-4jDCNvS0.mjs.map +1 -0
- package/dist/psl-interpreter-C0suaXu2.d.mts +45 -0
- package/dist/psl-interpreter-C0suaXu2.d.mts.map +1 -0
- package/dist/psl-interpreter-C6Q4okuO.mjs +809 -0
- package/dist/psl-interpreter-C6Q4okuO.mjs.map +1 -0
- package/dist/validate-BLnItEKs.mjs +48 -0
- package/dist/validate-BLnItEKs.mjs.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"psl-interpreter-C6Q4okuO.mjs","names":[],"sources":["../src/core/psl-interpreter.ts"],"sourcesContent":["import type { ContractSourceDiagnostic, ContractSourceDiagnostics } from \"@prisma/orm-framework/config/config-types\";\nimport { computeExecutionHash, computeProfileHash, computeStorageHash } from \"@prisma/orm-framework/contract/hashing\";\nimport type {\n ApplicationDomain,\n Contract,\n ContractField,\n ExecutionMutationDefault,\n} from \"@prisma/orm-framework/contract/types\";\nimport { UNBOUND_DOMAIN_NAMESPACE_ID, crossRef } from \"@prisma/orm-framework/contract/types\";\nimport type { FieldSymbol, ModelSymbol, SymbolTable } from \"@prisma/orm-framework/psl-parser\";\nimport type {\n IdbIndexDefinition,\n IdbModelStorage,\n IdbMutationDefaultGeneratorId,\n IdbReferentialAction,\n IdbStorage,\n IdbStoreDefinition,\n} from \"@prisma-idb/target-idb/pack\";\nimport { notOk, ok } from \"@prisma/orm-framework/utils/result\";\nimport type { Result } from \"@prisma/orm-framework/utils/result\";\nimport { validateContract } from \"./validate\";\n\n/** The one `temporal.*` type-constructor path IDB currently understands. */\nconst TEMPORAL_UPDATED_AT_PATH = [\"temporal\", \"updatedAt\"] as const;\n\n/** Generator id shared by `temporal.updatedAt()`/bare `@updatedAt`/`@default(now())`. */\nconst TIMESTAMP_NOW_GENERATOR_ID: IdbMutationDefaultGeneratorId = \"timestampNow\";\n\n/** Synthetic generator id that just echoes `params.value` — backs `@default(<literal>)`. */\nconst LITERAL_GENERATOR_ID: IdbMutationDefaultGeneratorId = \"literal\";\n\n/** An execution-plane mutation default resolved for one field, pre-`ref` (the store name isn't known yet at field-resolution time). */\ninterface FieldExecutionDefault {\n readonly fieldName: string;\n readonly onCreate?: {\n readonly kind: \"generator\";\n readonly id: IdbMutationDefaultGeneratorId;\n readonly params?: Record<string, unknown>;\n };\n readonly onUpdate?: {\n readonly kind: \"generator\";\n readonly id: IdbMutationDefaultGeneratorId;\n readonly params?: Record<string, unknown>;\n };\n}\n\n/** Parses `@default(...)`'s positional argument as a literal value: `true`/`false`/a number/a quoted string. */\nfunction parseDefaultLiteralValue(raw: string): { readonly value: string | number | boolean } | undefined {\n const t = raw.trim();\n if (t === \"true\") return { value: true };\n if (t === \"false\") return { value: false };\n if (/^-?\\d+(\\.\\d+)?$/.test(t)) return { value: Number(t) };\n const str = parseStringArg(t);\n if (str !== undefined) return { value: str };\n return undefined;\n}\n\n/**\n * `true` if a parsed `@default(<literal>)` value's JS type matches what\n * `codecId` expects (a literal's JS type must match the field's declared\n * type — a string literal on an Int field, or vice versa, is a mismatch).\n * Declared as a function (not a `codecId → JS type` const lookup) since\n * `SCALAR_TO_CODEC_ID` — which every `codecId` here is sourced from — is\n * declared further down this module; a top-level const initializer would hit\n * the temporal dead zone, but a function body only evaluates when called.\n */\nexport function literalValueMatchesCodec(value: string | number | boolean, codecId: string): boolean {\n switch (codecId) {\n case SCALAR_TO_CODEC_ID[\"String\"]:\n return typeof value === \"string\";\n case SCALAR_TO_CODEC_ID[\"Int\"]:\n case SCALAR_TO_CODEC_ID[\"Float\"]:\n case SCALAR_TO_CODEC_ID[\"Decimal\"]:\n return typeof value === \"number\";\n case SCALAR_TO_CODEC_ID[\"Boolean\"]:\n return typeof value === \"boolean\";\n default:\n return false;\n }\n}\n\n/** Parses `@default(...)`'s positional argument as a function call: `name(...)` or bare `name()`. */\nfunction parseDefaultFunctionCall(raw: string): { readonly name: string; readonly arg?: string } | undefined {\n const trimmed = raw.trim();\n const openParen = trimmed.indexOf(\"(\");\n const closeParen = trimmed.lastIndexOf(\")\");\n if (openParen <= 0 || closeParen !== trimmed.length - 1) return undefined;\n const name = trimmed.slice(0, openParen).trim();\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) return undefined;\n const arg = trimmed.slice(openParen + 1, closeParen).trim();\n return arg ? { name, arg } : { name };\n}\n\ntype DefaultFunctionResolution =\n | { readonly ok: true; readonly generatorId: IdbMutationDefaultGeneratorId }\n | { readonly ok: false; readonly reason: \"unknown-function\" | \"invalid-argument\" };\n\n/** Resolves a parsed `@default(...)` function call (excluding `autoincrement()`, handled separately as a storage-plane concern) to a generator id. */\nfunction resolveDefaultFunctionGeneratorId(name: string, arg: string | undefined): DefaultFunctionResolution {\n switch (name) {\n case \"now\":\n return arg === undefined\n ? { ok: true, generatorId: TIMESTAMP_NOW_GENERATOR_ID }\n : { ok: false, reason: \"invalid-argument\" };\n case \"uuid\":\n if (arg === undefined || arg === \"4\") return { ok: true, generatorId: \"uuidv4\" };\n if (arg === \"7\") return { ok: true, generatorId: \"uuidv7\" };\n return { ok: false, reason: \"invalid-argument\" };\n case \"cuid\":\n return arg === undefined ? { ok: true, generatorId: \"cuid2\" } : { ok: false, reason: \"invalid-argument\" };\n default:\n return { ok: false, reason: \"unknown-function\" };\n }\n}\n\n// ── Scalar type → codec ID mapping ────────────────────────────────────────────\n\nexport const SCALAR_TO_CODEC_ID: Record<string, string> = {\n String: \"idb/string@1\",\n Int: \"idb/int32@1\",\n Float: \"idb/double@1\",\n Boolean: \"idb/bool@1\",\n DateTime: \"idb/date@1\",\n BigInt: \"idb/bigint@1\",\n Decimal: \"idb/decimal@1\",\n Json: \"idb/json@1\",\n Bytes: \"idb/bytes@1\",\n};\n\n// ── IDB valid-key codec set ─────────────────────────────────────────────────────\n\n/**\n * Codecs excluded from IndexedDB's \"valid key\" algorithm\n * (https://w3c.github.io/IndexedDB/#key-construct: number, string, Date,\n * buffer source, or Array — nothing else).\n *\n * - `idb/bool@1` — boolean is not, and has never been, a valid IDB key type.\n * - `idb/bigint@1` — bigint round-trips fine as a stored *value* (structured\n * clone supports it), but is explicitly absent from the key-type algorithm.\n * - `idb/json@1` — arbitrary shape (object, array, or primitive); can't be\n * statically guaranteed to be a valid key.\n *\n * Using any of these as a model's `@id`/key throws on every write\n * (`DataError` extracting the primary key). Using one as an index `keyPath`\n * doesn't throw on write — the record is just silently omitted from that\n * index — but throws the first time anyone queries it via `IDBKeyRange`\n * (see ADR 016's Context: `OutboxEvent.synced`, `idb/bool@1`, exactly this).\n */\nconst IDB_INVALID_KEY_CODEC_IDS = new Set([\"idb/bool@1\", \"idb/bigint@1\", \"idb/json@1\"]);\n\n/** `true` if `codecId`'s runtime representation is a valid IndexedDB key. */\nexport function isValidIdbKeyCodec(codecId: string): boolean {\n return !IDB_INVALID_KEY_CODEC_IDS.has(codecId);\n}\n\n// PSL PascalCase referential actions → IDB lowercase\nconst REFERENTIAL_ACTION_MAP: Record<string, IdbReferentialAction> = {\n Cascade: \"cascade\",\n SetNull: \"setNull\",\n SetDefault: \"setDefault\",\n Restrict: \"restrict\",\n NoAction: \"noAction\",\n};\n\n// ── Client contract projection (ADR 012) ───────────────────────────────────────\n\n/**\n * `\"full\"` interprets the schema as-is (today's behavior, unchanged — this is\n * the server-facing shape). `\"client\"` additionally strips anything marked\n * `@idb.exclude`/`@@idb.exclude`, producing the projected client contract.\n *\n * A surviving model's relation (any cardinality, required or optional) to an\n * excluded model is dropped (with a warning), keeping the underlying FK\n * scalar field — the model itself is never excluded as a result (ADR 013;\n * see its §\"Why we don't cascade on requiredness\"). Field-level excludes\n * that entangle with a relation (excluding an FK column, or the relation\n * field itself) remain unsupported and are reported as diagnostics — a\n * different, still out-of-scope case ADR 013 doesn't cover.\n */\nexport type ContractProjection = \"full\" | \"client\";\n\n/**\n * ADR 013 — shared between this file and `contract-builder.ts` (which\n * already imports {@link ContractProjection} from here) so the message\n * format isn't duplicated. Called whenever a surviving model's relation is\n * dropped because its target is excluded — any cardinality, required or\n * not; the model itself is never excluded as a result, only the relation.\n */\nexport function warnDroppedRelation(modelName: string, relationName: string, targetModel: string): void {\n console.warn(\n `[prisma-idb] Dropped relation \"${modelName}.${relationName}\" from the client contract: target model \"${targetModel}\" is excluded (ADR 013).`\n );\n}\n\n// ── Attribute arg helpers ──────────────────────────────────────────────────────\n\ntype AttributeArg = { kind: string; name?: string; value: string };\n\nfunction findPositionalArg(args: readonly AttributeArg[]): string | undefined {\n return args.find((a) => a.kind === \"positional\")?.value;\n}\n\nfunction findNamedArg(args: readonly AttributeArg[], name: string): string | undefined {\n return (args.find((a) => a.kind === \"named\" && a.name === name) as AttributeArg | undefined)?.value;\n}\n\nfunction parseStringArg(raw: string | undefined): string | undefined {\n if (raw === undefined) return undefined;\n const t = raw.trim();\n if ((t.startsWith('\"') && t.endsWith('\"')) || (t.startsWith(\"'\") && t.endsWith(\"'\"))) {\n return t.slice(1, -1);\n }\n return undefined;\n}\n\nfunction parseFieldList(raw: string | undefined): string[] | undefined {\n if (raw === undefined) return undefined;\n const t = raw.trim();\n if (!t.startsWith(\"[\") || !t.endsWith(\"]\")) return undefined;\n const inner = t.slice(1, -1).trim();\n if (inner === \"\") return [];\n return inner\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\nfunction lowerFirst(s: string): string {\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n\n// ── Field helpers ──────────────────────────────────────────────────────────────\n\nfunction hasFieldAttribute(field: FieldSymbol, name: string): boolean {\n return field.attributes.some((a) => a.name === name);\n}\n\nfunction getFieldAttribute(field: FieldSymbol, name: string) {\n return field.attributes.find((a) => a.name === name);\n}\n\nfunction hasModelAttribute(model: ModelSymbol, name: string): boolean {\n return model.attributes.some((a) => a.name === name);\n}\n\nconst IDB_EXCLUDE_ATTR = \"idb.exclude\";\n\n// ── Per-model interpretation result ───────────────────────────────────────────\n\ninterface InterpretedModel {\n readonly modelName: string;\n readonly storeName: string;\n readonly keyPath: string;\n readonly indexes: Record<string, IdbIndexDefinition>;\n readonly fields: Record<string, ContractField>;\n readonly relations: Record<\n string,\n {\n readonly to: ReturnType<typeof crossRef>;\n readonly cardinality: \"1:1\" | \"1:N\" | \"N:1\";\n readonly on: { readonly localFields: readonly string[]; readonly targetFields: readonly string[] };\n }\n >;\n readonly relationsStorage: Record<string, { onDelete?: IdbReferentialAction; onUpdate?: IdbReferentialAction }>;\n /** Literal `@default(...)` values, keyed by field name — feeds `IdbModelStorage.fieldDefaults` (`setDefault`). */\n readonly fieldDefaults: Record<string, string | number | boolean>;\n /** FK-side declarations keyed by targetModelName for back-relation resolution. */\n readonly fksByTarget: ReadonlyMap<string, { fieldName: string; localFields: string[]; targetFields: string[] }>;\n /** Execution-plane defaults resolved from `temporal.updatedAt()`, bare `@updatedAt`, and `@default(...)` — feeds `contract.execution.mutations.defaults`. */\n readonly fieldExecutionDefaults: readonly FieldExecutionDefault[];\n /** `true` when `@default(autoincrement())` was declared on this model's `@id` field — feeds `IdbStoreDefinition.autoIncrement`. */\n readonly autoIncrement: boolean;\n}\n\n// ── Core interpreter ───────────────────────────────────────────────────────────\n\nfunction interpretModel(\n model: ModelSymbol,\n modelNames: ReadonlySet<string>,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n projection: ContractProjection,\n excludedModelNames: ReadonlySet<string>,\n excludedFieldNamesByModel: ReadonlyMap<string, ReadonlySet<string>>\n): InterpretedModel | undefined {\n const modelFields = Object.values(model.fields);\n // Fields marked `@idb.exclude`. Empty (no-op) in \"full\" projection — the\n // attribute only takes effect when projecting the client contract.\n const excludedFieldNames = new Set(\n projection === \"client\" ? modelFields.filter((f) => hasFieldAttribute(f, IDB_EXCLUDE_ATTR)).map((f) => f.name) : []\n );\n // Derive store name from @@map or lowerFirst(modelName)\n const mapAttr = model.attributes.find((a) => a.name === \"map\");\n const storeName = parseStringArg(findPositionalArg(mapAttr?.args ?? [])) ?? lowerFirst(model.name);\n\n // Find the keyPath: @id field-level attribute OR @@id([field]) model-level\n let keyPath: string | undefined;\n let idFieldName: string | undefined;\n\n const idModelAttr = model.attributes.find((a) => a.name === \"id\");\n if (idModelAttr) {\n const fields = parseFieldList(findPositionalArg(idModelAttr.args));\n if (!fields || fields.length === 0) {\n diagnostics.push({\n code: \"IDB_INVALID_ID\",\n message: `Model \"${model.name}\" @@id([…]) is missing a field list.`,\n sourceId,\n span: idModelAttr.span,\n });\n return undefined;\n }\n if (fields.length > 1) {\n diagnostics.push({\n code: \"IDB_NO_COMPOUND_KEY\",\n message: `Model \"${model.name}\" @@id([${fields.join(\", \")}]) declares a compound key. IDB does not support compound primary keys — use a single @id field instead.`,\n sourceId,\n span: idModelAttr.span,\n });\n return undefined;\n }\n idFieldName = fields[0];\n keyPath = fields[0];\n }\n\n const idFields = modelFields.filter((f) => hasFieldAttribute(f, \"id\"));\n if (idFields.length > 1) {\n diagnostics.push({\n code: \"IDB_MULTIPLE_ID_FIELDS\",\n message: `Model \"${model.name}\" declares @id on multiple fields (${idFields.map((f) => f.name).join(\", \")}). Only one @id field is allowed.`,\n sourceId,\n span: model.span,\n });\n return undefined;\n }\n if (idFields.length === 1) {\n if (keyPath !== undefined) {\n diagnostics.push({\n code: \"IDB_INVALID_ID\",\n message: `Model \"${model.name}\" cannot declare both a field-level @id and a model-level @@id.`,\n sourceId,\n span: model.span,\n });\n return undefined;\n }\n idFieldName = idFields[0]!.name;\n keyPath = idFields[0]!.name;\n }\n\n if (keyPath === undefined) {\n diagnostics.push({\n code: \"IDB_MISSING_ID\",\n message: `Model \"${model.name}\" has no @id field. Add @id to exactly one scalar field.`,\n sourceId,\n span: model.span,\n });\n return undefined;\n }\n\n if (excludedFieldNames.has(keyPath)) {\n diagnostics.push({\n code: \"IDB_CANNOT_EXCLUDE_KEY_FIELD\",\n message: `Field \"${model.name}.${keyPath}\" is the model's @id key and cannot be marked @idb.exclude — the client contract needs a primary key for every included model.`,\n sourceId,\n span: model.span,\n });\n return undefined;\n }\n\n // ── Build indexes ────────────────────────────────────────────────────────────\n const indexes: Record<string, IdbIndexDefinition> = {};\n\n // @@index([fields]) model attribute\n for (const attr of model.attributes) {\n if (attr.name !== \"index\" && attr.name !== \"unique\") continue;\n const isUnique = attr.name === \"unique\";\n const fieldListRaw = findPositionalArg(attr.args);\n const fields = parseFieldList(fieldListRaw);\n if (!fields || fields.length === 0) {\n diagnostics.push({\n code: \"IDB_INVALID_INDEX\",\n message: `Model \"${model.name}\" @@${attr.name} is missing a field list.`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n if (fields.length > 1) {\n diagnostics.push({\n code: \"IDB_COMPOUND_INDEX_UNSUPPORTED\",\n message: `Model \"${model.name}\" @@${attr.name}([${fields.join(\", \")}]) declares a compound index. IDB compound indexes are not yet supported — use a single-field index.`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const field = fields[0]!;\n if (excludedFieldNames.has(field)) {\n diagnostics.push({\n code: \"IDB_INDEX_ON_EXCLUDED_FIELD\",\n message: `Model \"${model.name}\" @@${attr.name}([${field}]) references \"${field}\", which is marked @idb.exclude. Remove the index or the exclusion.`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const nameRaw = findNamedArg(attr.args, \"name\") ?? findNamedArg(attr.args, \"map\");\n const indexName = parseStringArg(nameRaw) ?? (isUnique ? `${field}_unique` : field);\n indexes[indexName] = { keyPath: field, unique: isUnique };\n }\n\n // ── Walk fields ──────────────────────────────────────────────────────────────\n const contractFields: Record<string, ContractField> = {};\n const relations: InterpretedModel[\"relations\"] = {};\n const relationsStorage: Record<string, { onDelete?: IdbReferentialAction; onUpdate?: IdbReferentialAction }> = {};\n const fieldDefaults: Record<string, string | number | boolean> = {};\n const fksByTarget = new Map<string, { fieldName: string; localFields: string[]; targetFields: string[] }>();\n const fieldExecutionDefaults: FieldExecutionDefault[] = [];\n let autoIncrement = false;\n\n for (const field of modelFields) {\n // Skip the @id field's optional marker — keyPath fields cannot be nullable in IDB\n if (field.name === idFieldName && field.optional) {\n diagnostics.push({\n code: \"IDB_NULLABLE_ID\",\n message: `Field \"${model.name}.${field.name}\" is marked as @id but is optional (?). The primary key cannot be nullable.`,\n sourceId,\n span: field.span,\n });\n }\n\n // Relation list field (backrelation) — skip for now, resolved in second pass\n if (field.list && modelNames.has(field.typeName)) {\n if (excludedModelNames.has(field.typeName)) {\n // The model itself is never excluded because of a relation (ADR\n // 013) — just drop this backrelation and keep the model.\n warnDroppedRelation(model.name, field.name, field.typeName);\n }\n continue;\n }\n\n // FK-side relation field: non-list, type is a model, has @relation\n const relationAttr = getFieldAttribute(field, \"relation\");\n if (!field.list && modelNames.has(field.typeName) && relationAttr) {\n if (excludedFieldNames.has(field.name)) {\n diagnostics.push({\n code: \"IDB_EXCLUDE_ON_RELATION_FIELD_UNSUPPORTED\",\n message: `Field \"${model.name}.${field.name}\" is a relation field and cannot be marked @idb.exclude directly. Exclude the target model with @@idb.exclude to drop the relation, or exclude a plain scalar field.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n if (excludedModelNames.has(field.typeName)) {\n // Same reasoning as the backrelation case above: drop the relation\n // (required or not), keep the model, keep the FK scalar field (it's\n // processed independently, below, as a plain scalar).\n warnDroppedRelation(model.name, field.name, field.typeName);\n continue;\n }\n const args = relationAttr.args;\n const localFieldsRaw = findNamedArg(args, \"fields\");\n const targetFieldsRaw = findNamedArg(args, \"references\");\n const localFields = parseFieldList(localFieldsRaw);\n const targetFields = parseFieldList(targetFieldsRaw);\n\n if (!localFields || localFields.length === 0 || !targetFields || targetFields.length === 0) {\n diagnostics.push({\n code: \"IDB_INVALID_RELATION\",\n message: `Relation field \"${model.name}.${field.name}\" must declare both fields and references in @relation.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n if (localFields.length !== targetFields.length) {\n diagnostics.push({\n code: \"IDB_INVALID_RELATION\",\n message: `Relation field \"${model.name}.${field.name}\" must have the same number of fields and references.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n\n const excludedLocalField = localFields.find((f) => excludedFieldNames.has(f));\n if (excludedLocalField !== undefined) {\n diagnostics.push({\n code: \"IDB_CANNOT_EXCLUDE_RELATION_FIELD\",\n message: `Field \"${model.name}.${excludedLocalField}\" backs relation \"${model.name}.${field.name}\" and cannot be excluded independently — field-level FK exclusion isn't supported (ADR 013's cascade only covers whole-model @@idb.exclude). Exclude the whole model instead, or remove the exclusion.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n\n const targetExcludedFields = excludedFieldNamesByModel.get(field.typeName);\n const excludedTargetField = targetExcludedFields\n ? targetFields.find((f) => targetExcludedFields.has(f))\n : undefined;\n if (excludedTargetField !== undefined) {\n diagnostics.push({\n code: \"IDB_CANNOT_EXCLUDE_RELATION_FIELD\",\n message: `Field \"${field.typeName}.${excludedTargetField}\" is referenced by relation \"${model.name}.${field.name}\" and cannot be excluded independently — field-level FK exclusion isn't supported (ADR 013's cascade only covers whole-model @@idb.exclude). Exclude the whole model instead, or remove the exclusion.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n\n const onDeleteRaw = findNamedArg(args, \"onDelete\");\n const onDelete = onDeleteRaw ? REFERENTIAL_ACTION_MAP[onDeleteRaw.trim()] : undefined;\n\n if (onDeleteRaw && onDelete === undefined) {\n diagnostics.push({\n code: \"IDB_UNKNOWN_REFERENTIAL_ACTION\",\n message: `Relation field \"${model.name}.${field.name}\" has unknown onDelete value \"${onDeleteRaw}\". Valid values: ${Object.keys(REFERENTIAL_ACTION_MAP).join(\", \")}.`,\n sourceId,\n span: field.span,\n });\n }\n\n const onUpdateRaw = findNamedArg(args, \"onUpdate\");\n const onUpdate = onUpdateRaw ? REFERENTIAL_ACTION_MAP[onUpdateRaw.trim()] : undefined;\n\n if (onUpdateRaw && onUpdate === undefined) {\n diagnostics.push({\n code: \"IDB_UNKNOWN_REFERENTIAL_ACTION\",\n message: `Relation field \"${model.name}.${field.name}\" has unknown onUpdate value \"${onUpdateRaw}\". Valid values: ${Object.keys(REFERENTIAL_ACTION_MAP).join(\", \")}.`,\n sourceId,\n span: field.span,\n });\n }\n\n relations[field.name] = {\n to: crossRef(field.typeName),\n cardinality: \"N:1\",\n on: { localFields, targetFields },\n };\n if (onDelete !== undefined || onUpdate !== undefined) {\n relationsStorage[field.name] = {\n ...(onDelete !== undefined ? { onDelete } : {}),\n ...(onUpdate !== undefined ? { onUpdate } : {}),\n };\n }\n fksByTarget.set(field.typeName, {\n fieldName: field.name,\n localFields,\n targetFields,\n });\n\n // Also create a default index on the FK field(s) if not already indexed\n for (const fkField of localFields) {\n if (!(fkField in indexes)) {\n indexes[fkField] = { keyPath: fkField, unique: false };\n }\n }\n continue;\n }\n\n // Non-model relation field without @relation — not a scalar, skip with error\n if (!field.list && modelNames.has(field.typeName) && !relationAttr) {\n diagnostics.push({\n code: \"IDB_MISSING_RELATION_ATTRIBUTE\",\n message: `Field \"${model.name}.${field.name}\" has model type \"${field.typeName}\" but no @relation attribute. Add @relation(fields: [...], references: [...]).`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n\n // Skip list fields of non-model types (JSON arrays etc. are handled as Json codec)\n if (field.list) {\n // Only model-type lists are backrelations; non-model lists are not supported in IDB.\n continue;\n }\n\n // Scalar field\n if (excludedFieldNames.has(field.name)) {\n if (hasFieldAttribute(field, \"unique\")) {\n diagnostics.push({\n code: \"IDB_INDEX_ON_EXCLUDED_FIELD\",\n message: `Field \"${model.name}.${field.name}\" is marked @unique but also @idb.exclude. Remove the @unique attribute or the exclusion.`,\n sourceId,\n span: field.span,\n });\n }\n // Dropped from the client contract. Its type isn't validated here —\n // a server-only field is free to use a type IDB doesn't support at\n // all, since the client interpreter never needs to represent it.\n continue;\n }\n\n // `temporal.updatedAt()` — a namespaced type-constructor call in the type\n // position (no plain type name), shared framework-level PSL grammar\n // (same construct the SQL family requires in place of the removed bare\n // `@updatedAt` attribute). Must be checked before the plain-scalar\n // lookup below: `field.typeName` for a type-constructor field is just\n // the call's last path segment (\"updatedAt\"), not a real scalar type.\n if (field.typeConstructor) {\n const path = field.typeConstructor.path;\n const isTemporalUpdatedAt =\n path.length === TEMPORAL_UPDATED_AT_PATH.length && path.every((p, i) => p === TEMPORAL_UPDATED_AT_PATH[i]);\n\n if (!isTemporalUpdatedAt) {\n diagnostics.push({\n code: \"IDB_UNSUPPORTED_TYPE_CONSTRUCTOR\",\n message: `Field \"${model.name}.${field.name}\" uses unsupported type constructor \"${path.join(\".\")}()\". IDB currently only supports temporal.updatedAt().`,\n sourceId,\n span: field.typeConstructor.span,\n });\n continue;\n }\n if (field.typeConstructor.args.length > 0) {\n diagnostics.push({\n code: \"IDB_TEMPORAL_UPDATED_AT_TAKES_NO_ARGS\",\n message: `Field \"${model.name}.${field.name}\" — temporal.updatedAt() takes no arguments.`,\n sourceId,\n span: field.typeConstructor.span,\n });\n continue;\n }\n if (field.name === idFieldName) {\n diagnostics.push({\n code: \"IDB_TEMPORAL_UPDATED_AT_ON_KEY_FIELD\",\n message: `Field \"${model.name}.${field.name}\" is the model's @id key and cannot be temporal.updatedAt() — an auto-managed timestamp cannot also be the primary key.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n\n contractFields[field.name] = {\n nullable: field.optional,\n type: { kind: \"scalar\", codecId: SCALAR_TO_CODEC_ID[\"DateTime\"]! },\n };\n fieldExecutionDefaults.push({\n fieldName: field.name,\n onCreate: { kind: \"generator\", id: TIMESTAMP_NOW_GENERATOR_ID },\n onUpdate: { kind: \"generator\", id: TIMESTAMP_NOW_GENERATOR_ID },\n });\n continue;\n }\n\n const codecId = SCALAR_TO_CODEC_ID[field.typeName];\n if (codecId === undefined) {\n diagnostics.push({\n code: \"IDB_UNSUPPORTED_FIELD_TYPE\",\n message: `Field \"${model.name}.${field.name}\" has unsupported type \"${field.typeName}\". Supported types: ${Object.keys(SCALAR_TO_CODEC_ID).join(\", \")}.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n\n contractFields[field.name] = {\n nullable: field.optional,\n type: { kind: \"scalar\", codecId },\n };\n\n // `@updatedAt` (classic Prisma spelling) — same runtime semantics as\n // `temporal.updatedAt()` above, just a different PSL surface for the\n // same \"fires on both create and update\" mutation default.\n const updatedAtAttr = getFieldAttribute(field, \"updatedAt\");\n const defaultAttr = getFieldAttribute(field, \"default\");\n\n if (updatedAtAttr && defaultAttr) {\n diagnostics.push({\n code: \"IDB_UPDATED_AT_AND_DEFAULT_CONFLICT\",\n message: `Field \"${model.name}.${field.name}\" cannot combine @updatedAt with @default(...).`,\n sourceId,\n span: defaultAttr.span,\n });\n continue;\n }\n\n if (updatedAtAttr) {\n if (field.name === idFieldName) {\n diagnostics.push({\n code: \"IDB_TEMPORAL_UPDATED_AT_ON_KEY_FIELD\",\n message: `Field \"${model.name}.${field.name}\" is the model's @id key and cannot be @updatedAt — an auto-managed timestamp cannot also be the primary key.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n if (field.optional) {\n diagnostics.push({\n code: \"IDB_EXECUTION_DEFAULT_ON_OPTIONAL_FIELD\",\n message: `Field \"${model.name}.${field.name}\" cannot be both optional and @updatedAt — an omitted value would be ambiguous between \"generate one\" and \"store null\". Remove \"?\" or the attribute.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n if (codecId !== SCALAR_TO_CODEC_ID[\"DateTime\"]) {\n diagnostics.push({\n code: \"IDB_UPDATED_AT_NOT_DATETIME\",\n message: `Field \"${model.name}.${field.name}\" is marked @updatedAt but has type \"${field.typeName}\", not DateTime.`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n fieldExecutionDefaults.push({\n fieldName: field.name,\n onCreate: { kind: \"generator\", id: TIMESTAMP_NOW_GENERATOR_ID },\n onUpdate: { kind: \"generator\", id: TIMESTAMP_NOW_GENERATOR_ID },\n });\n } else if (defaultAttr) {\n const raw = findPositionalArg(defaultAttr.args);\n if (raw === undefined) {\n diagnostics.push({\n code: \"IDB_INVALID_DEFAULT_VALUE\",\n message: `Field \"${model.name}.${field.name}\" @default(...) requires a positional argument.`,\n sourceId,\n span: defaultAttr.span,\n });\n continue;\n }\n\n const literal = parseDefaultLiteralValue(raw);\n if (literal) {\n if (!literalValueMatchesCodec(literal.value, codecId)) {\n diagnostics.push({\n code: \"IDB_INVALID_DEFAULT_VALUE\",\n message: `Field \"${model.name}.${field.name}\" has type \"${field.typeName}\" but @default(${raw}) is a ${typeof literal.value} literal.`,\n sourceId,\n span: defaultAttr.span,\n });\n continue;\n }\n fieldExecutionDefaults.push({\n fieldName: field.name,\n onCreate: { kind: \"generator\", id: LITERAL_GENERATOR_ID, params: { value: literal.value } },\n });\n // Also feeds `IdbModelStorage.fieldDefaults` (setDefault referential\n // action) — only literal defaults land here, never a generator\n // (uuid()/cuid()/now()/autoincrement()), matching Prisma's own rule\n // that `SetDefault` may only target a scalar/literal default.\n fieldDefaults[field.name] = literal.value;\n } else {\n const call = parseDefaultFunctionCall(raw);\n if (!call) {\n diagnostics.push({\n code: \"IDB_INVALID_DEFAULT_VALUE\",\n message: `Field \"${model.name}.${field.name}\" has unsupported default value \"${raw}\".`,\n sourceId,\n span: defaultAttr.span,\n });\n continue;\n }\n\n if (call.name === \"autoincrement\") {\n if (field.name !== idFieldName) {\n diagnostics.push({\n code: \"IDB_AUTOINCREMENT_NOT_ON_KEY_FIELD\",\n message: `Field \"${model.name}.${field.name}\" uses @default(autoincrement()) but is not the model's @id key. IndexedDB only generates keys for the primary key field.`,\n sourceId,\n span: defaultAttr.span,\n });\n continue;\n }\n if (codecId !== SCALAR_TO_CODEC_ID[\"Int\"]) {\n diagnostics.push({\n code: \"IDB_AUTOINCREMENT_NOT_INT\",\n message: `Field \"${model.name}.${field.name}\" uses @default(autoincrement()) but has type \"${field.typeName}\", not Int. IndexedDB key generators only produce numbers.`,\n sourceId,\n span: defaultAttr.span,\n });\n continue;\n }\n autoIncrement = true;\n continue;\n }\n\n if (field.optional) {\n diagnostics.push({\n code: \"IDB_EXECUTION_DEFAULT_ON_OPTIONAL_FIELD\",\n message: `Field \"${model.name}.${field.name}\" cannot be both optional and @default(${call.name}(...)) — an omitted value would be ambiguous between \"generate one\" and \"store null\". Remove \"?\" or the default.`,\n sourceId,\n span: defaultAttr.span,\n });\n continue;\n }\n\n const resolution = resolveDefaultFunctionGeneratorId(call.name, call.arg);\n if (!resolution.ok) {\n diagnostics.push({\n code:\n resolution.reason === \"unknown-function\"\n ? \"IDB_UNKNOWN_DEFAULT_FUNCTION\"\n : \"IDB_INVALID_DEFAULT_FUNCTION_ARGUMENT\",\n message:\n resolution.reason === \"unknown-function\"\n ? `Field \"${model.name}.${field.name}\" uses unsupported default function \"${call.name}(...)\". Supported: now(), uuid(), uuid(7), cuid(), autoincrement().`\n : `Field \"${model.name}.${field.name}\" — @default(${call.name}(${call.arg ?? \"\"})) has an unsupported argument.`,\n sourceId,\n span: defaultAttr.span,\n });\n continue;\n }\n\n fieldExecutionDefaults.push({\n fieldName: field.name,\n onCreate: { kind: \"generator\", id: resolution.generatorId },\n });\n }\n }\n\n // @unique field attribute → unique index\n if (hasFieldAttribute(field, \"unique\")) {\n const existingKey = Object.entries(indexes).find(([, idx]) => idx.keyPath === field.name)?.[0];\n if (!existingKey) {\n indexes[`${field.name}_unique`] = { keyPath: field.name, unique: true };\n }\n }\n }\n\n // ── Validate key/index field types against IDB's valid-key algorithm ───────\n // Only checked when the field itself resolved a codec — a field that\n // already failed IDB_UNSUPPORTED_FIELD_TYPE above shouldn't also get a\n // second, redundant diagnostic here. Every entry `interpretModel` puts into\n // `contractFields` is `kind: \"scalar\"` (see the assignment above) — IDB has\n // no value-object fields — so the narrowing here is just satisfying\n // `ContractField.type`'s shared framework union type.\n const scalarCodecOf = (fieldName: string): string | undefined => {\n const type = contractFields[fieldName]?.type;\n return type?.kind === \"scalar\" ? type.codecId : undefined;\n };\n\n const keyFieldCodec = scalarCodecOf(keyPath);\n if (keyFieldCodec !== undefined && !isValidIdbKeyCodec(keyFieldCodec)) {\n diagnostics.push({\n code: \"IDB_INVALID_KEY_TYPE\",\n message: `Model \"${model.name}\" @id field \"${keyPath}\" has type \"${keyFieldCodec}\", which IndexedDB cannot use as a key. Every write would throw (DataError extracting the primary key). Use String, Int, Float, DateTime, Decimal, or Bytes instead.`,\n sourceId,\n span: modelFields.find((f) => f.name === keyPath)?.span ?? model.span,\n });\n }\n\n for (const [indexName, idx] of Object.entries(indexes)) {\n const fieldCodec = scalarCodecOf(idx.keyPath);\n if (fieldCodec === undefined || isValidIdbKeyCodec(fieldCodec)) continue;\n diagnostics.push({\n code: \"IDB_INVALID_INDEX_KEY_TYPE\",\n message: `Model \"${model.name}\" index \"${indexName}\" is keyed on \"${idx.keyPath}\" (type \"${fieldCodec}\"), which IndexedDB cannot use as an index key. Records are silently omitted from the index on write, and any query against it throws at runtime. Use String, Int, Float, DateTime, Decimal, or Bytes instead.`,\n sourceId,\n span: modelFields.find((f) => f.name === idx.keyPath)?.span ?? model.span,\n });\n }\n\n return {\n modelName: model.name,\n storeName,\n keyPath,\n indexes,\n fields: contractFields,\n relations,\n relationsStorage,\n fieldDefaults,\n fksByTarget,\n fieldExecutionDefaults,\n autoIncrement,\n };\n}\n\n// ── Main export ────────────────────────────────────────────────────────────────\n\n/**\n * Interprets a PSL symbol table (`buildSymbolTable` from `@prisma/orm-toolchain`)\n * and produces an IDB `Contract`.\n *\n * This is the IDB equivalent of `interpretPslDocumentToSqlContract` from the\n * SQL family. It handles IDB-specific constraints:\n *\n * - No namespace blocks (IDB has a single implicit `__unbound__` namespace)\n * - No compound primary keys (IDB `keyPath` must be a single field)\n * - Relations are FK-side (`@relation`) + backrelation list fields\n * - Indexes map directly to `IDBObjectStore.createIndex()` calls\n *\n * `options.projection: \"client\"` additionally strips models/fields marked\n * `@@idb.exclude`/`@idb.exclude`, producing the projected client contract\n * (ADR 012). Call this twice — once per projection — to emit both the full\n * and client `Contract`s from the same schema.\n */\nexport interface InterpretPslOptions {\n /** @default \"full\" */\n readonly projection?: ContractProjection;\n}\n\nexport function interpretPslDocumentToIdbContract(\n table: SymbolTable,\n sourceId: string,\n options?: InterpretPslOptions\n): Result<Contract<IdbStorage>, ContractSourceDiagnostics> {\n const projection: ContractProjection = options?.projection ?? \"full\";\n const diagnostics: ContractSourceDiagnostic[] = [];\n\n // IDB does not support namespace blocks\n const explicitNamespaces = Object.values(table.topLevel.namespaces);\n for (const ns of explicitNamespaces) {\n diagnostics.push({\n code: \"IDB_UNSUPPORTED_NAMESPACE_BLOCK\",\n message: `IDB does not support \\`namespace ${ns.name} { … }\\` blocks. All models must be declared at the top level.`,\n sourceId,\n span: ns.span,\n });\n }\n\n const allModelsUnprojected = [\n ...Object.values(table.topLevel.models),\n ...explicitNamespaces.flatMap((ns) => Object.values(ns.models)),\n ];\n // Full set, including excluded models — needed so field-type checks below\n // still recognize a reference to an excluded model as \"a relation\", not an\n // unsupported scalar type.\n const modelNames = new Set(allModelsUnprojected.map((m) => m.name));\n\n // Models marked `@@idb.exclude`. Empty (no-op) in \"full\" projection. This\n // is the *only* way a model ends up excluded — relations never add to this\n // set (ADR 013 §\"Why we don't cascade on requiredness\"); a surviving\n // model's relation into this set is dropped, not cascaded.\n const excludedModelNames = new Set(\n projection === \"client\"\n ? allModelsUnprojected.filter((m) => hasModelAttribute(m, IDB_EXCLUDE_ATTR)).map((m) => m.name)\n : []\n );\n\n // The models actually interpreted — excluded models are dropped entirely\n // in \"client\" projection, never reaching `interpretModel`.\n const allModels =\n projection === \"client\"\n ? allModelsUnprojected.filter((m) => !excludedModelNames.has(m.name))\n : allModelsUnprojected;\n\n // Field-level exclusions, keyed by model name, so a relation's `references:`\n // fields can be checked against the *target* model's exclusions (a model\n // may not itself be excluded but still have an excluded field a relation\n // points at).\n const excludedFieldNamesByModel = new Map<string, ReadonlySet<string>>(\n projection === \"client\"\n ? allModelsUnprojected.map((m) => [\n m.name,\n new Set(\n Object.values(m.fields)\n .filter((f) => hasFieldAttribute(f, IDB_EXCLUDE_ATTR))\n .map((f) => f.name)\n ),\n ])\n : []\n );\n\n const interpretedByName = new Map<string, InterpretedModel>();\n\n // First pass: interpret each model individually\n for (const model of allModels) {\n const result = interpretModel(\n model,\n modelNames,\n sourceId,\n diagnostics,\n projection,\n excludedModelNames,\n excludedFieldNamesByModel\n );\n if (result) {\n interpretedByName.set(model.name, result);\n }\n }\n\n // Second pass: resolve backrelation list fields\n for (const model of allModels) {\n const interp = interpretedByName.get(model.name);\n if (!interp) continue;\n\n for (const field of Object.values(model.fields)) {\n if (!field.list || !modelNames.has(field.typeName)) continue;\n // Already warned about and dropped by the first pass — don't also\n // report it as an unresolved backrelation.\n if (excludedModelNames.has(field.typeName)) continue;\n\n const targetInterp = interpretedByName.get(field.typeName);\n if (!targetInterp) continue;\n\n // Find the FK in the target model that points back to this model\n const fk = targetInterp.fksByTarget.get(model.name);\n if (!fk) {\n diagnostics.push({\n code: \"IDB_UNRESOLVED_BACKRELATION\",\n message: `Backrelation field \"${model.name}.${field.name}\" (list of ${field.typeName}) has no matching @relation in \"${field.typeName}\" pointing to \"${model.name}\". Add @relation(fields: [...], references: [...]) to the FK field in \"${field.typeName}\".`,\n sourceId,\n span: field.span,\n });\n continue;\n }\n\n // The 1:N side: localFields are the PK fields of this model, targetFields are the FK fields in the target\n const mutableInterp = interp as { relations: Record<string, unknown> };\n mutableInterp.relations[field.name] = {\n to: crossRef(field.typeName),\n cardinality: \"1:N\",\n on: { localFields: fk.targetFields, targetFields: fk.localFields },\n };\n }\n }\n\n if (diagnostics.length > 0) {\n return notOk({\n summary: \"PSL to IDB contract interpretation failed\",\n diagnostics,\n });\n }\n\n // ── Build the contract ────────────────────────────────────────────────────────\n\n const ns = UNBOUND_DOMAIN_NAMESPACE_ID;\n const stores: Record<string, IdbStoreDefinition> = {};\n const roots: Record<string, ReturnType<typeof crossRef>> = {};\n const domainModels: Record<string, unknown> = {};\n const executionDefaults: ExecutionMutationDefault[] = [];\n\n for (const [modelName, interp] of interpretedByName) {\n stores[interp.storeName] = {\n keyPath: interp.keyPath,\n ...(interp.autoIncrement ? { autoIncrement: true } : {}),\n ...(Object.keys(interp.indexes).length > 0 ? { indexes: interp.indexes } : {}),\n };\n\n roots[interp.storeName] = crossRef(modelName);\n\n for (const fd of interp.fieldExecutionDefaults) {\n executionDefaults.push({\n ref: { namespace: ns, table: interp.storeName, column: fd.fieldName },\n ...(fd.onCreate ? { onCreate: fd.onCreate } : {}),\n ...(fd.onUpdate ? { onUpdate: fd.onUpdate } : {}),\n });\n }\n\n const modelStorage: IdbModelStorage = {\n storeName: interp.storeName,\n keyPath: interp.keyPath,\n ...(Object.keys(interp.relationsStorage).length > 0 ? { relations: interp.relationsStorage } : {}),\n ...(Object.keys(interp.fieldDefaults).length > 0 ? { fieldDefaults: interp.fieldDefaults } : {}),\n };\n\n domainModels[modelName] = {\n fields: interp.fields,\n relations: interp.relations,\n storage: modelStorage,\n };\n }\n\n const storageBlock = {\n stores,\n namespaces: { [ns]: { id: ns, entries: {} } },\n };\n\n const capabilities = {\n idb: { ddlOnlyInUpgrade: true, transactionalDDL: true },\n };\n\n const storageHash = computeStorageHash({\n target: \"idb\",\n targetFamily: \"idb\",\n storage: storageBlock,\n });\n\n const profileHash = computeProfileHash({\n target: \"idb\",\n targetFamily: \"idb\",\n capabilities,\n });\n\n const storage: IdbStorage = { ...storageBlock, storageHash };\n\n const domain = {\n namespaces: { [ns]: { models: domainModels } },\n } as unknown as ApplicationDomain;\n\n const execution =\n executionDefaults.length > 0\n ? {\n executionHash: computeExecutionHash({\n target: \"idb\",\n targetFamily: \"idb\",\n execution: { mutations: { defaults: executionDefaults } },\n }),\n mutations: { defaults: executionDefaults },\n }\n : undefined;\n\n const contract: Contract<IdbStorage> = {\n target: \"idb\",\n targetFamily: \"idb\",\n roots,\n domain,\n storage,\n capabilities,\n extensions: {},\n meta: {},\n profileHash,\n ...(execution ? { execution } : {}),\n };\n\n validateContract(contract);\n return ok(contract);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { domainModelsAtDefaultNamespace } from "@prisma/orm-framework/contract/types";
|
|
2
|
+
import { ContractValidationError } from "@prisma/orm-framework/contract/contract-validation-error";
|
|
3
|
+
import { validateContractDomain } from "@prisma/orm-framework/contract/validate-domain";
|
|
4
|
+
//#region src/core/validate.ts
|
|
5
|
+
/**
|
|
6
|
+
* Validates the IDB-specific storage block of a contract.
|
|
7
|
+
*
|
|
8
|
+
* Runs after the framework's {@link validateContractDomain} (structural +
|
|
9
|
+
* domain validation). Checks:
|
|
10
|
+
*
|
|
11
|
+
* 1. `storage.stores` is present and is an object.
|
|
12
|
+
* 2. Every store has a non-empty `keyPath` string.
|
|
13
|
+
* 3. Every model's `storage.storeName` references an existing store.
|
|
14
|
+
*
|
|
15
|
+
* @throws {@link ContractValidationError} with phase `'storage'` on failure.
|
|
16
|
+
*/
|
|
17
|
+
function validateIdbStorage(contract) {
|
|
18
|
+
const storage = contract.storage;
|
|
19
|
+
if (!storage || typeof storage.stores !== "object" || storage.stores === null) throw new ContractValidationError("IDB contract must have storage.stores (an object)", "storage");
|
|
20
|
+
for (const [storeName, store] of Object.entries(storage.stores)) if (!store || typeof store.keyPath !== "string" || store.keyPath === "") throw new ContractValidationError(`Store "${storeName}" is missing a required non-empty keyPath string`, "storage");
|
|
21
|
+
const storeNames = new Set(Object.keys(storage.stores));
|
|
22
|
+
const models = domainModelsAtDefaultNamespace(contract.domain);
|
|
23
|
+
for (const [modelName, model] of Object.entries(models)) {
|
|
24
|
+
const storeName = model.storage?.storeName;
|
|
25
|
+
if (!storeName) throw new ContractValidationError(`Model "${modelName}" is missing storage.storeName`, "storage");
|
|
26
|
+
if (!storeNames.has(storeName)) throw new ContractValidationError(`Model "${modelName}" references non-existent store "${storeName}"`, "storage");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses and validates a raw contract value against the IDB contract schema.
|
|
31
|
+
*
|
|
32
|
+
* Runs two validation passes: framework domain validation then IDB-specific
|
|
33
|
+
* storage validation. Throws a {@link ContractValidationError} describing the
|
|
34
|
+
* first failure found.
|
|
35
|
+
*
|
|
36
|
+
* @param value - Raw contract value (e.g. parsed from `contract.json`).
|
|
37
|
+
* @returns The validated, fully-typed {@link IdbContract}.
|
|
38
|
+
*/
|
|
39
|
+
function validateContract(value) {
|
|
40
|
+
const contract = value;
|
|
41
|
+
validateContractDomain(contract);
|
|
42
|
+
validateIdbStorage(contract);
|
|
43
|
+
return contract;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { validateContract as t };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=validate-BLnItEKs.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-BLnItEKs.mjs","names":[],"sources":["../src/core/validate.ts"],"sourcesContent":["import type { Contract } from \"@prisma/orm-framework/contract/types\";\nimport { domainModelsAtDefaultNamespace } from \"@prisma/orm-framework/contract/types\";\nimport { ContractValidationError } from \"@prisma/orm-framework/contract/contract-validation-error\";\nimport { validateContractDomain } from \"@prisma/orm-framework/contract/validate-domain\";\nimport type { IdbModelStorage, IdbStorage } from \"@prisma-idb/target-idb/pack\";\n\n/** Fully-typed IDB contract after validation. */\nexport type IdbContract = Contract<IdbStorage>;\n\n/**\n * Validates the IDB-specific storage block of a contract.\n *\n * Runs after the framework's {@link validateContractDomain} (structural +\n * domain validation). Checks:\n *\n * 1. `storage.stores` is present and is an object.\n * 2. Every store has a non-empty `keyPath` string.\n * 3. Every model's `storage.storeName` references an existing store.\n *\n * @throws {@link ContractValidationError} with phase `'storage'` on failure.\n */\nfunction validateIdbStorage(contract: Contract): void {\n const storage = contract.storage as unknown as Partial<IdbStorage> | undefined;\n\n if (!storage || typeof storage.stores !== \"object\" || storage.stores === null) {\n throw new ContractValidationError(\"IDB contract must have storage.stores (an object)\", \"storage\");\n }\n\n // Validate each store has a keyPath.\n for (const [storeName, store] of Object.entries(storage.stores)) {\n if (!store || typeof store.keyPath !== \"string\" || store.keyPath === \"\") {\n throw new ContractValidationError(\n `Store \"${storeName}\" is missing a required non-empty keyPath string`,\n \"storage\"\n );\n }\n }\n\n // Validate model → store references. Models live under\n // `domain.namespaces.<ns>.models`; resolved via `domainModelsAtDefaultNamespace`.\n const storeNames = new Set(Object.keys(storage.stores));\n const models = domainModelsAtDefaultNamespace(contract.domain) as Record<\n string,\n { storage?: Partial<IdbModelStorage> }\n >;\n\n for (const [modelName, model] of Object.entries(models)) {\n const storeName = model.storage?.storeName;\n if (!storeName) {\n throw new ContractValidationError(`Model \"${modelName}\" is missing storage.storeName`, \"storage\");\n }\n if (!storeNames.has(storeName)) {\n throw new ContractValidationError(`Model \"${modelName}\" references non-existent store \"${storeName}\"`, \"storage\");\n }\n }\n}\n\n/**\n * Parses and validates a raw contract value against the IDB contract schema.\n *\n * Runs two validation passes: framework domain validation then IDB-specific\n * storage validation. Throws a {@link ContractValidationError} describing the\n * first failure found.\n *\n * @param value - Raw contract value (e.g. parsed from `contract.json`).\n * @returns The validated, fully-typed {@link IdbContract}.\n */\nexport function validateContract(value: unknown): IdbContract {\n // In v0.11.0 the contract arrives already structurally parsed (it's a\n // Contract object, not raw JSON). Domain validation checks roots, models,\n // valueObjects, and relations.\n const contract = value as Contract;\n validateContractDomain(contract);\n validateIdbStorage(contract);\n return contract as IdbContract;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAqBA,SAAS,mBAAmB,UAA0B;CACpD,MAAM,UAAU,SAAS;CAEzB,IAAI,CAAC,WAAW,OAAO,QAAQ,WAAW,YAAY,QAAQ,WAAW,MACvE,MAAM,IAAI,wBAAwB,qDAAqD,SAAS;CAIlG,KAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,QAAQ,MAAM,GAC5D,IAAI,CAAC,SAAS,OAAO,MAAM,YAAY,YAAY,MAAM,YAAY,IACnE,MAAM,IAAI,wBACR,UAAU,UAAU,mDACpB,SACF;CAMJ,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,QAAQ,MAAM,CAAC;CACtD,MAAM,SAAS,+BAA+B,SAAS,MAAM;CAK7D,KAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,MAAM,GAAG;EACvD,MAAM,YAAY,MAAM,SAAS;EACjC,IAAI,CAAC,WACH,MAAM,IAAI,wBAAwB,UAAU,UAAU,iCAAiC,SAAS;EAElG,IAAI,CAAC,WAAW,IAAI,SAAS,GAC3B,MAAM,IAAI,wBAAwB,UAAU,UAAU,mCAAmC,UAAU,IAAI,SAAS;CAEpH;AACF;;;;;;;;;;;AAYA,SAAgB,iBAAiB,OAA6B;CAI5D,MAAM,WAAW;CACjB,uBAAuB,QAAQ;CAC/B,mBAAmB,QAAQ;CAC3B,OAAO;AACT"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prisma-idb/family-idb",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Prisma 8 IDB family — control-plane descriptor and family instance (CLI/config integration)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"keywords": [
|
|
10
|
+
"prisma",
|
|
11
|
+
"prisma-8",
|
|
12
|
+
"indexeddb",
|
|
13
|
+
"offline-first",
|
|
14
|
+
"idb",
|
|
15
|
+
"cli"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/prisma-idb/prisma-idb.git",
|
|
20
|
+
"directory": "packages/prisma-orm/family-idb"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://prisma-idb.dev/",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/prisma-idb/prisma-idb/issues"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
"./control": "./dist/exports/control.mjs",
|
|
29
|
+
"./pack": "./dist/exports/pack.mjs",
|
|
30
|
+
"./contract-ts": "./dist/exports/contract-ts.mjs",
|
|
31
|
+
"./contract-psl": "./dist/exports/contract-psl.mjs",
|
|
32
|
+
"./config-types": "./dist/exports/config-types.mjs",
|
|
33
|
+
"./cli": "./dist/exports/cli.mjs",
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"prisma-idb": "./dist/bin/prisma-idb.mjs"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@prisma/cli-engine": "0.2.0",
|
|
41
|
+
"@prisma/orm-framework": "8.0.0-rc.5",
|
|
42
|
+
"@prisma/orm-toolchain": "8.0.0-rc.5",
|
|
43
|
+
"fake-indexeddb": "^6.2.5",
|
|
44
|
+
"pathe": "^2.0.3",
|
|
45
|
+
"@prisma-idb/target-idb": "0.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^24.10.9",
|
|
49
|
+
"tsdown": "^0.22.14",
|
|
50
|
+
"typescript": "^6.0.3",
|
|
51
|
+
"vitest": "^4.1.10"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsdown",
|
|
58
|
+
"dev": "tsdown --watch",
|
|
59
|
+
"check": "tsc --noEmit",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"lint": "prettier --check . && eslint .",
|
|
62
|
+
"format": "prettier --write ."
|
|
63
|
+
}
|
|
64
|
+
}
|