@prisma-idb/sync-server 0.3.2 → 0.4.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/dist/postgres.d.mts.map +1 -1
- package/dist/postgres.mjs +28 -3
- package/dist/postgres.mjs.map +1 -1
- package/dist/schema.d.mts.map +1 -1
- package/dist/schema.mjs +1 -1
- package/dist/{sql-contract-Dk216Tf3.mjs → sql-contract-0ZmfUgDg.mjs} +11 -19
- package/dist/sql-contract-0ZmfUgDg.mjs.map +1 -0
- package/package.json +6 -6
- package/dist/sql-contract-Dk216Tf3.mjs.map +0 -1
package/dist/postgres.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.mts","names":[],"sources":["../src/exports/postgres.ts"],"mappings":";;UAYiB;;WAEN;;;;;;WAMA;WACA;aAAgB;;WAChB;aAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"postgres.d.mts","names":[],"sources":["../src/exports/postgres.ts"],"mappings":";;UAYiB;;WAEN;;;;;;WAMA;WACA;aAAgB;;WAChB;aAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkDnB,aAAa,SAAS,4BAA4B"}
|
package/dist/postgres.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as sqlContractWithSync } from "./sql-contract-
|
|
1
|
+
import { t as sqlContractWithSync } from "./sql-contract-0ZmfUgDg.mjs";
|
|
2
2
|
import { defineConfig as defineConfig$1 } from "@prisma/orm-framework/config/config-types";
|
|
3
3
|
import { ifDefined } from "@prisma/orm-framework/utils/defined";
|
|
4
4
|
import postgresAdapter from "@prisma/orm-postgres/adapter/control";
|
|
5
|
-
import { PG_INT_CODEC_ID, PG_TEXT_CODEC_ID } from "@prisma/orm-postgres/target/codec-ids";
|
|
5
|
+
import { PG_INT_CODEC_ID, PG_TEXT_CODEC_ID, PG_TIMESTAMPTZ_DATE_CODEC_ID } from "@prisma/orm-postgres/target/codec-ids";
|
|
6
6
|
import postgresDriver from "@prisma/orm-postgres/driver/control";
|
|
7
7
|
import sql from "@prisma/orm-postgres/family/control";
|
|
8
8
|
import postgres from "@prisma/orm-postgres/target/control";
|
|
@@ -10,6 +10,31 @@ import postgresPackRef from "@prisma/orm-postgres/target/pack";
|
|
|
10
10
|
import { postgresCreateNamespace } from "@prisma/orm-postgres/target/types";
|
|
11
11
|
//#region src/exports/postgres.ts
|
|
12
12
|
/**
|
|
13
|
+
* `@prisma/orm-postgres`'s adapter with PSL `DateTime` bound to the JS-`Date`
|
|
14
|
+
* codec. From rc.12 the stock adapter binds it to `pg/timestamptz-temporal@1`,
|
|
15
|
+
* which throws on decode unless the runtime has a global `Temporal` (Node 24
|
|
16
|
+
* LTS does not) and hands back `Temporal.Instant`s where every IDB client
|
|
17
|
+
* reads and writes `Date`s. Same `timestamptz` column either way, so this
|
|
18
|
+
* changes the JS representation only, not the database schema.
|
|
19
|
+
*/
|
|
20
|
+
const syncPostgresAdapter = {
|
|
21
|
+
...postgresAdapter,
|
|
22
|
+
authoring: {
|
|
23
|
+
...postgresAdapter.authoring,
|
|
24
|
+
type: {
|
|
25
|
+
...postgresAdapter.authoring?.type,
|
|
26
|
+
DateTime: {
|
|
27
|
+
kind: "typeConstructor",
|
|
28
|
+
documentation: "An instant stored as PostgreSQL timestamptz and represented as a JavaScript Date.",
|
|
29
|
+
output: {
|
|
30
|
+
codecId: PG_TIMESTAMPTZ_DATE_CODEC_ID,
|
|
31
|
+
nativeType: "timestamptz"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
13
38
|
* The Postgres-target config for a sync server: wires `@prisma/orm-postgres`'s
|
|
14
39
|
* family/target/adapter/driver descriptors and {@link sqlContractWithSync}
|
|
15
40
|
* through the core `defineConfig` (`@prisma/orm-framework/config/config-types`)
|
|
@@ -37,7 +62,7 @@ function defineConfig(options) {
|
|
|
37
62
|
return defineConfig$1({
|
|
38
63
|
family: sql,
|
|
39
64
|
target: postgres,
|
|
40
|
-
adapter:
|
|
65
|
+
adapter: syncPostgresAdapter,
|
|
41
66
|
driver: postgresDriver,
|
|
42
67
|
contract: sqlContractWithSync(options.schema, {
|
|
43
68
|
target: postgresPackRef,
|
package/dist/postgres.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.mjs","names":["coreDefineConfig"],"sources":["../src/exports/postgres.ts"],"sourcesContent":["import type { PrismaNextConfig } from \"@prisma/orm-framework/config/config-types\";\nimport { defineConfig as coreDefineConfig } from \"@prisma/orm-framework/config/config-types\";\nimport { ifDefined } from \"@prisma/orm-framework/utils/defined\";\nimport postgresAdapter from \"@prisma/orm-postgres/adapter/control\";\nimport { PG_INT_CODEC_ID, PG_TEXT_CODEC_ID } from \"@prisma/orm-postgres/target/codec-ids\";\nimport postgresDriver from \"@prisma/orm-postgres/driver/control\";\nimport sql from \"@prisma/orm-postgres/family/control\";\nimport postgres from \"@prisma/orm-postgres/target/control\";\nimport postgresPackRef from \"@prisma/orm-postgres/target/pack\";\nimport { postgresCreateNamespace } from \"@prisma/orm-postgres/target/types\";\nimport { sqlContractWithSync } from \"../core/sql-contract\";\n\nexport interface PostgresSyncConfigOptions {\n /** Path to the shared `schema.prisma` — the same file the browser/IDB config parses. */\n readonly schema: string;\n /**\n * Defaults to deriving from `schema`'s own directory (e.g.\n * `src/lib/prisma/contract.json`). Override this when that collides with\n * an IDB-family `contract.json` living alongside it.\n */\n readonly output?: string;\n readonly db?: { readonly connection?: string };\n readonly migrations?: { readonly dir?: string };\n}\n\n/**\n * The Postgres-target config for a sync server: wires `@prisma/orm-postgres`'s\n * family/target/adapter/driver descriptors and {@link sqlContractWithSync}\n * through the core `defineConfig` (`@prisma/orm-framework/config/config-types`)\n * for you. That wiring can't go through `@prisma/orm-postgres/config`'s own\n * `defineConfig` — its `contract` option only accepts a schema path and\n * builds its own internal `prismaContract(...)` call, so it can't take\n * `sqlContractWithSync`'s `ContractConfig` return value.\n *\n * @example\n * ```ts\n * import { definePrismaConfig } from \"@prisma/cli-engine\";\n * import { defineConfig } from \"@prisma-idb/sync-server/postgres\";\n *\n * export default definePrismaConfig({\n * orm: defineConfig({\n * schema: \"src/lib/prisma/schema.prisma\",\n * output: \"src/lib/prisma/schema.postgres.generated.json\",\n * db: { connection: process.env.DATABASE_URL },\n * migrations: { dir: \"migrations-postgres\" },\n * }),\n * });\n * ```\n */\nexport function defineConfig(options: PostgresSyncConfigOptions): PrismaNextConfig<\"sql\", \"postgres\"> {\n return coreDefineConfig({\n family: sql,\n target: postgres,\n adapter:
|
|
1
|
+
{"version":3,"file":"postgres.mjs","names":["coreDefineConfig"],"sources":["../src/exports/postgres.ts"],"sourcesContent":["import type { PrismaNextConfig } from \"@prisma/orm-framework/config/config-types\";\nimport { defineConfig as coreDefineConfig } from \"@prisma/orm-framework/config/config-types\";\nimport { ifDefined } from \"@prisma/orm-framework/utils/defined\";\nimport postgresAdapter from \"@prisma/orm-postgres/adapter/control\";\nimport { PG_INT_CODEC_ID, PG_TEXT_CODEC_ID, PG_TIMESTAMPTZ_DATE_CODEC_ID } from \"@prisma/orm-postgres/target/codec-ids\";\nimport postgresDriver from \"@prisma/orm-postgres/driver/control\";\nimport sql from \"@prisma/orm-postgres/family/control\";\nimport postgres from \"@prisma/orm-postgres/target/control\";\nimport postgresPackRef from \"@prisma/orm-postgres/target/pack\";\nimport { postgresCreateNamespace } from \"@prisma/orm-postgres/target/types\";\nimport { sqlContractWithSync } from \"../core/sql-contract\";\n\nexport interface PostgresSyncConfigOptions {\n /** Path to the shared `schema.prisma` — the same file the browser/IDB config parses. */\n readonly schema: string;\n /**\n * Defaults to deriving from `schema`'s own directory (e.g.\n * `src/lib/prisma/contract.json`). Override this when that collides with\n * an IDB-family `contract.json` living alongside it.\n */\n readonly output?: string;\n readonly db?: { readonly connection?: string };\n readonly migrations?: { readonly dir?: string };\n}\n\n/**\n * `@prisma/orm-postgres`'s adapter with PSL `DateTime` bound to the JS-`Date`\n * codec. From rc.12 the stock adapter binds it to `pg/timestamptz-temporal@1`,\n * which throws on decode unless the runtime has a global `Temporal` (Node 24\n * LTS does not) and hands back `Temporal.Instant`s where every IDB client\n * reads and writes `Date`s. Same `timestamptz` column either way, so this\n * changes the JS representation only, not the database schema.\n */\nconst syncPostgresAdapter: typeof postgresAdapter = {\n ...postgresAdapter,\n authoring: {\n ...postgresAdapter.authoring,\n type: {\n ...postgresAdapter.authoring?.type,\n DateTime: {\n kind: \"typeConstructor\",\n documentation: \"An instant stored as PostgreSQL timestamptz and represented as a JavaScript Date.\",\n output: { codecId: PG_TIMESTAMPTZ_DATE_CODEC_ID, nativeType: \"timestamptz\" },\n },\n },\n },\n};\n\n/**\n * The Postgres-target config for a sync server: wires `@prisma/orm-postgres`'s\n * family/target/adapter/driver descriptors and {@link sqlContractWithSync}\n * through the core `defineConfig` (`@prisma/orm-framework/config/config-types`)\n * for you. That wiring can't go through `@prisma/orm-postgres/config`'s own\n * `defineConfig` — its `contract` option only accepts a schema path and\n * builds its own internal `prismaContract(...)` call, so it can't take\n * `sqlContractWithSync`'s `ContractConfig` return value.\n *\n * @example\n * ```ts\n * import { definePrismaConfig } from \"@prisma/cli-engine\";\n * import { defineConfig } from \"@prisma-idb/sync-server/postgres\";\n *\n * export default definePrismaConfig({\n * orm: defineConfig({\n * schema: \"src/lib/prisma/schema.prisma\",\n * output: \"src/lib/prisma/schema.postgres.generated.json\",\n * db: { connection: process.env.DATABASE_URL },\n * migrations: { dir: \"migrations-postgres\" },\n * }),\n * });\n * ```\n */\nexport function defineConfig(options: PostgresSyncConfigOptions): PrismaNextConfig<\"sql\", \"postgres\"> {\n return coreDefineConfig({\n family: sql,\n target: postgres,\n adapter: syncPostgresAdapter,\n driver: postgresDriver,\n contract: sqlContractWithSync(options.schema, {\n target: postgresPackRef,\n createNamespace: postgresCreateNamespace,\n enumInferenceCodecs: { text: PG_TEXT_CODEC_ID, int: PG_INT_CODEC_ID },\n ...ifDefined(\"output\", options.output),\n }),\n ...ifDefined(\"db\", options.db),\n ...ifDefined(\"migrations\", options.migrations),\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiCA,MAAM,sBAA8C;CAClD,GAAG;CACH,WAAW;EACT,GAAG,gBAAgB;EACnB,MAAM;GACJ,GAAG,gBAAgB,WAAW;GAC9B,UAAU;IACR,MAAM;IACN,eAAe;IACf,QAAQ;KAAE,SAAS;KAA8B,YAAY;IAAc;GAC7E;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,aAAa,SAAyE;CACpG,OAAOA,eAAiB;EACtB,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,QAAQ;EACR,UAAU,oBAAoB,QAAQ,QAAQ;GAC5C,QAAQ;GACR,iBAAiB;GACjB,qBAAqB;IAAE,MAAM;IAAkB,KAAK;GAAgB;GACpE,GAAG,UAAU,UAAU,QAAQ,MAAM;EACvC,CAAC;EACD,GAAG,UAAU,MAAM,QAAQ,EAAE;EAC7B,GAAG,UAAU,cAAc,QAAQ,UAAU;CAC/C,CAAC;AACH"}
|
package/dist/schema.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.mts","names":[],"sources":["../src/core/changelog-schema.ts","../src/core/sql-contract.ts"],"mappings":";;;;iBA4DgB,wBAAwB;;;;;;;;;;iBAaxB,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"schema.d.mts","names":[],"sources":["../src/core/changelog-schema.ts","../src/core/sql-contract.ts"],"mappings":";;;;iBA4DgB,wBAAwB;;;;;;;;;;iBAaxB,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCtCzB,oBAAoB,oBAAoB,SAAS,wBAAwB"}
|
package/dist/schema.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as injectChangelogModelSql, r as prepareSqlSchemaWithSync, t as sqlContractWithSync } from "./sql-contract-
|
|
1
|
+
import { n as injectChangelogModelSql, r as prepareSqlSchemaWithSync, t as sqlContractWithSync } from "./sql-contract-0ZmfUgDg.mjs";
|
|
2
2
|
export { injectChangelogModelSql, prepareSqlSchemaWithSync, sqlContractWithSync };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { stripIdbExcludeAttributes } from "@prisma-idb/family-idb/contract-psl";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { buildSymbolTable,
|
|
3
|
+
import { buildSymbolTable, mapPslDiagnostics } from "@prisma/orm-framework/psl-parser";
|
|
4
4
|
import { hasPslInterpreter, withSeedDiagnostics } from "@prisma/orm-framework/psl-parser/interpret";
|
|
5
5
|
import { parse } from "@prisma/orm-framework/psl-parser/syntax";
|
|
6
6
|
import { notOk, ok } from "@prisma/orm-framework/utils/result";
|
|
@@ -81,14 +81,6 @@ function prepareSqlSchemaWithSync(schema) {
|
|
|
81
81
|
}
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/core/sql-contract.ts
|
|
84
|
-
function mapParseDiagnostics(diagnostics, sourceFile, sourceId) {
|
|
85
|
-
return diagnostics.map((d) => ({
|
|
86
|
-
code: d.code,
|
|
87
|
-
message: d.message,
|
|
88
|
-
sourceId,
|
|
89
|
-
span: rangeToPslSpan(d.range, sourceFile)
|
|
90
|
-
}));
|
|
91
|
-
}
|
|
92
84
|
/**
|
|
93
85
|
* Reads `schemaPath` once, runs it through `prepareSqlSchemaWithSync`, and
|
|
94
86
|
* hands the *text* straight to the SQL family's own parse → interpret →
|
|
@@ -140,18 +132,18 @@ function sqlContractWithSync(schemaPath, options) {
|
|
|
140
132
|
});
|
|
141
133
|
}
|
|
142
134
|
const schema = prepareSqlSchemaWithSync(raw);
|
|
143
|
-
const { document,
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
135
|
+
const { document, sources, diagnostics: parseDiagnostics } = parse(schema, schemaPath);
|
|
136
|
+
const documents = [document];
|
|
137
|
+
const { symbolTable, diagnostics: symbolTableDiagnostics } = buildSymbolTable({
|
|
138
|
+
documents,
|
|
139
|
+
sources,
|
|
147
140
|
pslBlockDescriptors: context.authoringContributions.pslBlockDescriptors
|
|
148
141
|
});
|
|
149
|
-
const seedDiagnostics = [...
|
|
142
|
+
const seedDiagnostics = mapPslDiagnostics([...parseDiagnostics, ...symbolTableDiagnostics], sources);
|
|
150
143
|
const interpreted = withSeedDiagnostics(interpret({
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
symbolTable
|
|
154
|
-
sourceId: schemaPath
|
|
144
|
+
documents,
|
|
145
|
+
sources,
|
|
146
|
+
symbolTable
|
|
155
147
|
}, context), seedDiagnostics);
|
|
156
148
|
if (!interpreted.ok) return interpreted;
|
|
157
149
|
return ok(applySqlSpecifierControlPolicy(interpreted.value, options.defaultControlPolicy, options.createNamespace));
|
|
@@ -162,4 +154,4 @@ function sqlContractWithSync(schemaPath, options) {
|
|
|
162
154
|
//#endregion
|
|
163
155
|
export { injectChangelogModelSql as n, prepareSqlSchemaWithSync as r, sqlContractWithSync as t };
|
|
164
156
|
|
|
165
|
-
//# sourceMappingURL=sql-contract-
|
|
157
|
+
//# sourceMappingURL=sql-contract-0ZmfUgDg.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-contract-0ZmfUgDg.mjs","names":[],"sources":["../src/core/changelog-schema.ts","../src/core/sql-contract.ts"],"sourcesContent":["import { stripIdbExcludeAttributes } from \"@prisma-idb/family-idb/contract-psl\";\n\n/**\n * Synthetic `Changelog` model, appended to the raw PSL text of a server\n * contract (never the client one) so a consumer never hand-authors it —\n * the old generator required an exact 6-field model + a matching enum and\n * threw one of a dozen validation errors if either drifted.\n *\n * `id` is a real DB-generated `autoincrement()` — no client ever creates a\n * `Changelog` row, this is server-only bookkeeping, so there's no reason\n * to hand it a client-style id. `keyPath` is `String`, not `Json`: every\n * model this package's own consumers sync uses a single-field `String`\n * key today (no compound keys), so there's nothing to store as JSON, and\n * — confirmed directly against a real Postgres run — this target's\n * `pg/jsonb@1` codec doesn't decode correctly in the currently-published\n * `@prisma/orm-postgres` version (every other codec, including the enum,\n * decodes fine). `String` sidesteps a real gap rather than working around\n * it blindly. If a future consumer needs a genuinely compound/JSON-shaped\n * key, this is the function to fork, not patch — it'd change\n * `sync-server`'s own `key: unknown` handling too, not just this schema\n * fragment.\n *\n * The enum deliberately has no `@@type(...)` codec pragma — confirmed\n * empirically (a throwaway `contract emit` against `@prisma/orm-postgres`)\n * that omitting it still resolves to `pg/text@1`, because\n * `@prisma/orm-postgres/config`'s `defineConfig` already sets\n * `enumInferenceCodecs: { text: PG_TEXT_CODEC_ID, ... }` — the *target*\n * supplies that default, not the schema text. Hardcoding `@@type(\"pg/text@1\")`\n * here would have been redundant against Postgres and actively wrong\n * against a different SQL target (e.g. a future SQLite one, whose\n * own inference default isn't a `pg/*` codec) — this function is named\n * `*Sql`, not `*Postgres`, so it shouldn't assume one. This doesn't make it\n * Mongo-portable, to be clear — Mongo's contract-psl is a different PSL\n * dialect entirely (different scalar types, presumably no `enum`/\n * `@default(autoincrement())` the way SQL has them), so this function was\n * never going to apply there regardless; the fix here is about staying\n * agnostic *within* the SQL family (Postgres/SQLite/whatever comes next),\n * which is the scope its name actually promises.\n */\nconst CHANGELOG_MODEL_SQL_PSL = `\nenum ChangeOperation {\n create\n update\n delete\n}\n\nmodel Changelog {\n id Int @id @default(autoincrement())\n model String\n keyPath String\n operation ChangeOperation\n scopeKey String\n outboxEventId String @unique\n createdAt DateTime @default(now())\n\n @@index([scopeKey, id])\n}\n`;\n\n/** Appends the synthetic `Changelog` model to raw PSL schema text. */\nexport function injectChangelogModelSql(schema: string): string {\n return `${schema}\\n${CHANGELOG_MODEL_SQL_PSL}`;\n}\n\n/**\n * The composed step a SQL-family config needs to turn a schema authored\n * for `family-idb` (browser client) into the real server schema: strip\n * `@idb.exclude`/`@@idb.exclude` (meaningless to a real server, and the\n * SQL parser hard-errors on the unrecognized `idb` namespace otherwise —\n * see `stripIdbExcludeAttributes`), then append `Changelog`. See\n * `sqlContractWithSync` for the version that also feeds this straight into\n * the SQL family's own parser, in memory.\n */\nexport function prepareSqlSchemaWithSync(schema: string): string {\n return injectChangelogModelSql(stripIdbExcludeAttributes(schema));\n}\n","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 { hasPslInterpreter, withSeedDiagnostics } from \"@prisma/orm-framework/psl-parser/interpret\";\nimport { parse } from \"@prisma/orm-framework/psl-parser/syntax\";\nimport { notOk, ok } from \"@prisma/orm-framework/utils/result\";\nimport { applySqlSpecifierControlPolicy } from \"@prisma/orm-family-sql/contract-ts/contract-builder\";\nimport { prismaContract, type PrismaContractOptions } from \"@prisma/orm-family-sql/contract-psl/provider\";\nimport { prepareSqlSchemaWithSync } from \"./changelog-schema\";\n\n/**\n * Reads `schemaPath` once, runs it through `prepareSqlSchemaWithSync`, and\n * hands the *text* straight to the SQL family's own parse → interpret →\n * control-policy pipeline — no generated `.prisma` file lands on disk.\n *\n * `@prisma/orm-family-sql`'s own `prismaContract(schemaPath, options)`\n * always `readFile()`s its argument, with no hook to inject text instead\n * (github.com/prisma/orm#30115). This works around that today by\n * decomposing it: call the real `prismaContract` to get a `source` whose\n * `interpret` is the target-specific closure we don't want to reimplement\n * (`options.target`, `options.createNamespace`, etc. all live there), then\n * replace only `load` with a version that transforms the schema text\n * in-memory instead of pointing at a second file. The transformed text\n * still flows through the same parse → symbol-table → interpret →\n * `applySqlSpecifierControlPolicy` steps `prismaContract` itself runs, so\n * `storageHash` and diagnostics behave identically to the file-based path.\n *\n * Note: `@prisma/orm-postgres/config`'s `defineConfig` (and its per-target\n * siblings) only accept a schema *path* for `contract`, not a\n * `ContractConfig` — they build their own `prismaContract(...)` call\n * internally. Passing this function's return value to one of those still\n * requires wiring the family/target/adapter/driver through the core\n * `defineConfig` (`@prisma/orm-framework/config/config-types`) directly\n * instead of the target's convenience wrapper.\n */\nexport function sqlContractWithSync(schemaPath: string, options: PrismaContractOptions): ContractConfig {\n const { source, output } = prismaContract(schemaPath, options);\n if (!hasPslInterpreter(source)) {\n throw new Error(\"sqlContractWithSync: prismaContract() did not return a PSL-capable source.\");\n }\n const { interpret } = source;\n\n return {\n ...(output !== undefined ? { output } : {}),\n source: {\n ...source,\n async load(context) {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n \"sqlContractWithSync: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.\"\n );\n }\n\n let raw: string;\n try {\n raw = 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 const schema = prepareSqlSchemaWithSync(raw);\n\n const { document, sources, diagnostics: parseDiagnostics } = parse(schema, schemaPath);\n const documents = [document];\n const { symbolTable, diagnostics: symbolTableDiagnostics } = buildSymbolTable({\n documents,\n sources,\n pslBlockDescriptors: context.authoringContributions.pslBlockDescriptors,\n });\n\n const seedDiagnostics = mapPslDiagnostics([...parseDiagnostics, ...symbolTableDiagnostics], sources);\n\n const interpreted = withSeedDiagnostics(\n interpret({ documents, sources, symbolTable }, context),\n seedDiagnostics\n );\n if (!interpreted.ok) {\n return interpreted;\n }\n\n return ok(\n applySqlSpecifierControlPolicy(interpreted.value, options.defaultControlPolicy, options.createNamespace)\n );\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;AAqBhC,SAAgB,wBAAwB,QAAwB;CAC9D,OAAO,GAAG,OAAO,IAAI;AACvB;;;;;;;;;;AAWA,SAAgB,yBAAyB,QAAwB;CAC/D,OAAO,wBAAwB,0BAA0B,MAAM,CAAC;AAClE;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxCA,SAAgB,oBAAoB,YAAoB,SAAgD;CACtG,MAAM,EAAE,QAAQ,WAAW,eAAe,YAAY,OAAO;CAC7D,IAAI,CAAC,kBAAkB,MAAM,GAC3B,MAAM,IAAI,MAAM,4EAA4E;CAE9F,MAAM,EAAE,cAAc;CAEtB,OAAO;EACL,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;EACzC,QAAQ;GACN,GAAG;GACH,MAAM,KAAK,SAAS;IAClB,MAAM,CAAC,sBAAsB,QAAQ;IACrC,IAAI,uBAAuB,KAAA,GACzB,MAAM,IAAI,MACR,uIACF;IAGF,IAAI;IACJ,IAAI;KACF,MAAM,MAAM,SAAS,oBAAoB,OAAO;IAClD,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,MAAM,SAAS,yBAAyB,GAAG;IAE3C,MAAM,EAAE,UAAU,SAAS,aAAa,qBAAqB,MAAM,QAAQ,UAAU;IACrF,MAAM,YAAY,CAAC,QAAQ;IAC3B,MAAM,EAAE,aAAa,aAAa,2BAA2B,iBAAiB;KAC5E;KACA;KACA,qBAAqB,QAAQ,uBAAuB;IACtD,CAAC;IAED,MAAM,kBAAkB,kBAAkB,CAAC,GAAG,kBAAkB,GAAG,sBAAsB,GAAG,OAAO;IAEnG,MAAM,cAAc,oBAClB,UAAU;KAAE;KAAW;KAAS;IAAY,GAAG,OAAO,GACtD,eACF;IACA,IAAI,CAAC,YAAY,IACf,OAAO;IAGT,OAAO,GACL,+BAA+B,YAAY,OAAO,QAAQ,sBAAsB,QAAQ,eAAe,CACzG;GACF;EACF;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-idb/sync-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Prisma 8 IDB — sync ownership DAG (server-side push authorization + pull scoping, ADR 014)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"./package.json": "./package.json"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@prisma-idb/family-idb": "0.
|
|
45
|
-
"@prisma/orm-family-sql": "8.0.0-rc.
|
|
46
|
-
"@prisma/orm-framework": "8.0.0-rc.
|
|
47
|
-
"@prisma/orm-postgres": "8.0.0-rc.
|
|
44
|
+
"@prisma-idb/family-idb": "0.8.0",
|
|
45
|
+
"@prisma/orm-family-sql": "8.0.0-rc.12",
|
|
46
|
+
"@prisma/orm-framework": "8.0.0-rc.12",
|
|
47
|
+
"@prisma/orm-postgres": "8.0.0-rc.12"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@prisma-idb/target-idb": "0.
|
|
50
|
+
"@prisma-idb/target-idb": "0.8.0",
|
|
51
51
|
"@types/node": "^24.13.3",
|
|
52
52
|
"tsdown": "^0.22.14",
|
|
53
53
|
"typescript": "^6.0.3",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sql-contract-Dk216Tf3.mjs","names":[],"sources":["../src/core/changelog-schema.ts","../src/core/sql-contract.ts"],"sourcesContent":["import { stripIdbExcludeAttributes } from \"@prisma-idb/family-idb/contract-psl\";\n\n/**\n * Synthetic `Changelog` model, appended to the raw PSL text of a server\n * contract (never the client one) so a consumer never hand-authors it —\n * the old generator required an exact 6-field model + a matching enum and\n * threw one of a dozen validation errors if either drifted.\n *\n * `id` is a real DB-generated `autoincrement()` — no client ever creates a\n * `Changelog` row, this is server-only bookkeeping, so there's no reason\n * to hand it a client-style id. `keyPath` is `String`, not `Json`: every\n * model this package's own consumers sync uses a single-field `String`\n * key today (no compound keys), so there's nothing to store as JSON, and\n * — confirmed directly against a real Postgres run — this target's\n * `pg/jsonb@1` codec doesn't decode correctly in the currently-published\n * `@prisma/orm-postgres` version (every other codec, including the enum,\n * decodes fine). `String` sidesteps a real gap rather than working around\n * it blindly. If a future consumer needs a genuinely compound/JSON-shaped\n * key, this is the function to fork, not patch — it'd change\n * `sync-server`'s own `key: unknown` handling too, not just this schema\n * fragment.\n *\n * The enum deliberately has no `@@type(...)` codec pragma — confirmed\n * empirically (a throwaway `contract emit` against `@prisma/orm-postgres`)\n * that omitting it still resolves to `pg/text@1`, because\n * `@prisma/orm-postgres/config`'s `defineConfig` already sets\n * `enumInferenceCodecs: { text: PG_TEXT_CODEC_ID, ... }` — the *target*\n * supplies that default, not the schema text. Hardcoding `@@type(\"pg/text@1\")`\n * here would have been redundant against Postgres and actively wrong\n * against a different SQL target (e.g. a future SQLite one, whose\n * own inference default isn't a `pg/*` codec) — this function is named\n * `*Sql`, not `*Postgres`, so it shouldn't assume one. This doesn't make it\n * Mongo-portable, to be clear — Mongo's contract-psl is a different PSL\n * dialect entirely (different scalar types, presumably no `enum`/\n * `@default(autoincrement())` the way SQL has them), so this function was\n * never going to apply there regardless; the fix here is about staying\n * agnostic *within* the SQL family (Postgres/SQLite/whatever comes next),\n * which is the scope its name actually promises.\n */\nconst CHANGELOG_MODEL_SQL_PSL = `\nenum ChangeOperation {\n create\n update\n delete\n}\n\nmodel Changelog {\n id Int @id @default(autoincrement())\n model String\n keyPath String\n operation ChangeOperation\n scopeKey String\n outboxEventId String @unique\n createdAt DateTime @default(now())\n\n @@index([scopeKey, id])\n}\n`;\n\n/** Appends the synthetic `Changelog` model to raw PSL schema text. */\nexport function injectChangelogModelSql(schema: string): string {\n return `${schema}\\n${CHANGELOG_MODEL_SQL_PSL}`;\n}\n\n/**\n * The composed step a SQL-family config needs to turn a schema authored\n * for `family-idb` (browser client) into the real server schema: strip\n * `@idb.exclude`/`@@idb.exclude` (meaningless to a real server, and the\n * SQL parser hard-errors on the unrecognized `idb` namespace otherwise —\n * see `stripIdbExcludeAttributes`), then append `Changelog`. See\n * `sqlContractWithSync` for the version that also feeds this straight into\n * the SQL family's own parser, in memory.\n */\nexport function prepareSqlSchemaWithSync(schema: string): string {\n return injectChangelogModelSql(stripIdbExcludeAttributes(schema));\n}\n","import { readFile } from \"node:fs/promises\";\nimport type { ContractConfig, ContractSourceDiagnostic } from \"@prisma/orm-framework/config/config-types\";\nimport { buildSymbolTable, rangeToPslSpan } from \"@prisma/orm-framework/psl-parser\";\nimport { hasPslInterpreter, withSeedDiagnostics } from \"@prisma/orm-framework/psl-parser/interpret\";\nimport type { ParseDiagnostic, SourceFile } from \"@prisma/orm-framework/psl-parser/syntax\";\nimport { parse } from \"@prisma/orm-framework/psl-parser/syntax\";\nimport { notOk, ok } from \"@prisma/orm-framework/utils/result\";\nimport { applySqlSpecifierControlPolicy } from \"@prisma/orm-family-sql/contract-ts/contract-builder\";\nimport { prismaContract, type PrismaContractOptions } from \"@prisma/orm-family-sql/contract-psl/provider\";\nimport { prepareSqlSchemaWithSync } from \"./changelog-schema\";\n\nfunction mapParseDiagnostics(\n diagnostics: readonly ParseDiagnostic[],\n sourceFile: SourceFile,\n sourceId: string\n): ContractSourceDiagnostic[] {\n return diagnostics.map((d) => ({\n code: d.code as string,\n message: d.message,\n sourceId,\n span: rangeToPslSpan(d.range, sourceFile),\n }));\n}\n\n/**\n * Reads `schemaPath` once, runs it through `prepareSqlSchemaWithSync`, and\n * hands the *text* straight to the SQL family's own parse → interpret →\n * control-policy pipeline — no generated `.prisma` file lands on disk.\n *\n * `@prisma/orm-family-sql`'s own `prismaContract(schemaPath, options)`\n * always `readFile()`s its argument, with no hook to inject text instead\n * (github.com/prisma/orm#30115). This works around that today by\n * decomposing it: call the real `prismaContract` to get a `source` whose\n * `interpret` is the target-specific closure we don't want to reimplement\n * (`options.target`, `options.createNamespace`, etc. all live there), then\n * replace only `load` with a version that transforms the schema text\n * in-memory instead of pointing at a second file. The transformed text\n * still flows through the same parse → symbol-table → interpret →\n * `applySqlSpecifierControlPolicy` steps `prismaContract` itself runs, so\n * `storageHash` and diagnostics behave identically to the file-based path.\n *\n * Note: `@prisma/orm-postgres/config`'s `defineConfig` (and its per-target\n * siblings) only accept a schema *path* for `contract`, not a\n * `ContractConfig` — they build their own `prismaContract(...)` call\n * internally. Passing this function's return value to one of those still\n * requires wiring the family/target/adapter/driver through the core\n * `defineConfig` (`@prisma/orm-framework/config/config-types`) directly\n * instead of the target's convenience wrapper.\n */\nexport function sqlContractWithSync(schemaPath: string, options: PrismaContractOptions): ContractConfig {\n const { source, output } = prismaContract(schemaPath, options);\n if (!hasPslInterpreter(source)) {\n throw new Error(\"sqlContractWithSync: prismaContract() did not return a PSL-capable source.\");\n }\n const { interpret } = source;\n\n return {\n ...(output !== undefined ? { output } : {}),\n source: {\n ...source,\n async load(context) {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n \"sqlContractWithSync: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.\"\n );\n }\n\n let raw: string;\n try {\n raw = 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 const schema = prepareSqlSchemaWithSync(raw);\n\n const { document, sourceFile, diagnostics: parseDiagnostics } = parse(schema);\n const { table: symbolTable, diagnostics: symbolTableDiagnostics } = buildSymbolTable({\n document,\n sourceFile,\n pslBlockDescriptors: context.authoringContributions.pslBlockDescriptors,\n });\n\n const seedDiagnostics = [\n ...mapParseDiagnostics(parseDiagnostics, sourceFile, schemaPath),\n ...mapParseDiagnostics(symbolTableDiagnostics, sourceFile, schemaPath),\n ];\n\n const interpreted = withSeedDiagnostics(\n interpret({ document, sourceFile, symbolTable, sourceId: schemaPath }, context),\n seedDiagnostics\n );\n if (!interpreted.ok) {\n return interpreted;\n }\n\n return ok(\n applySqlSpecifierControlPolicy(interpreted.value, options.defaultControlPolicy, options.createNamespace)\n );\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;AAqBhC,SAAgB,wBAAwB,QAAwB;CAC9D,OAAO,GAAG,OAAO,IAAI;AACvB;;;;;;;;;;AAWA,SAAgB,yBAAyB,QAAwB;CAC/D,OAAO,wBAAwB,0BAA0B,MAAM,CAAC;AAClE;;;AChEA,SAAS,oBACP,aACA,YACA,UAC4B;CAC5B,OAAO,YAAY,KAAK,OAAO;EAC7B,MAAM,EAAE;EACR,SAAS,EAAE;EACX;EACA,MAAM,eAAe,EAAE,OAAO,UAAU;CAC1C,EAAE;AACJ;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,oBAAoB,YAAoB,SAAgD;CACtG,MAAM,EAAE,QAAQ,WAAW,eAAe,YAAY,OAAO;CAC7D,IAAI,CAAC,kBAAkB,MAAM,GAC3B,MAAM,IAAI,MAAM,4EAA4E;CAE9F,MAAM,EAAE,cAAc;CAEtB,OAAO;EACL,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;EACzC,QAAQ;GACN,GAAG;GACH,MAAM,KAAK,SAAS;IAClB,MAAM,CAAC,sBAAsB,QAAQ;IACrC,IAAI,uBAAuB,KAAA,GACzB,MAAM,IAAI,MACR,uIACF;IAGF,IAAI;IACJ,IAAI;KACF,MAAM,MAAM,SAAS,oBAAoB,OAAO;IAClD,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,MAAM,SAAS,yBAAyB,GAAG;IAE3C,MAAM,EAAE,UAAU,YAAY,aAAa,qBAAqB,MAAM,MAAM;IAC5E,MAAM,EAAE,OAAO,aAAa,aAAa,2BAA2B,iBAAiB;KACnF;KACA;KACA,qBAAqB,QAAQ,uBAAuB;IACtD,CAAC;IAED,MAAM,kBAAkB,CACtB,GAAG,oBAAoB,kBAAkB,YAAY,UAAU,GAC/D,GAAG,oBAAoB,wBAAwB,YAAY,UAAU,CACvE;IAEA,MAAM,cAAc,oBAClB,UAAU;KAAE;KAAU;KAAY;KAAa,UAAU;IAAW,GAAG,OAAO,GAC9E,eACF;IACA,IAAI,CAAC,YAAY,IACf,OAAO;IAGT,OAAO,GACL,+BAA+B,YAAY,OAAO,QAAQ,sBAAsB,QAAQ,eAAe,CACzG;GACF;EACF;CACF;AACF"}
|