@prisma-idb/family-idb 0.12.0 → 0.13.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/README.md +5 -5
- package/dist/bin/prisma-idb.mjs +1 -1
- package/dist/{cli-DszpOXVL.mjs → cli-cDU50TgX.mjs} +20 -9
- package/dist/cli-cDU50TgX.mjs.map +1 -0
- package/dist/exports/cli.d.mts +1 -0
- package/dist/exports/cli.d.mts.map +1 -1
- package/dist/exports/cli.mjs +1 -1
- package/dist/exports/config-types.d.mts +1 -1
- package/dist/exports/config-types.d.mts.map +1 -1
- package/dist/exports/config-types.mjs +6 -2
- package/dist/exports/config-types.mjs.map +1 -1
- package/dist/exports/contract-psl.d.mts +2 -1
- package/dist/exports/contract-psl.d.mts.map +1 -1
- package/dist/exports/contract-psl.mjs +10 -5
- package/dist/exports/contract-psl.mjs.map +1 -1
- package/dist/exports/contract-ts.d.mts +9 -1
- package/dist/exports/contract-ts.d.mts.map +1 -1
- package/dist/exports/contract-ts.mjs +17 -8
- package/dist/exports/contract-ts.mjs.map +1 -1
- package/dist/exports/control.d.mts +11 -1
- package/dist/exports/control.d.mts.map +1 -1
- package/dist/exports/control.mjs +19 -31
- package/dist/exports/control.mjs.map +1 -1
- package/dist/{migration-plan-BwakybVZ.mjs → migration-plan-D5q-v5vh.mjs} +10 -3
- package/dist/migration-plan-D5q-v5vh.mjs.map +1 -0
- package/dist/{preflight-Bx2q040D.mjs → preflight-CJCC7zqV.mjs} +53 -11
- package/dist/preflight-CJCC7zqV.mjs.map +1 -0
- package/dist/{psl-interpreter-Vi1cBmhb.d.mts → psl-interpreter-D-xZYPYu.d.mts} +6 -2
- package/dist/psl-interpreter-D-xZYPYu.d.mts.map +1 -0
- package/dist/{psl-interpreter-BoPLi4c4.mjs → psl-interpreter-DgfjFTU2.mjs} +89 -20
- package/dist/psl-interpreter-DgfjFTU2.mjs.map +1 -0
- package/dist/{schema-verify-B7-xiHem.mjs → schema-verify-vrrFfMwf.mjs} +7 -1
- package/dist/schema-verify-vrrFfMwf.mjs.map +1 -0
- package/dist/{validate-dwKE5_5B.mjs → validate-Dt8a97c4.mjs} +7 -2
- package/dist/{validate-dwKE5_5B.mjs.map → validate-Dt8a97c4.mjs.map} +1 -1
- package/package.json +5 -5
- package/dist/cli-DszpOXVL.mjs.map +0 -1
- package/dist/migration-plan-BwakybVZ.mjs.map +0 -1
- package/dist/preflight-Bx2q040D.mjs.map +0 -1
- package/dist/psl-interpreter-BoPLi4c4.mjs.map +0 -1
- package/dist/psl-interpreter-Vi1cBmhb.d.mts.map +0 -1
- package/dist/schema-verify-B7-xiHem.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -10,11 +10,11 @@ npm install --save-dev @prisma-idb/family-idb
|
|
|
10
10
|
|
|
11
11
|
IndexedDB only exists in the browser, so three migration jobs need their own commands:
|
|
12
12
|
|
|
13
|
-
| Command | Does
|
|
14
|
-
| ------------------------------------- |
|
|
15
|
-
| `prisma-idb migration plan` | Plans the next migration from the newest one on disk. Warns if it deletes data.
|
|
16
|
-
| `prisma-idb migration contract-space` | Bundles the migrations into a module the browser imports.
|
|
17
|
-
| `prisma-idb migration preflight` | Replays migrations in memory
|
|
13
|
+
| Command | Does |
|
|
14
|
+
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
15
|
+
| `prisma-idb migration plan` | Plans the next migration from the newest one on disk. Warns if it deletes data. |
|
|
16
|
+
| `prisma-idb migration contract-space` | Bundles the migrations into a module the browser imports. |
|
|
17
|
+
| `prisma-idb migration preflight` | Replays migrations in memory, verifies the schema against the head snapshot, and checks that the emitted contract is the head. |
|
|
18
18
|
|
|
19
19
|
All three read `prisma.config.ts`. See [Migrations](https://prisma-idb.dev/docs/prisma-8/migrations).
|
|
20
20
|
|
package/dist/bin/prisma-idb.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { CliStructuredError, notOk, ok } from "@prisma/cli-engine/protocol";
|
|
|
14
14
|
function createCollectingSink() {
|
|
15
15
|
const completedLines = [];
|
|
16
16
|
let buffer = "";
|
|
17
|
+
/** Accumulate partial writes into complete lines for all presentation formats. */
|
|
17
18
|
function push(text) {
|
|
18
19
|
buffer += text;
|
|
19
20
|
const parts = buffer.split("\n");
|
|
@@ -201,7 +202,7 @@ const commands = {
|
|
|
201
202
|
handler: async (args, ctx) => {
|
|
202
203
|
const contractPath = requireContractPath(ctx.config, ctx.cwd, args.flags.contract);
|
|
203
204
|
const migrationsDir = resolveMigrationsDir(ctx.config, ctx.cwd, args.flags.migrationsDir);
|
|
204
|
-
const { migrationPlan } = await import("./migration-plan-
|
|
205
|
+
const { migrationPlan } = await import("./migration-plan-D5q-v5vh.mjs");
|
|
205
206
|
const sink = createCollectingSink();
|
|
206
207
|
const exitCode = await migrationPlan({
|
|
207
208
|
migrationsDir,
|
|
@@ -220,19 +221,27 @@ const commands = {
|
|
|
220
221
|
"migration preflight": defineIdbCommand({
|
|
221
222
|
help: {
|
|
222
223
|
summary: "Validate the migration chain against fake-indexeddb",
|
|
223
|
-
description: "Walks every migration package under <migrationsDir>/app/ in chain order,\napplying each package's ops.json against a fresh fake-indexeddb instance.\nVerifies the final stores and indexes against the head contract snapshot.\nFails on replay errors, schema drift,
|
|
224
|
+
description: "Walks every migration package under <migrationsDir>/app/ in chain order,\napplying each package's ops.json against a fresh fake-indexeddb instance.\nVerifies the final stores and indexes against the head contract snapshot.\nFails on replay errors, schema drift, a missing or mismatched head snapshot,\nor an emitted contract.json that no migration reaches.",
|
|
224
225
|
examples: ["migration preflight"]
|
|
225
226
|
},
|
|
226
|
-
args: { flags: {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
args: { flags: {
|
|
228
|
+
contract: flag.string({
|
|
229
|
+
brief: "Path to contract.json (default: orm.contract.output)",
|
|
230
|
+
placeholder: "path"
|
|
231
|
+
}),
|
|
232
|
+
migrationsDir: flag.string({
|
|
233
|
+
brief: "Path to the migrations root (default: orm.migrations.dir)",
|
|
234
|
+
placeholder: "path"
|
|
235
|
+
})
|
|
236
|
+
} },
|
|
230
237
|
handler: async (args, ctx) => {
|
|
231
238
|
const migrationsDir = resolveMigrationsDir(ctx.config, ctx.cwd, args.flags.migrationsDir);
|
|
232
|
-
const
|
|
239
|
+
const contractPath = requireContractPath(ctx.config, ctx.cwd, args.flags.contract);
|
|
240
|
+
const { runPreflight } = await import("./preflight-CJCC7zqV.mjs");
|
|
233
241
|
const sink = createCollectingSink();
|
|
234
242
|
const exitCode = await runPreflight({
|
|
235
243
|
migrationsDir,
|
|
244
|
+
contractPath,
|
|
236
245
|
out: sink.out,
|
|
237
246
|
err: sink.err
|
|
238
247
|
});
|
|
@@ -255,7 +264,7 @@ const idbCommandFamily = defineCommandFamily({
|
|
|
255
264
|
});
|
|
256
265
|
//#endregion
|
|
257
266
|
//#region package.json
|
|
258
|
-
var version = "0.
|
|
267
|
+
var version = "0.13.0";
|
|
259
268
|
//#endregion
|
|
260
269
|
//#region src/cli/cli.ts
|
|
261
270
|
const BIN_NAME = "prisma-idb";
|
|
@@ -263,6 +272,7 @@ const BIN_GROUPS = { migration: {
|
|
|
263
272
|
brief: "On-disk migration management commands",
|
|
264
273
|
description: "Plan, bundle, and validate IDB migration packages. Migrations are\ncontract-to-contract edges stored as versioned directories under migrations/."
|
|
265
274
|
} };
|
|
275
|
+
/** Create the companion CLI with the shared ORM config section and IDB migration commands. */
|
|
266
276
|
function createIdbCli() {
|
|
267
277
|
return createCli({
|
|
268
278
|
name: BIN_NAME,
|
|
@@ -313,6 +323,7 @@ function runtimeFromProcess(proc) {
|
|
|
313
323
|
};
|
|
314
324
|
}
|
|
315
325
|
const STARTUP_FAILURE_EXIT_CODE = 1;
|
|
326
|
+
/** Normalize startup failures before writing the structured error and exit code. */
|
|
316
327
|
function reportStartupFailure(proc, error) {
|
|
317
328
|
const normalized = CliStructuredError.is(error) ? error : new CliStructuredError("IDB-CLI.STARTUP_FAILURE", error instanceof Error ? error.message : String(error));
|
|
318
329
|
proc.stderr.write(`✘ [${normalized.code}] ${normalized.message}\n`);
|
|
@@ -329,4 +340,4 @@ async function runIdbCli(proc) {
|
|
|
329
340
|
//#endregion
|
|
330
341
|
export { idbCommandFamily as a, runIdbCli as i, BIN_NAME as n, createIdbCli as r, BIN_GROUPS as t };
|
|
331
342
|
|
|
332
|
-
//# sourceMappingURL=cli-
|
|
343
|
+
//# sourceMappingURL=cli-cDU50TgX.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-cDU50TgX.mjs","names":["packageJson.version"],"sources":["../src/cli/collecting-sink.ts","../src/cli/define-command.ts","../src/cli/migration/paths.ts","../src/cli/migration/contract-space.ts","../src/cli/migration/plan.ts","../src/cli/migration/preflight.ts","../src/cli/family.ts","../package.json","../src/cli/cli.ts"],"sourcesContent":["import type { Presentations } from \"@prisma/cli-engine\";\n\n/**\n * Collects a wrapped core function's `out`/`err` sink writes so a command\n * handler can present them through the engine instead of writing to the\n * real `process.stdout`/`process.stderr` directly (which would corrupt\n * `--json` mode and be invisible to `createTestCli`'s in-memory harness).\n */\nexport interface CollectingSink {\n readonly out: (line: string) => void;\n readonly err: (line: string) => void;\n /** Every line written to either sink, in order, newline-split. */\n lines(): readonly string[];\n /**\n * `lines()` joined back into text — the full collected log (progress\n * AND error detail, not just the `err`-only parts), for use as a\n * `CliStructuredError`'s `summary` on a nonzero exit. A wrapped function\n * writes its error explanation to `err` only after already writing\n * per-step progress to `out` (e.g. preflight's `\"<dir> … \"` / `\"FAILED\"`\n * pair) — using only the `err` writes would silently drop that context.\n */\n fullText(): string;\n}\n\n/**\n * Buffers writes the way a real stream does: a write with no trailing\n * newline (e.g. the wrapped functions' `out(\" ${dirName} … \")` followed\n * later by a separate `out(\"ok\\n\")` call) stays pending and joins with\n * whatever arrives next, rather than becoming its own line. Splitting each\n * `out`/`err` call independently — the first cut of this — silently broke\n * exactly this pattern in `preflight.ts`'s per-package progress line.\n */\nexport function createCollectingSink(): CollectingSink {\n const completedLines: string[] = [];\n let buffer = \"\";\n\n /** Accumulate partial writes into complete lines for all presentation formats. */\n function push(text: string): void {\n buffer += text;\n const parts = buffer.split(\"\\n\");\n buffer = parts.pop() ?? \"\";\n for (const part of parts) {\n if (part.length > 0) completedLines.push(part);\n }\n }\n\n const lines = (): readonly string[] => (buffer.length > 0 ? [...completedLines, buffer] : completedLines);\n\n return {\n out: (text) => push(text),\n err: (text) => push(text),\n lines,\n fullText: () => lines().join(\"\\n\").trim(),\n };\n}\n\n/**\n * Renders collected lines as a `drawing` block (verbatim, no reflow) in\n * human mode; `stdout` stays empty since these commands carry no separate\n * machine-pipeable data channel beyond the human log itself.\n */\nexport function presentationsFromSink(sink: CollectingSink, exitCode: number): Presentations {\n const lines = sink.lines();\n return {\n human: () => (lines.length === 0 ? [] : [{ kind: \"drawing\", lines }]),\n stdout: () => [],\n json: () => ({ exitCode, lines }),\n next: () => [],\n };\n}\n","import type { PrismaNextConfig } from \"@prisma/orm-toolchain/config-loader\";\nimport type {\n ArgsSpec,\n CommandDefinition,\n FlagSpec,\n Handler,\n HelpSpec,\n PositionalSpec,\n SpawnDeclarations,\n} from \"@prisma/cli-engine\";\nimport { defineCommand } from \"@prisma/cli-engine\";\nimport { CliStructuredError, notOk } from \"@prisma/cli-engine/protocol\";\nimport { ormConfigSection } from \"./config-section\";\n\nfunction normalizeError(error: unknown): CliStructuredError {\n if (CliStructuredError.is(error)) return error;\n return new CliStructuredError(\"IDB-CLI.UNEXPECTED_ERROR\", error instanceof Error ? error.message : String(error));\n}\n\n/**\n * These 3 commands are IDB-specific (fake-indexeddb, IdbMigrationPlanner) —\n * pointing them at a non-IDB `prisma.config.ts` would fail confusingly deep\n * inside that logic rather than with a clear, actionable error. `orm`'s own\n * config section is family-agnostic by design (ADR 150), so this guard is\n * this shell's responsibility, not the section's.\n */\nfunction requireIdbFamily(config: PrismaNextConfig): void {\n const familyId = config.family?.familyId;\n if (familyId !== \"idb\") {\n throw new CliStructuredError(\n \"IDB-CLI.FAMILY_MISMATCH\",\n `config family is \"${familyId ?? \"unknown\"}\", expected \"idb\".`,\n {\n why: \"This CLI's migration commands operate on IDB-family projects only.\",\n nextActions: [\n {\n kind: \"edit-file\",\n label:\n \"Point --config at your browser-side prisma.config.ts (the one using @prisma-idb/family-idb/control)\",\n },\n ],\n }\n );\n }\n}\n\n/**\n * `defineCommand` pre-bound to the `orm` config section (see\n * `config-section.ts`) with a uniform error boundary, mirroring\n * `@prisma/orm-toolchain`'s own `defineOrmCommand`. The section's schema\n * resolves `contract.output`/`migrations.dir` against the config file that\n * wrote them (and defaults `migrations.dir`), so handlers always read\n * absolute paths without a separate finalize step.\n */\nexport function defineIdbCommand<\n TFlags extends Record<string, FlagSpec<unknown>> = Record<never, FlagSpec<unknown>>,\n TPositionals extends Record<string, PositionalSpec<unknown>> = Record<never, PositionalSpec<unknown>>,\n TCode extends number = never,\n>(\n def: {\n readonly help: HelpSpec;\n readonly args?: ArgsSpec<TFlags, TPositionals>;\n readonly exitCodes?: Readonly<Record<TCode, string>>;\n readonly handler: Handler<TFlags, TPositionals, PrismaNextConfig, TCode, false, false>;\n } & SpawnDeclarations\n): CommandDefinition<TFlags, TPositionals, PrismaNextConfig, TCode, false, false> {\n return defineCommand<TFlags, TPositionals, PrismaNextConfig, TCode, false, false>({\n ...def,\n needs: { config: ormConfigSection },\n handler: async (args, ctx) => {\n try {\n requireIdbFamily(ctx.config);\n return await def.handler(args, ctx);\n } catch (error) {\n return notOk(normalizeError(error));\n }\n },\n });\n}\n","import type { PrismaNextConfig } from \"@prisma/orm-toolchain/config-loader\";\nimport { CliStructuredError } from \"@prisma/cli-engine/protocol\";\nimport { resolve } from \"pathe\";\n\n/**\n * Resolves the contract/migrations paths a command needs from the already\n * finalized (absolute-paths) `orm` config section, with CLI flag overrides\n * winning when supplied. `ctx.config` arrives finalized by\n * `defineIdbCommand` (see `../define-command.ts`), so `config.contract.output`\n * and `config.migrations.dir` are already absolute — only an explicit\n * `--contract`/`--migrations-dir` flag (relative to `cwd`) needs resolving\n * here.\n */\nexport function requireContractPath(config: PrismaNextConfig, cwd: string, override: string | undefined): string {\n if (override !== undefined) return resolve(cwd, override);\n const output = config.contract?.output;\n if (output === undefined) {\n throw new CliStructuredError(\n \"IDB-CLI.CONTRACT_PATH_MISSING\",\n \"config.contract.output is required to resolve the contract path.\",\n {\n why: \"Neither --contract nor prisma.config.ts's orm.contract.output supplied a path.\",\n nextActions: [\n { kind: \"edit-file\", label: \"Set contract.output in prisma.config.ts, or pass --contract explicitly\" },\n ],\n }\n );\n }\n return output;\n}\n\n/**\n * `finalizeConfig` always resolves `migrations.dir` to an absolute path\n * (defaulting to `<configDir>/migrations` when unset); the fallback here is\n * defensive, not the expected path.\n */\nexport function resolveMigrationsDir(config: PrismaNextConfig, cwd: string, override: string | undefined): string {\n if (override !== undefined) return resolve(cwd, override);\n return config.migrations?.dir ?? resolve(cwd, \"migrations\");\n}\n","import { dirname, join, resolve } from \"pathe\";\nimport { flag } from \"@prisma/cli-engine\";\nimport { CliStructuredError, notOk, ok } from \"@prisma/cli-engine/protocol\";\nimport { createCollectingSink, presentationsFromSink } from \"../collecting-sink\";\nimport { defineIdbCommand } from \"../define-command\";\nimport { requireContractPath, resolveMigrationsDir } from \"./paths\";\n\nexport const migrationContractSpaceCommand = defineIdbCommand({\n help: {\n summary: \"Regenerate contract-space.generated.ts from migrations/app/\",\n description:\n \"Reads every migration package under <migrationsDir>/app/, validates the\\n\" +\n \"chain's connectivity, and emits a generated TypeScript module that bundles\\n\" +\n \"them into a ContractSpace.\",\n examples: [\"migration contract-space\", \"migration contract-space --out src/lib/prisma/contract-space.ts\"],\n },\n args: {\n flags: {\n contract: flag.string({\n brief: \"Path to contract.json (default: orm.contract.output)\",\n placeholder: \"path\",\n }),\n migrationsDir: flag.string({\n brief: \"Path to the migrations root (default: orm.migrations.dir)\",\n placeholder: \"path\",\n }),\n out: flag.string({\n brief: \"Output file path (default: colocated with the resolved contract.json)\",\n placeholder: \"path\",\n }),\n },\n },\n handler: async (args, ctx) => {\n const contractPath = requireContractPath(ctx.config, ctx.cwd, args.flags.contract);\n const migrationsDir = resolveMigrationsDir(ctx.config, ctx.cwd, args.flags.migrationsDir);\n const outPath =\n args.flags.out !== undefined\n ? resolve(ctx.cwd, args.flags.out)\n : join(dirname(contractPath), \"contract-space.generated.ts\");\n\n const { generateContractSpace } = await import(\"../../core/contract-space-codegen\");\n const sink = createCollectingSink();\n const exitCode = await generateContractSpace({\n migrationsDir,\n contractPath,\n outPath,\n out: sink.out,\n err: sink.err,\n });\n\n if (exitCode !== 0) {\n return notOk(\n new CliStructuredError(\"IDB-CLI.CONTRACT_SPACE_FAILED\", sink.fullText() || \"migration contract-space failed.\")\n );\n }\n return ok(ctx.present({ data: { exitCode, outPath } }, presentationsFromSink(sink, exitCode)));\n },\n});\n","import { flag } from \"@prisma/cli-engine\";\nimport { CliStructuredError, notOk, ok } from \"@prisma/cli-engine/protocol\";\nimport { createCollectingSink, presentationsFromSink } from \"../collecting-sink\";\nimport { defineIdbCommand } from \"../define-command\";\nimport { requireContractPath, resolveMigrationsDir } from \"./paths\";\n\nexport const migrationPlanCommand = defineIdbCommand({\n help: {\n summary: \"Plan the next IDB migration package (auto-detects baseline vs. incremental)\",\n description:\n \"Compares the emitted contract against the latest on-disk migration state and\\n\" +\n \"produces a new migration package with the required operations. Offline —\\n\" +\n \"never opens IndexedDB (there is no live database on the Node side to consult).\",\n examples: [\"migration plan\", \"migration plan --name add-posts\", \"migration plan --space idb-sync\"],\n },\n args: {\n flags: {\n name: flag.string({\n brief: 'Directory slug (default: \"baseline\" for a fresh space; required otherwise)',\n placeholder: \"slug\",\n }),\n space: flag.string({\n brief: 'Contract-space id (default: \"app\"). Only extension authors set this.',\n placeholder: \"id\",\n }),\n contract: flag.string({\n brief: \"Path to contract.json (default: orm.contract.output)\",\n placeholder: \"path\",\n }),\n migrationsDir: flag.string({\n brief: \"Path to the migrations root (default: orm.migrations.dir)\",\n placeholder: \"path\",\n }),\n },\n },\n handler: async (args, ctx) => {\n const contractPath = requireContractPath(ctx.config, ctx.cwd, args.flags.contract);\n const migrationsDir = resolveMigrationsDir(ctx.config, ctx.cwd, args.flags.migrationsDir);\n\n const { migrationPlan } = await import(\"../../core/migration-plan\");\n const sink = createCollectingSink();\n const exitCode = await migrationPlan({\n migrationsDir,\n contractPath,\n out: sink.out,\n err: sink.err,\n ...(args.flags.name !== undefined && { name: args.flags.name }),\n ...(args.flags.space !== undefined && { spaceId: args.flags.space }),\n });\n\n if (exitCode === 2) {\n return notOk(\n new CliStructuredError(\n \"IDB-CLI.MIGRATION_NAME_REQUIRED\",\n sink.fullText() || \"--name <slug> is required when generating an incremental migration.\"\n )\n );\n }\n if (exitCode !== 0) {\n return notOk(\n new CliStructuredError(\"IDB-CLI.MIGRATION_PLAN_FAILED\", sink.fullText() || \"migration plan failed.\")\n );\n }\n return ok(ctx.present({ data: { exitCode } }, presentationsFromSink(sink, exitCode)));\n },\n});\n","import { flag } from \"@prisma/cli-engine\";\nimport { CliStructuredError, notOk, ok } from \"@prisma/cli-engine/protocol\";\nimport { createCollectingSink, presentationsFromSink } from \"../collecting-sink\";\nimport { defineIdbCommand } from \"../define-command\";\nimport { requireContractPath, resolveMigrationsDir } from \"./paths\";\n\nexport const migrationPreflightCommand = defineIdbCommand({\n help: {\n summary: \"Validate the migration chain against fake-indexeddb\",\n description:\n \"Walks every migration package under <migrationsDir>/app/ in chain order,\\n\" +\n \"applying each package's ops.json against a fresh fake-indexeddb instance.\\n\" +\n \"Verifies the final stores and indexes against the head contract snapshot.\\n\" +\n \"Fails on replay errors, schema drift, a missing or mismatched head snapshot,\\n\" +\n \"or an emitted contract.json that no migration reaches.\",\n examples: [\"migration preflight\"],\n },\n args: {\n flags: {\n contract: flag.string({\n brief: \"Path to contract.json (default: orm.contract.output)\",\n placeholder: \"path\",\n }),\n migrationsDir: flag.string({\n brief: \"Path to the migrations root (default: orm.migrations.dir)\",\n placeholder: \"path\",\n }),\n },\n },\n handler: async (args, ctx) => {\n const migrationsDir = resolveMigrationsDir(ctx.config, ctx.cwd, args.flags.migrationsDir);\n\n const contractPath = requireContractPath(ctx.config, ctx.cwd, args.flags.contract);\n\n const { runPreflight } = await import(\"../../core/preflight\");\n const sink = createCollectingSink();\n const exitCode = await runPreflight({ migrationsDir, contractPath, out: sink.out, err: sink.err });\n\n if (exitCode !== 0) {\n return notOk(new CliStructuredError(\"IDB-CLI.PREFLIGHT_FAILED\", sink.fullText() || \"Preflight failed.\"));\n }\n return ok(ctx.present({ data: { exitCode } }, presentationsFromSink(sink, exitCode)));\n },\n});\n","import type { AnyCommand } from \"@prisma/cli-engine\";\nimport { defineCommandFamily } from \"@prisma/cli-engine\";\nimport { ormConfigSection } from \"./config-section\";\nimport { migrationContractSpaceCommand } from \"./migration/contract-space\";\nimport { migrationPlanCommand } from \"./migration/plan\";\nimport { migrationPreflightCommand } from \"./migration/preflight\";\n\nconst commands: Readonly<Record<string, AnyCommand>> = {\n \"migration plan\": migrationPlanCommand,\n \"migration contract-space\": migrationContractSpaceCommand,\n \"migration preflight\": migrationPreflightCommand,\n};\n\n/**\n * The unit this package contributes to a `@prisma/cli-engine` shell: its\n * config section (reused from the ORM family, see `config-section.ts`) and\n * its 3 commands. These have no generic equivalent — the real `prisma` CLI's\n * `migration new`/`plan`/etc. work against a live database or a SQL/Mongo\n * on-disk model; ours works against `fake-indexeddb` and a hand-rolled\n * contract-space convention.\n */\nexport const idbCommandFamily = defineCommandFamily({\n configSection: ormConfigSection,\n commands,\n});\n","","import type { Cli, HostProcess, Runtime } from \"@prisma/cli-engine\";\nimport { createCli, loadConfig } from \"@prisma/cli-engine\";\nimport { CliStructuredError } from \"@prisma/cli-engine/protocol\";\nimport packageJson from \"../../package.json\" with { type: \"json\" };\nimport { idbCommandFamily } from \"./family\";\n\nexport const BIN_NAME = \"prisma-idb\";\n\nexport const BIN_GROUPS = {\n migration: {\n brief: \"On-disk migration management commands\",\n description:\n \"Plan, bundle, and validate IDB migration packages. Migrations are\\n\" +\n \"contract-to-contract edges stored as versioned directories under migrations/.\",\n },\n} as const;\n\n/** Create the companion CLI with the shared ORM config section and IDB migration commands. */\nexport function createIdbCli(): Cli {\n return createCli({\n name: BIN_NAME,\n version: packageJson.version,\n commandFamilies: [idbCommandFamily],\n groups: BIN_GROUPS,\n commands: idbCommandFamily.commands,\n help: {\n tagline: \"IDB-target tooling for Prisma 8\",\n description: \"Migration authoring for IndexedDB projects — no live database on the Node side to consult.\",\n },\n });\n}\n\n/** Everything environmental the engine is given, adapted from the host process once. */\nexport function runtimeFromProcess(proc: HostProcess): Runtime {\n return {\n stdout: { write: (text) => void proc.stdout.write(text) },\n stderr: { write: (text) => void proc.stderr.write(text) },\n stdin: proc.stdin,\n cwd: proc.cwd(),\n env: proc.env,\n isTty: {\n stdin: proc.stdin.isTTY === true,\n stdout: proc.stdout.isTTY === true,\n stderr: proc.stderr.isTTY === true,\n },\n host: {\n runtime: { name: \"node\", version: proc.version },\n platform: proc.platform,\n arch: proc.arch,\n },\n exit: (code) => proc.exit(code),\n onSignal: (callback) => {\n const onInterrupt = () => callback(\"SIGINT\");\n const onTerminate = () => callback(\"SIGTERM\");\n proc.on(\"SIGINT\", onInterrupt);\n proc.on(\"SIGTERM\", onTerminate);\n return () => {\n proc.off(\"SIGINT\", onInterrupt);\n proc.off(\"SIGTERM\", onTerminate);\n };\n },\n loadConfig: (configPath) => loadConfig(proc.cwd(), configPath),\n // Never reached: no command here declares `credentials`/`managesCredentials`,\n // so ctx.api is never constructed — required on Runtime regardless.\n managementApi: { baseUrl: \"https://api.prisma.io\" },\n };\n}\n\nconst STARTUP_FAILURE_EXIT_CODE = 1;\n\n/** Normalize startup failures before writing the structured error and exit code. */\nfunction reportStartupFailure(proc: HostProcess, error: unknown): number {\n const normalized = CliStructuredError.is(error)\n ? error\n : new CliStructuredError(\"IDB-CLI.STARTUP_FAILURE\", error instanceof Error ? error.message : String(error));\n proc.stderr.write(`✘ [${normalized.code}] ${normalized.message}\\n`);\n return STARTUP_FAILURE_EXIT_CODE;\n}\n\n/** Parses, executes and settles one invocation; returns the exit code. */\nexport async function runIdbCli(proc: HostProcess): Promise<number> {\n try {\n return await createIdbCli().run(proc.argv.slice(2), runtimeFromProcess(proc));\n } catch (error) {\n return reportStartupFailure(proc, error);\n }\n}\n"],"mappings":"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"}
|
package/dist/exports/cli.d.mts
CHANGED
|
@@ -18,6 +18,7 @@ declare const BIN_GROUPS: {
|
|
|
18
18
|
readonly description: string;
|
|
19
19
|
};
|
|
20
20
|
};
|
|
21
|
+
/** Create the companion CLI with the shared ORM config section and IDB migration commands. */
|
|
21
22
|
declare function createIdbCli(): Cli;
|
|
22
23
|
/** Parses, executes and settles one invocation; returns the exit code. */
|
|
23
24
|
declare function runIdbCli(proc: HostProcess): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.mts","names":[],"sources":["../../src/cli/family.ts","../../src/cli/cli.ts"],"mappings":";;;;;;;;;;cAqBa,+CAAgB;;;cCfhB;cAEA
|
|
1
|
+
{"version":3,"file":"cli.d.mts","names":[],"sources":["../../src/cli/family.ts","../../src/cli/cli.ts"],"mappings":";;;;;;;;;;cAqBa,+CAAgB;;;cCfhB;cAEA;;;;;;;iBAUG,gBAAgB;;iBA8DV,UAAU,MAAM,cAAc"}
|
package/dist/exports/cli.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as idbCommandFamily, i as runIdbCli, n as BIN_NAME, r as createIdbCli, t as BIN_GROUPS } from "../cli-
|
|
1
|
+
import { a as idbCommandFamily, i as runIdbCli, n as BIN_NAME, r as createIdbCli, t as BIN_GROUPS } from "../cli-cDU50TgX.mjs";
|
|
2
2
|
export { BIN_GROUPS, BIN_NAME, createIdbCli, idbCommandFamily, runIdbCli };
|
|
@@ -5,7 +5,7 @@ declare const defineConfig: typeof defineConfig$1;
|
|
|
5
5
|
/**
|
|
6
6
|
* Wraps an in-memory contract object for use in `prisma.config.ts`.
|
|
7
7
|
*
|
|
8
|
-
* Use this
|
|
8
|
+
* Use this when the contract is authored as a TypeScript value.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-types.d.mts","names":[],"sources":["../../src/exports/config-types.ts"],"mappings":";;;cAYa,qBAAY;;;;;;;;;;;;;;;;;;iBAyBT,mBAAmB,UAAU,UAAU,kBAAkB;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"config-types.d.mts","names":[],"sources":["../../src/exports/config-types.ts"],"mappings":";;;cAYa,qBAAY;;;;;;;;;;;;;;;;;;iBAyBT,mBAAmB,UAAU,UAAU,kBAAkB;;;;;;;;;;;;;iBAsBzD,2BAA2B,sBAAsB,kBAAkB"}
|
|
@@ -12,7 +12,7 @@ function defaultOutputFromContractPath(contractPath) {
|
|
|
12
12
|
/**
|
|
13
13
|
* Wraps an in-memory contract object for use in `prisma.config.ts`.
|
|
14
14
|
*
|
|
15
|
-
* Use this
|
|
15
|
+
* Use this when the contract is authored as a TypeScript value.
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```ts
|
|
@@ -28,7 +28,10 @@ function defaultOutputFromContractPath(contractPath) {
|
|
|
28
28
|
*/
|
|
29
29
|
function typescriptContract(contract, output) {
|
|
30
30
|
return {
|
|
31
|
-
source: {
|
|
31
|
+
source: {
|
|
32
|
+
format: "typescript",
|
|
33
|
+
load: async () => ok(contract)
|
|
34
|
+
},
|
|
32
35
|
...output !== void 0 ? { output } : {}
|
|
33
36
|
};
|
|
34
37
|
}
|
|
@@ -47,6 +50,7 @@ function typescriptContract(contract, output) {
|
|
|
47
50
|
function typescriptContractFromPath(contractPath, output) {
|
|
48
51
|
return {
|
|
49
52
|
source: {
|
|
53
|
+
format: "typescript",
|
|
50
54
|
inputs: [contractPath],
|
|
51
55
|
load: async (context) => {
|
|
52
56
|
const [absolutePath] = context.resolvedInputs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-types.mjs","names":["coreDefineConfig"],"sources":["../../src/exports/config-types.ts"],"sourcesContent":["// Adapted from Prisma ORM's SQL contract config helpers.\n// These helpers are fully family-agnostic — they wrap any Contract object\n// in a ContractSourceProvider that the Prisma CLI config loader understands.\nimport { pathToFileURL } from \"node:url\";\nimport type { ContractConfig, PrismaNextConfig } from \"@prisma/orm-framework/config/config-types\";\nimport { defineConfig as coreDefineConfig } from \"@prisma/orm-framework/config/config-types\";\nimport type { Contract } from \"@prisma/orm-framework/contract/types\";\nimport { ok } from \"@prisma/orm-framework/utils/result\";\nimport { extname } from \"pathe\";\n\n// Re-export defineConfig so users only need @prisma-idb/family-idb.\nexport { type PrismaNextConfig };\nexport const defineConfig = coreDefineConfig;\n\nfunction defaultOutputFromContractPath(contractPath: string): string {\n const ext = extname(contractPath);\n if (ext.length === 0) return `${contractPath}.json`;\n return `${contractPath.slice(0, -ext.length)}.json`;\n}\n\n/**\n * Wraps an in-memory contract object for use in `prisma.config.ts`.\n *\n * Use this
|
|
1
|
+
{"version":3,"file":"config-types.mjs","names":["coreDefineConfig"],"sources":["../../src/exports/config-types.ts"],"sourcesContent":["// Adapted from Prisma ORM's SQL contract config helpers.\n// These helpers are fully family-agnostic — they wrap any Contract object\n// in a ContractSourceProvider that the Prisma CLI config loader understands.\nimport { pathToFileURL } from \"node:url\";\nimport type { ContractConfig, PrismaNextConfig } from \"@prisma/orm-framework/config/config-types\";\nimport { defineConfig as coreDefineConfig } from \"@prisma/orm-framework/config/config-types\";\nimport type { Contract } from \"@prisma/orm-framework/contract/types\";\nimport { ok } from \"@prisma/orm-framework/utils/result\";\nimport { extname } from \"pathe\";\n\n// Re-export defineConfig so users only need @prisma-idb/family-idb.\nexport { type PrismaNextConfig };\nexport const defineConfig = coreDefineConfig;\n\nfunction defaultOutputFromContractPath(contractPath: string): string {\n const ext = extname(contractPath);\n if (ext.length === 0) return `${contractPath}.json`;\n return `${contractPath.slice(0, -ext.length)}.json`;\n}\n\n/**\n * Wraps an in-memory contract object for use in `prisma.config.ts`.\n *\n * Use this when the contract is authored as a TypeScript value.\n *\n * @example\n * ```ts\n * import { typescriptContract } from '@prisma-idb/family-idb/config-types';\n * import contract from './prisma/contract';\n *\n * export default {\n * family: idbFamily,\n * target: idbTarget,\n * contract: typescriptContract(contract, 'src/prisma/contract.json'),\n * };\n * ```\n */\nexport function typescriptContract(contract: Contract, output?: string): ContractConfig {\n return {\n source: {\n format: \"typescript\",\n load: async () => ok(contract),\n },\n ...(output !== undefined ? { output } : {}),\n };\n}\n\n/**\n * Loads a contract from a TypeScript file at `contractPath` and wraps it for\n * use in `prisma.config.ts`. The file must export the contract as\n * `default` or `contract`.\n *\n * @example\n * ```ts\n * export default {\n * contract: typescriptContractFromPath('./prisma/contract.ts'),\n * };\n * ```\n */\nexport function typescriptContractFromPath(contractPath: string, output?: string): ContractConfig {\n return {\n source: {\n format: \"typescript\",\n inputs: [contractPath],\n load: async (context) => {\n const [absolutePath] = context.resolvedInputs;\n if (absolutePath === undefined) {\n throw new Error(\n \"typescriptContractFromPath: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.\"\n );\n }\n const mod = await import(pathToFileURL(absolutePath).href);\n const contract: Contract | undefined = mod.default ?? mod.contract;\n if (contract === undefined) {\n throw new Error(\n `typescriptContractFromPath: module at \"${absolutePath}\" has no \"default\" or \"contract\" export.`\n );\n }\n return ok(contract);\n },\n },\n output: output ?? defaultOutputFromContractPath(contractPath),\n };\n}\n"],"mappings":";;;;;AAYA,MAAa,eAAeA;AAE5B,SAAS,8BAA8B,cAA8B;CACnE,MAAM,MAAM,QAAQ,YAAY;CAChC,IAAI,IAAI,WAAW,GAAG,OAAO,GAAG,aAAa;CAC7C,OAAO,GAAG,aAAa,MAAM,GAAG,CAAC,IAAI,MAAM,EAAE;AAC/C;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBAAmB,UAAoB,QAAiC;CACtF,OAAO;EACL,QAAQ;GACN,QAAQ;GACR,MAAM,YAAY,GAAG,QAAQ;EAC/B;EACA,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;CAC3C;AACF;;;;;;;;;;;;;AAcA,SAAgB,2BAA2B,cAAsB,QAAiC;CAChG,OAAO;EACL,QAAQ;GACN,QAAQ;GACR,QAAQ,CAAC,YAAY;GACrB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,gBAAgB,QAAQ;IAC/B,IAAI,iBAAiB,KAAA,GACnB,MAAM,IAAI,MACR,8IACF;IAEF,MAAM,MAAM,MAAM,OAAO,cAAc,YAAY,CAAC,CAAC;IACrD,MAAM,WAAiC,IAAI,WAAW,IAAI;IAC1D,IAAI,aAAa,KAAA,GACf,MAAM,IAAI,MACR,0CAA0C,aAAa,yCACzD;IAEF,OAAO,GAAG,QAAQ;GACpB;EACF;EACA,QAAQ,UAAU,8BAA8B,YAAY;CAC9D;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as InterpretPslOptions, r as interpretPslDocumentToIdbContract, t as ContractProjection } from "../psl-interpreter-
|
|
1
|
+
import { n as InterpretPslOptions, r as interpretPslDocumentToIdbContract, t as ContractProjection } from "../psl-interpreter-D-xZYPYu.mjs";
|
|
2
2
|
import { ContractConfig } from "@prisma/orm-framework/config/config-types";
|
|
3
3
|
//#region src/core/psl-provider.d.ts
|
|
4
4
|
/**
|
|
@@ -14,6 +14,7 @@ import { ContractConfig } from "@prisma/orm-framework/config/config-types";
|
|
|
14
14
|
* from the client.
|
|
15
15
|
*/
|
|
16
16
|
declare function stripIdbExcludeAttributes(schema: string): string;
|
|
17
|
+
/** Output, projection, and schema text hooks for the PSL contract provider. */
|
|
17
18
|
interface PrismaIdbContractOptions {
|
|
18
19
|
readonly output?: string;
|
|
19
20
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-psl.d.mts","names":[],"sources":["../../src/core/psl-provider.ts"],"mappings":";;;;;;;;;;;;;;;iBAsBgB,0BAA0B;
|
|
1
|
+
{"version":3,"file":"contract-psl.d.mts","names":[],"sources":["../../src/core/psl-provider.ts"],"mappings":";;;;;;;;;;;;;;;iBAsBgB,0BAA0B;;UAkBzB;WACN;;;;;;;WAOA,aAAa;;;;;;;;;WASb,oBAAoB;;;;;;;;;;;;;;;;;;;;;;iBAuBf,kBAAkB,oBAAoB,UAAU,2BAA2B"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as interpretPslDocumentToIdbContract } from "../psl-interpreter-
|
|
1
|
+
import { t as interpretPslDocumentToIdbContract } from "../psl-interpreter-DgfjFTU2.mjs";
|
|
2
|
+
import { buildSymbolTable, mapPslDiagnostics } from "@prisma/orm-framework/psl-parser";
|
|
3
|
+
import { parse } from "@prisma/orm-framework/psl-parser/syntax";
|
|
2
4
|
import { notOk } from "@prisma/orm-framework/utils/result";
|
|
3
5
|
import { readFile } from "node:fs/promises";
|
|
4
|
-
import { buildSymbolTable, mapPslDiagnostics } from "@prisma/orm-framework/psl-parser";
|
|
5
6
|
import { withSeedDiagnostics } from "@prisma/orm-framework/psl-parser/interpret";
|
|
6
|
-
import { parse } from "@prisma/orm-framework/psl-parser/syntax";
|
|
7
7
|
import { basename, extname } from "pathe";
|
|
8
8
|
//#region src/core/psl-provider.ts
|
|
9
9
|
/**
|
|
@@ -21,6 +21,7 @@ import { basename, extname } from "pathe";
|
|
|
21
21
|
function stripIdbExcludeAttributes(schema) {
|
|
22
22
|
return schema.replace(/^[ \t]*@@idb\.exclude\b.*\n?/gm, "").replace(/[ \t]*@idb\.exclude\b/g, "");
|
|
23
23
|
}
|
|
24
|
+
/** Place contract.json beside schema.prisma, or use the schema basename otherwise. */
|
|
24
25
|
function defaultOutputFromSchemaPath(schemaPath) {
|
|
25
26
|
const ext = extname(schemaPath);
|
|
26
27
|
if (ext.length === 0) return `${schemaPath}.json`;
|
|
@@ -51,6 +52,7 @@ function defaultOutputFromSchemaPath(schemaPath) {
|
|
|
51
52
|
function prismaIdbContract(schemaPath, options) {
|
|
52
53
|
return {
|
|
53
54
|
source: {
|
|
55
|
+
format: "psl",
|
|
54
56
|
inputs: [schemaPath],
|
|
55
57
|
load: async (context) => {
|
|
56
58
|
const [absoluteSchemaPath] = context.resolvedInputs;
|
|
@@ -74,10 +76,13 @@ function prismaIdbContract(schemaPath, options) {
|
|
|
74
76
|
const { symbolTable: table, diagnostics: symbolDiagnostics } = buildSymbolTable({
|
|
75
77
|
documents: [document],
|
|
76
78
|
sources,
|
|
77
|
-
|
|
79
|
+
defaultNamespaceId: context.defaultNamespaceId
|
|
78
80
|
});
|
|
79
81
|
const seedDiagnostics = [...mapPslDiagnostics(parseDiagnostics, sources), ...mapPslDiagnostics(symbolDiagnostics, sources)];
|
|
80
|
-
return withSeedDiagnostics(interpretPslDocumentToIdbContract(table, schemaPath,
|
|
82
|
+
return withSeedDiagnostics(interpretPslDocumentToIdbContract(table, schemaPath, {
|
|
83
|
+
sources,
|
|
84
|
+
...options?.projection !== void 0 ? { projection: options.projection } : {}
|
|
85
|
+
}), seedDiagnostics);
|
|
81
86
|
}
|
|
82
87
|
},
|
|
83
88
|
output: options?.output ?? defaultOutputFromSchemaPath(schemaPath)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-psl.mjs","names":[],"sources":["../../src/core/psl-provider.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { ContractConfig } from \"@prisma/orm-framework/config/config-types\";\nimport { buildSymbolTable, mapPslDiagnostics } from \"@prisma/orm-framework/psl-parser\";\nimport { withSeedDiagnostics } from \"@prisma/orm-framework/psl-parser/interpret\";\nimport { parse } from \"@prisma/orm-framework/psl-parser/syntax\";\nimport { notOk } from \"@prisma/orm-framework/utils/result\";\nimport { extname, basename } from \"pathe\";\nimport type { ContractProjection } from \"./psl-interpreter\";\nimport { interpretPslDocumentToIdbContract } from \"./psl-interpreter\";\n\n/**\n * Removes `@idb.exclude`/`@@idb.exclude` from raw PSL text — the `idb`\n * namespace family-idb owns (`psl-interpreter.ts`'s `IDB_EXCLUDE_ATTR`).\n * A foreign PSL parser (e.g. the SQL family's) doesn't recognize this\n * namespace and hard-errors on it (`PSL_EXTENSION_NAMESPACE_NOT_COMPOSED`);\n * stripping it is the text-level equivalent of what family-idb itself\n * already does for these same fields under `projection: \"full\"`, where the\n * attribute is documented as a no-op. Use this when sharing a schema.prisma\n * authored for family-idb with a different family's schema loader — the\n * server always wants every field these attributes would otherwise hide\n * from the client.\n */\nexport function stripIdbExcludeAttributes(schema: string): string {\n return schema\n .replace(/^[ \\t]*@@idb\\.exclude\\b.*\\n?/gm, \"\") // model-level: drop the whole line, incl. trailing comments\n .replace(/[ \\t]*@idb\\.exclude\\b/g, \"\"); // field-level: drop just the token, keep the field\n}\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 if (basename(base) === \"schema\") {\n return `${base.slice(0, -\"schema\".length)}contract.json`;\n }\n return `${base}.json`;\n}\n\nexport interface PrismaIdbContractOptions {\n readonly output?: string;\n /**\n * `\"client\"` projects out anything marked `@idb.exclude`/`@@idb.exclude`\n * (ADR 012). Pass a distinct `output` alongside this so the client and\n * full/server contracts don't collide on the same file.\n * @default \"full\"\n */\n readonly projection?: ContractProjection;\n /**\n * Runs on the raw schema text right after it's read, before parsing.\n * Lets a downstream package (e.g. `@prisma-idb/sync-server`) append\n * synthetic model/enum declarations — the appended text goes through the\n * exact same parse → interpret → hash pipeline as hand-authored PSL, so\n * `storageHash` reflects it correctly (it's computed *inside*\n * `interpretPslDocumentToIdbContract`, from whatever this returns).\n */\n readonly injectSchemaText?: (schema: string) => string;\n}\n\n/**\n * Creates a `ContractConfig` that reads an IDB schema from a `.prisma` file.\n *\n * Use this in `prisma.config.ts` as the `contract:` value when you prefer\n * PSL authoring over the TypeScript-first `defineContract()` helper.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@prisma-idb/family-idb/config-types';\n * import { prismaIdbContract } from '@prisma-idb/family-idb/contract-psl';\n *\n * export default defineConfig({\n * // ...\n * contract: prismaIdbContract('./src/prisma/schema.prisma'),\n * });\n * ```\n *\n * The emitted `contract.json` lands next to the schema file by default\n * (`schema.prisma` → `contract.json`). Override with `options.output`.\n */\nexport function prismaIdbContract(schemaPath: string, options?: PrismaIdbContractOptions): 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 \"prismaIdbContract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.\"\n );\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 });\n }\n\n if (options?.injectSchemaText) {\n schema = options.injectSchemaText(schema);\n }\n\n // The filename becomes each diagnostic's `sourceId`, so pass the\n // configured schema path to keep diagnostics pointing at the user's file.\n const { document, sources, diagnostics: parseDiagnostics } = parse(schema, schemaPath);\n const { symbolTable: table, diagnostics: symbolDiagnostics } = buildSymbolTable({\n documents: [document],\n sources,\n
|
|
1
|
+
{"version":3,"file":"contract-psl.mjs","names":[],"sources":["../../src/core/psl-provider.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { ContractConfig } from \"@prisma/orm-framework/config/config-types\";\nimport { buildSymbolTable, mapPslDiagnostics } from \"@prisma/orm-framework/psl-parser\";\nimport { withSeedDiagnostics } from \"@prisma/orm-framework/psl-parser/interpret\";\nimport { parse } from \"@prisma/orm-framework/psl-parser/syntax\";\nimport { notOk } from \"@prisma/orm-framework/utils/result\";\nimport { extname, basename } from \"pathe\";\nimport type { ContractProjection } from \"./psl-interpreter\";\nimport { interpretPslDocumentToIdbContract } from \"./psl-interpreter\";\n\n/**\n * Removes `@idb.exclude`/`@@idb.exclude` from raw PSL text — the `idb`\n * namespace family-idb owns (`psl-interpreter.ts`'s `IDB_EXCLUDE_ATTR`).\n * A foreign PSL parser (e.g. the SQL family's) doesn't recognize this\n * namespace and hard-errors on it (`PSL_EXTENSION_NAMESPACE_NOT_COMPOSED`);\n * stripping it is the text-level equivalent of what family-idb itself\n * already does for these same fields under `projection: \"full\"`, where the\n * attribute is documented as a no-op. Use this when sharing a schema.prisma\n * authored for family-idb with a different family's schema loader — the\n * server always wants every field these attributes would otherwise hide\n * from the client.\n */\nexport function stripIdbExcludeAttributes(schema: string): string {\n return schema\n .replace(/^[ \\t]*@@idb\\.exclude\\b.*\\n?/gm, \"\") // model-level: drop the whole line, incl. trailing comments\n .replace(/[ \\t]*@idb\\.exclude\\b/g, \"\"); // field-level: drop just the token, keep the field\n}\n\n/** Place contract.json beside schema.prisma, or use the schema basename otherwise. */\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 if (basename(base) === \"schema\") {\n return `${base.slice(0, -\"schema\".length)}contract.json`;\n }\n return `${base}.json`;\n}\n\n/** Output, projection, and schema text hooks for the PSL contract provider. */\nexport interface PrismaIdbContractOptions {\n readonly output?: string;\n /**\n * `\"client\"` projects out anything marked `@idb.exclude`/`@@idb.exclude`\n * (ADR 012). Pass a distinct `output` alongside this so the client and\n * full/server contracts don't collide on the same file.\n * @default \"full\"\n */\n readonly projection?: ContractProjection;\n /**\n * Runs on the raw schema text right after it's read, before parsing.\n * Lets a downstream package (e.g. `@prisma-idb/sync-server`) append\n * synthetic model/enum declarations — the appended text goes through the\n * exact same parse → interpret → hash pipeline as hand-authored PSL, so\n * `storageHash` reflects it correctly (it's computed *inside*\n * `interpretPslDocumentToIdbContract`, from whatever this returns).\n */\n readonly injectSchemaText?: (schema: string) => string;\n}\n\n/**\n * Creates a `ContractConfig` that reads an IDB schema from a `.prisma` file.\n *\n * Use this in `prisma.config.ts` as the `contract:` value when you prefer\n * PSL authoring over the TypeScript-first `defineContract()` helper.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@prisma-idb/family-idb/config-types';\n * import { prismaIdbContract } from '@prisma-idb/family-idb/contract-psl';\n *\n * export default defineConfig({\n * // ...\n * contract: prismaIdbContract('./src/prisma/schema.prisma'),\n * });\n * ```\n *\n * The emitted `contract.json` lands next to the schema file by default\n * (`schema.prisma` → `contract.json`). Override with `options.output`.\n */\nexport function prismaIdbContract(schemaPath: string, options?: PrismaIdbContractOptions): ContractConfig {\n return {\n source: {\n format: \"psl\",\n inputs: [schemaPath],\n load: async (context) => {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n \"prismaIdbContract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.\"\n );\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 });\n }\n\n if (options?.injectSchemaText) {\n schema = options.injectSchemaText(schema);\n }\n\n // The filename becomes each diagnostic's `sourceId`, so pass the\n // configured schema path to keep diagnostics pointing at the user's file.\n const { document, sources, diagnostics: parseDiagnostics } = parse(schema, schemaPath);\n const { symbolTable: table, diagnostics: symbolDiagnostics } = buildSymbolTable({\n documents: [document],\n sources,\n defaultNamespaceId: context.defaultNamespaceId,\n });\n\n // Do not short-circuit on provider-level diagnostics — the fault-tolerant\n // parser/symbol-table still produce a usable table, and the interpreter\n // may surface its own diagnostics in the same response.\n const seedDiagnostics = [\n ...mapPslDiagnostics(parseDiagnostics, sources),\n ...mapPslDiagnostics(symbolDiagnostics, sources),\n ];\n\n const interpreted = withSeedDiagnostics(\n interpretPslDocumentToIdbContract(table, schemaPath, {\n sources,\n ...(options?.projection !== undefined ? { projection: options.projection } : {}),\n }),\n seedDiagnostics\n );\n // Return the full Result so seed diagnostics (parse + symbol-table\n // findings) survive the success path — the config loader surfaces\n // them alongside the contract.\n return interpreted;\n },\n },\n output: options?.output ?? defaultOutputFromSchemaPath(schemaPath),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,0BAA0B,QAAwB;CAChE,OAAO,OACJ,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,0BAA0B,EAAE;AACzC;;AAGA,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;CAC5C,IAAI,SAAS,IAAI,MAAM,UACrB,OAAO,GAAG,KAAK,MAAM,GAAG,EAAgB,EAAE;CAE5C,OAAO,GAAG,KAAK;AACjB;;;;;;;;;;;;;;;;;;;;;AA2CA,SAAgB,kBAAkB,YAAoB,SAAoD;CACxG,OAAO;EACL,QAAQ;GACN,QAAQ;GACR,QAAQ,CAAC,UAAU;GACnB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,sBAAsB,QAAQ;IACrC,IAAI,uBAAuB,KAAA,GACzB,MAAM,IAAI,MACR,qIACF;IAGF,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;KACF,CAAC;IACH;IAEA,IAAI,SAAS,kBACX,SAAS,QAAQ,iBAAiB,MAAM;IAK1C,MAAM,EAAE,UAAU,SAAS,aAAa,qBAAqB,MAAM,QAAQ,UAAU;IACrF,MAAM,EAAE,aAAa,OAAO,aAAa,sBAAsB,iBAAiB;KAC9E,WAAW,CAAC,QAAQ;KACpB;KACA,oBAAoB,QAAQ;IAC9B,CAAC;IAKD,MAAM,kBAAkB,CACtB,GAAG,kBAAkB,kBAAkB,OAAO,GAC9C,GAAG,kBAAkB,mBAAmB,OAAO,CACjD;IAYA,OAVoB,oBAClB,kCAAkC,OAAO,YAAY;KACnD;KACA,GAAI,SAAS,eAAe,KAAA,IAAY,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;IAChF,CAAC,GACD,eAKe;GACnB;EACF;EACA,QAAQ,SAAS,UAAU,4BAA4B,UAAU;CACnE;AACF"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { t as ContractProjection } from "../psl-interpreter-
|
|
1
|
+
import { t as ContractProjection } from "../psl-interpreter-D-xZYPYu.mjs";
|
|
2
2
|
import { IdbKeyPath, IdbReferentialAction, IdbStorage } from "@prisma-idb/target-idb/pack";
|
|
3
3
|
import { Contract } from "@prisma/orm-framework/contract/types";
|
|
4
4
|
//#region src/core/contract-builder.d.ts
|
|
5
|
+
/** Scalar names supported by the TypeScript IDB contract builder. */
|
|
5
6
|
type PrismaScalarType = "String" | "Int" | "Float" | "Boolean" | "DateTime" | "BigInt" | "Decimal" | "Json" | "Bytes";
|
|
7
|
+
/** A required or nullable scalar field declaration. */
|
|
6
8
|
type PrismaScalarFieldSpec = PrismaScalarType | `${PrismaScalarType}?`;
|
|
7
9
|
/**
|
|
8
10
|
* A field spec string: the Prisma scalar type name, optionally suffixed with
|
|
@@ -11,7 +13,9 @@ type PrismaScalarFieldSpec = PrismaScalarType | `${PrismaScalarType}?`;
|
|
|
11
13
|
type FieldSpec<EnumName extends string = never> = PrismaScalarFieldSpec | EnumName | `${EnumName}?` | `${EnumName}[]`;
|
|
12
14
|
/** A named enum's ordered string values. Each value is also its member name. */
|
|
13
15
|
type EnumDef = readonly string[];
|
|
16
|
+
/** Named string enums available to model field declarations. */
|
|
14
17
|
type EnumDefs = Readonly<Record<string, EnumDef>>;
|
|
18
|
+
/** A reference relation and its storage-level referential actions. */
|
|
15
19
|
type RelationDef = {
|
|
16
20
|
readonly to: string;
|
|
17
21
|
readonly cardinality: "1:1" | "1:N" | "N:1";
|
|
@@ -28,12 +32,14 @@ type RelationDef = {
|
|
|
28
32
|
*/
|
|
29
33
|
readonly nullable?: boolean;
|
|
30
34
|
};
|
|
35
|
+
/** The key fields and flags of one secondary index. */
|
|
31
36
|
type IndexDef = {
|
|
32
37
|
/** A single field name, or an ordered list of field names for a compound (multi-field) index. */
|
|
33
38
|
readonly keyPath: IdbKeyPath;
|
|
34
39
|
readonly unique?: boolean;
|
|
35
40
|
readonly multiEntry?: boolean;
|
|
36
41
|
};
|
|
42
|
+
/** The fields, storage layout, relations, and projection rules of one model. */
|
|
37
43
|
type ModelDef<EnumName extends string = never> = {
|
|
38
44
|
readonly store: string;
|
|
39
45
|
/** The primary key field, or an ordered list of fields for a compound primary key. */
|
|
@@ -60,6 +66,7 @@ type ModelDef<EnumName extends string = never> = {
|
|
|
60
66
|
/** Server-only fields on an otherwise-synced model — dropped in client projection. See ADR 012. */
|
|
61
67
|
readonly excludeFields?: readonly string[];
|
|
62
68
|
};
|
|
69
|
+
/** Family and target metadata together with the models and enums to build. */
|
|
63
70
|
type DefineContractInput<TEnums extends EnumDefs = Record<never, never>> = {
|
|
64
71
|
/** Pass the default export of `@prisma-idb/family-idb/pack`. */
|
|
65
72
|
readonly family: {
|
|
@@ -74,6 +81,7 @@ type DefineContractInput<TEnums extends EnumDefs = Record<never, never>> = {
|
|
|
74
81
|
readonly enums?: TEnums;
|
|
75
82
|
readonly models: Record<string, ModelDef<Extract<keyof TEnums, string>>>;
|
|
76
83
|
};
|
|
84
|
+
/** Projection settings for the TypeScript contract builder. */
|
|
77
85
|
type DefineContractOptions = {
|
|
78
86
|
/** @default "full" */
|
|
79
87
|
readonly projection?: ContractProjection;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-ts.d.mts","names":[],"sources":["../../src/core/contract-builder.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"contract-ts.d.mts","names":[],"sources":["../../src/core/contract-builder.ts"],"mappings":";;;;;KA0BK;;KAGA,wBAAwB,sBAAsB;;;;;KAMvC,UAAU,mCACpB,wBAAwB,cAAc,iBAAiB;;KAG7C;;KAGA,WAAW,SAAS,eAAe;;KAiBnC;WACD;WACA;WACA;aACE;aACA;;WAEF,WAAW;WACX,WAAW;;;;;;WAMX;;;KAIC;;WAED,SAAS;WACT;WACA;;;KAIC,SAAS;WACV;;WAEA,KAAK;;WAEL,QAAQ,eAAe,UAAU;WACjC,UAAU,eAAe;WACzB,YAAY,eAAe;;;;;;;;;;;;;WAa3B,gBAAgB;;WAEhB;;WAEA;;;KAIC,oBAAoB,eAAe,WAAW;;WAE/C;aAAmB;aAA0B;;;WAE7C;aAAmB;aAA2B;;WAC9C,QAAQ;WACR,QAAQ,eAAe,SAAS,cAAc;;;KAI7C;;WAED,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAudR,qBAAqB,eAAe,WAAW,sBAC7D,OAAO,oBAAoB,SAC3B,UAAU,wBACT,SAAS"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as validateContract } from "../validate-
|
|
2
|
-
import { i as warnDroppedRelation, n as isValidIdbKeyCodec, r as literalValueMatchesCodec } from "../psl-interpreter-
|
|
1
|
+
import { t as validateContract } from "../validate-Dt8a97c4.mjs";
|
|
2
|
+
import { a as buildRecordShape, i as warnDroppedRelation, n as isValidIdbKeyCodec, r as literalValueMatchesCodec } from "../psl-interpreter-DgfjFTU2.mjs";
|
|
3
3
|
import { keyPathFields } from "@prisma-idb/target-idb/pack";
|
|
4
4
|
import { UNBOUND_DOMAIN_NAMESPACE_ID, crossRef } from "@prisma/orm-framework/contract/types";
|
|
5
5
|
import { computeProfileHash, computeStorageHash } from "@prisma/orm-framework/contract/hashing";
|
|
@@ -66,6 +66,7 @@ function projectModelsForClient(models) {
|
|
|
66
66
|
}
|
|
67
67
|
return result;
|
|
68
68
|
}
|
|
69
|
+
/** Separate the field type name from nullable and list suffixes. */
|
|
69
70
|
function parseFieldSpec(spec) {
|
|
70
71
|
const nullable = spec.endsWith("?");
|
|
71
72
|
const withoutOptional = nullable ? spec.slice(0, -1) : spec;
|
|
@@ -76,6 +77,7 @@ function parseFieldSpec(spec) {
|
|
|
76
77
|
many
|
|
77
78
|
};
|
|
78
79
|
}
|
|
80
|
+
/** Resolve scalar or enum field declarations to their stored codec. */
|
|
79
81
|
function resolveFieldCodecId(def, fieldName, enums) {
|
|
80
82
|
const spec = def.fields[fieldName];
|
|
81
83
|
if (spec === void 0) return void 0;
|
|
@@ -158,6 +160,7 @@ function validateNoConflictingRelationActions(models) {
|
|
|
158
160
|
}
|
|
159
161
|
}
|
|
160
162
|
}
|
|
163
|
+
/** Translate supported field declarations into domain fields and enum references. */
|
|
161
164
|
function buildFields(fields, enums, namespaceId) {
|
|
162
165
|
const result = {};
|
|
163
166
|
for (const [name, spec] of Object.entries(fields)) {
|
|
@@ -173,7 +176,7 @@ function buildFields(fields, enums, namespaceId) {
|
|
|
173
176
|
kind: "scalar",
|
|
174
177
|
codecId
|
|
175
178
|
},
|
|
176
|
-
...many ? { many:
|
|
179
|
+
...many ? { many: { elementNullable: false } } : {},
|
|
177
180
|
...enumValues !== void 0 ? { valueSet: {
|
|
178
181
|
plane: "domain",
|
|
179
182
|
entityKind: "enum",
|
|
@@ -184,6 +187,7 @@ function buildFields(fields, enums, namespaceId) {
|
|
|
184
187
|
}
|
|
185
188
|
return result;
|
|
186
189
|
}
|
|
190
|
+
/** Validate named string enum members and construct their stored values. */
|
|
187
191
|
function buildEnums(enums) {
|
|
188
192
|
const result = {};
|
|
189
193
|
for (const [name, values] of Object.entries(enums)) {
|
|
@@ -209,6 +213,7 @@ function keepReferencedEnums(enums, models) {
|
|
|
209
213
|
const referenced = new Set(Object.values(models).flatMap((def) => Object.values(def.fields).map((spec) => parseFieldSpec(spec).typeName)));
|
|
210
214
|
return Object.fromEntries(Object.entries(enums).filter(([name]) => referenced.has(name)));
|
|
211
215
|
}
|
|
216
|
+
/** Expose each model under its declared object-store root. */
|
|
212
217
|
function buildRoots(models) {
|
|
213
218
|
const roots = {};
|
|
214
219
|
for (const modelName of Object.keys(models)) {
|
|
@@ -217,9 +222,10 @@ function buildRoots(models) {
|
|
|
217
222
|
}
|
|
218
223
|
return roots;
|
|
219
224
|
}
|
|
220
|
-
|
|
225
|
+
/** Build store metadata and canonical record shapes before computing the storage hash. */
|
|
226
|
+
function buildStores(models, domainModels, enums) {
|
|
221
227
|
const stores = {};
|
|
222
|
-
for (const def of Object.
|
|
228
|
+
for (const [modelName, def] of Object.entries(models)) {
|
|
223
229
|
const indexes = {};
|
|
224
230
|
for (const [indexName, idx] of Object.entries(def.indexes ?? {})) indexes[indexName] = {
|
|
225
231
|
keyPath: idx.keyPath,
|
|
@@ -227,12 +233,14 @@ function buildStores(models) {
|
|
|
227
233
|
...idx.multiEntry !== void 0 ? { multiEntry: idx.multiEntry } : {}
|
|
228
234
|
};
|
|
229
235
|
stores[def.store] = {
|
|
236
|
+
record: buildRecordShape(modelName, domainModels[modelName].fields, { enum: enums }),
|
|
230
237
|
keyPath: def.key,
|
|
231
238
|
...Object.keys(indexes).length > 0 ? { indexes } : {}
|
|
232
239
|
};
|
|
233
240
|
}
|
|
234
241
|
return stores;
|
|
235
242
|
}
|
|
243
|
+
/** Build domain relations and keep referential actions in IDB storage metadata. */
|
|
236
244
|
function buildModels(models, enums, namespaceId) {
|
|
237
245
|
const result = {};
|
|
238
246
|
for (const [modelName, def] of Object.entries(models)) {
|
|
@@ -302,12 +310,13 @@ function defineContract(input, options) {
|
|
|
302
310
|
const domainEnums = projection === "client" ? keepReferencedEnums(validatedEnums, models) : validatedEnums;
|
|
303
311
|
for (const [modelName, def] of Object.entries(models)) validateModelKeyAndIndexes(modelName, def, enums);
|
|
304
312
|
validateNoConflictingRelationActions(models);
|
|
305
|
-
const
|
|
313
|
+
const ns = UNBOUND_DOMAIN_NAMESPACE_ID;
|
|
314
|
+
const domainModels = buildModels(models, enums, ns);
|
|
315
|
+
const stores = buildStores(models, domainModels, domainEnums);
|
|
306
316
|
const capabilities = { idb: {
|
|
307
317
|
ddlOnlyInUpgrade: true,
|
|
308
318
|
transactionalDDL: true
|
|
309
319
|
} };
|
|
310
|
-
const ns = UNBOUND_DOMAIN_NAMESPACE_ID;
|
|
311
320
|
const storageBlock = {
|
|
312
321
|
stores,
|
|
313
322
|
namespaces: { [ns]: {
|
|
@@ -330,7 +339,7 @@ function defineContract(input, options) {
|
|
|
330
339
|
storageHash
|
|
331
340
|
};
|
|
332
341
|
const domain = { namespaces: { [ns]: {
|
|
333
|
-
models:
|
|
342
|
+
models: domainModels,
|
|
334
343
|
...Object.keys(domainEnums).length > 0 ? { enum: domainEnums } : {}
|
|
335
344
|
} } };
|
|
336
345
|
const contract = {
|