@schemic/core 0.1.0-alpha.0 → 0.1.0-alpha.2
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/lib/authoring.js +2 -0
- package/lib/authoring.js.map +1 -1
- package/lib/{chunk-T23RNU7G.js → chunk-LDKFTPH3.js} +3 -2
- package/lib/{chunk-T23RNU7G.js.map → chunk-LDKFTPH3.js.map} +1 -1
- package/lib/{config-TIiKDd9t.d.ts → config-v3H_2lwA.d.ts} +1 -1
- package/lib/config.d.ts +1 -1
- package/lib/{driver-Dh5hLKHm.d.ts → driver-BTaJ2ryZ.d.ts} +2 -2
- package/lib/driver.d.ts +2 -2
- package/lib/driver.js +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.js +1 -1
- package/lib/testing.d.ts +2 -2
- package/lib/testing.js +1 -1
- package/package.json +1 -1
- package/src/driver/driver.ts +9 -1
package/lib/authoring.js
CHANGED
|
@@ -6,6 +6,8 @@ var SFieldBase = class {
|
|
|
6
6
|
this.schema = schema;
|
|
7
7
|
this.native = native;
|
|
8
8
|
}
|
|
9
|
+
schema;
|
|
10
|
+
native;
|
|
9
11
|
// --- Field-level codec (raw, on `this.schema`): `decode` reads (wire -> app), `encode` writes
|
|
10
12
|
// (app -> wire). Create-shaping is a table concept, so these are NOT create-shaped. ---
|
|
11
13
|
/** Decode a DB value to its app type (wire -> app). */
|
package/lib/authoring.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/authoring.ts"],"sourcesContent":["// The NEUTRAL, dialect-agnostic AUTHORING BASE (docs/AUTHORING-SPLIT.md — \"base builder in core\").\n// Each driver package builds its `s.*` on this: `class <D>Field extends SFieldBase<S, Flags, <D>Meta>`\n// adds the dialect's native authoring (`$`-methods) and its `$<driver>(type, codec)` escape hatch for\n// types not representable on the wire; the base provides the Zod codec, the Zod wrappers, the full\n// `z.*` passthrough, and the `rebuild`/`blank` seam that carries native metadata through a chain.\n//\n// It references NOTHING dialect-specific — it's generic over the per-dialect native-metadata slot `N`.\n// It is also Zod-CLEAN: app-side behaviour delegates to the inner Zod schema (`z.decode`/`z.encode`/\n// the wrappers) via Zod's public API, with side-channel metadata kept on WeakMaps — never patching\n// Zod internals.\n\nimport * as z from \"zod\";\n\n// `SFieldBase` is INVARIANT in its native-metadata slot `N` (the protected `rebuild(native: N)` makes\n// N contravariant while `native`/`blank` make it covariant). So a dialect field — `SField` with\n// `N = SurrealMeta` — is NOT assignable to a fixed `N = unknown`, which would make `AnyField` reject\n// real dialect fields (e.g. `.or(s.int())`). At THIS cross-dialect boundary `N` is honestly \"any\n// dialect's metadata\": erase it to `any` (bivariant) so every driver's field is an `AnyField`. The\n// concrete `N` is preserved everywhere it matters — each driver's own field type keeps `N = <D>Meta`.\n\n/** Any field of ANY dialect — the base type the helpers + wrappers accept. */\n// biome-ignore lint/suspicious/noExplicitAny: cross-dialect erasure of the invariant native slot N.\nexport type AnyField = SFieldBase<z.ZodType, string, any>;\n\n/** The Zod schema a field (or a raw Zod schema) carries. */\nexport type SchemaOf<F> =\n // biome-ignore lint/suspicious/noExplicitAny: match a field of any dialect (N is invariant).\n F extends SFieldBase<infer S, string, any>\n ? S\n : F extends z.ZodType\n ? F\n : never;\n\n/** The `Flags` channel a field carries (driver `$`-methods brand it; widens to `string` for `Shape`). */\nexport type FlagsOf<F> =\n // biome-ignore lint/suspicious/noExplicitAny: match a field of any dialect (N is invariant).\n F extends SFieldBase<z.ZodType, infer Fl, any> ? Fl : never;\n\n/** The schema one wrapper down — what `unwrap()` returns. */\nexport type InnerOf<S extends z.ZodType> =\n S extends z.ZodOptional<infer I extends z.ZodType>\n ? I\n : S extends z.ZodNullable<infer I extends z.ZodType>\n ? I\n : S extends z.ZodDefault<infer I extends z.ZodType>\n ? I\n : S extends z.ZodPrefault<infer I extends z.ZodType>\n ? I\n : S extends z.ZodCatch<infer I extends z.ZodType>\n ? I\n : S extends z.ZodReadonly<infer I extends z.ZodType>\n ? I\n : S extends z.ZodArray<infer I extends z.ZodType>\n ? I\n : S;\n\n/**\n * Maps an object schema (built via a driver's `s.object`) to its original field shape, so nested\n * fields keep their authoring metadata through generation. Kept on the schema, not the field, so it\n * composes through `array()`/`optional()`/nesting.\n */\nexport const objectFieldsRegistry = new WeakMap<\n z.ZodType,\n Record<string, AnyField>\n>();\n\n/**\n * The PORTABLE, dialect-agnostic field base. Holds the Zod schema, an opaque per-dialect `native`\n * metadata slot, the field-level codecs, and the app-land Zod wrappers (which carry `native` forward\n * via the `rebuild` hook so a chain keeps its concrete dialect type). Each dialect subclasses it to\n * add native authoring (`$`-methods) and re-type the wrappers so a chain stays its own field type.\n */\nexport abstract class SFieldBase<\n S extends z.ZodType = z.ZodType,\n Flags extends string = never,\n N = unknown,\n> {\n constructor(\n readonly schema: S,\n readonly native: N,\n ) {}\n\n /** Rebuild a sibling field of the SAME dialect with a new schema/flags. Each dialect overrides it. */\n protected abstract rebuild<S2 extends z.ZodType, F2 extends string>(\n schema: S2,\n native: N,\n ): SFieldBase<S2, F2, N>;\n /** A fresh, empty native-metadata bag (for wrappers like `or`/`and` that reset it). */\n protected abstract blank(): N;\n\n // --- Field-level codec (raw, on `this.schema`): `decode` reads (wire -> app), `encode` writes\n // (app -> wire). Create-shaping is a table concept, so these are NOT create-shaped. ---\n /** Decode a DB value to its app type (wire -> app). */\n decode(value: unknown): z.output<S> {\n return z.decode(this.schema, value as never);\n }\n /** Encode an app value to its DB wire type (app -> wire). */\n encode(value: z.output<S>): z.input<S> {\n return z.encode(this.schema, value);\n }\n decodeAsync(value: unknown): Promise<z.output<S>> {\n return z.decodeAsync(this.schema, value as never);\n }\n encodeAsync(value: z.output<S>): Promise<z.input<S>> {\n return z.encodeAsync(this.schema, value);\n }\n safeDecode(value: unknown) {\n return z.safeDecode(this.schema, value as never);\n }\n safeEncode(value: z.output<S>) {\n return z.safeEncode(this.schema, value);\n }\n safeDecodeAsync(value: unknown) {\n return z.safeDecodeAsync(this.schema, value as never);\n }\n safeEncodeAsync(value: z.output<S>) {\n return z.safeEncodeAsync(this.schema, value);\n }\n // Deprecated Zod-style aliases — `parse` runs the DECODE direction (wire -> app).\n /** @deprecated `parse` decodes a value (wire -> app). Use {@link decode}. */\n parse(value: unknown): z.output<S> {\n return this.decode(value);\n }\n /** @deprecated Use {@link safeDecode}. */\n safeParse(value: unknown) {\n return this.safeDecode(value);\n }\n /** @deprecated Use {@link decodeAsync}. */\n parseAsync(value: unknown): Promise<z.output<S>> {\n return this.decodeAsync(value);\n }\n /** @deprecated Use {@link safeDecodeAsync}. */\n safeParseAsync(value: unknown) {\n return this.safeDecodeAsync(value);\n }\n\n // Zod wrappers — delegate to the inner schema, carry native metadata + flags forward.\n optional(): SFieldBase<z.ZodOptional<S>, Flags, N> {\n return this.rebuild(this.schema.optional(), this.native);\n }\n nullable(): SFieldBase<z.ZodNullable<S>, Flags, N> {\n return this.rebuild(this.schema.nullable(), this.native);\n }\n default(value: z.input<S>): SFieldBase<z.ZodDefault<S>, Flags, N> {\n return this.rebuild(this.schema.default(value as never), this.native);\n }\n /** Zod prefault: fill an absent value with `value`, then validate it (unlike `.default`). */\n prefault(value: z.input<S>): SFieldBase<z.ZodPrefault<S>, Flags, N> {\n return this.rebuild(z.prefault(this.schema, value as never), this.native);\n }\n /** Zod catch: fall back to `value` when parsing fails. */\n catch(value: z.output<S>): SFieldBase<z.ZodCatch<S>, Flags, N> {\n return this.rebuild(this.schema.catch(value as never), this.native);\n }\n array(): SFieldBase<z.ZodArray<S>, Flags, N> {\n return this.rebuild(z.array(this.schema), this.native);\n }\n nullish(): SFieldBase<z.ZodOptional<z.ZodNullable<S>>, Flags, N> {\n return this.rebuild(this.schema.nullish(), this.native);\n }\n /** Zod union — `a.or(b)` accepts either. Mirrors Zod's `.or()`. */\n or<F extends AnyField | z.ZodType>(\n other: F,\n ): SFieldBase<z.ZodUnion<[S, SchemaOf<F>]>, never, N> {\n return this.rebuild<z.ZodUnion<[S, SchemaOf<F>]>, never>(\n z.union([this.schema, toZod(other)]) as z.ZodUnion<[S, SchemaOf<F>]>,\n this.blank(),\n );\n }\n /** Zod intersection — `a.and(b)`. Mirrors Zod's `.and()`. */\n and<F extends AnyField | z.ZodType>(\n other: F,\n ): SFieldBase<z.ZodIntersection<S, SchemaOf<F>>, never, N> {\n return this.rebuild<z.ZodIntersection<S, SchemaOf<F>>, never>(\n z.intersection(this.schema, toZod(other) as SchemaOf<F>),\n this.blank(),\n );\n }\n\n // --- Native Zod passthrough (drop-in for `z.*`): app-side validation / transform / metadata,\n // delegated to the inner schema. The dialect-DDL side stays under the driver's `$`-methods. ---\n refine(\n check: (arg: z.output<S>) => unknown,\n params?: string | z.core.$ZodCustomParams,\n ): this {\n return this.rebuild(\n this.schema.refine(check, params) as S,\n this.native,\n ) as unknown as this;\n }\n superRefine(\n refinement: (\n arg: z.output<S>,\n ctx: z.core.$RefinementCtx<z.output<S>>,\n ) => void,\n ): this {\n return this.rebuild(\n this.schema.superRefine(refinement) as S,\n this.native,\n ) as unknown as this;\n }\n check(\n ...checks: (z.core.CheckFn<z.output<S>> | z.core.$ZodCheck<z.output<S>>)[]\n ): this {\n return this.rebuild(\n this.schema.check(...checks) as S,\n this.native,\n ) as unknown as this;\n }\n overwrite(fn: (x: z.output<S>) => z.output<S>): this {\n return this.rebuild(\n this.schema.overwrite(fn) as S,\n this.native,\n ) as unknown as this;\n }\n brand<B extends PropertyKey = PropertyKey>(value?: B): this {\n return this.rebuild(\n this.schema.brand(value) as unknown as S,\n this.native,\n ) as unknown as this;\n }\n /** Zod's app-side metadata (JSON-schema/docs) — distinct from a driver's `$comment()`. */\n describe(description: string): this {\n return this.rebuild(\n this.schema.describe(description) as S,\n this.native,\n ) as unknown as this;\n }\n meta(data: z.core.GlobalMeta): this {\n return this.rebuild(\n this.schema.meta(data) as S,\n this.native,\n ) as unknown as this;\n }\n /** Zod's app-side readonly (TS-immutable output) — distinct from a driver's `$readonly()`. */\n readonly(): SFieldBase<z.ZodReadonly<S>, Flags, N> {\n return this.rebuild(this.schema.readonly(), this.native);\n }\n /** Zod transform — changes the decoded `App<>` value; the stored (wire) type is unchanged. */\n transform<NewOut>(\n fn: (arg: z.output<S>, ctx: z.core.$RefinementCtx<z.output<S>>) => NewOut,\n ): SFieldBase<\n z.ZodPipe<S, z.ZodTransform<Awaited<NewOut>, z.output<S>>>,\n Flags,\n N\n > {\n return this.rebuild(this.schema.transform(fn), this.native);\n }\n /** Zod pipe — feed this field's output into `target`; the stored (wire) type stays `this`. */\n pipe<T extends z.core.$ZodType<unknown, z.output<S>>>(\n target: T,\n ): SFieldBase<z.ZodPipe<S, T>, Flags, N> {\n return this.rebuild(\n this.schema.pipe(target) as z.ZodPipe<S, T>,\n this.native,\n );\n }\n /** Peel one wrapper (optional/nullable/default/prefault/catch/readonly/array) off the field. */\n unwrap(): SFieldBase<InnerOf<S>, Flags, N> {\n const def = this.schema._zod.def as {\n innerType?: z.ZodType;\n element?: z.ZodType;\n };\n const inner = def.innerType ?? def.element ?? this.schema;\n return this.rebuild(inner, this.native) as unknown as SFieldBase<\n InnerOf<S>,\n Flags,\n N\n >;\n }\n\n /** Object-only: allow arbitrary extra keys — `FLEXIBLE` in DDL. Mirrors Zod's `.loose()`. */\n loose(): this {\n return this.objectMode(\"loose\");\n }\n /** Object-only: reject unknown keys — the default. Mirrors Zod's `.strict()`. */\n strict(): this {\n return this.objectMode(\"strict\");\n }\n /** Alias for {@link loose} — a `FLEXIBLE` object accepting arbitrary keys. */\n flexible(): this {\n return this.loose();\n }\n private objectMode(mode: \"loose\" | \"strict\"): this {\n const obj = this.schema as unknown as {\n loose?: () => z.ZodType;\n strict?: () => z.ZodType;\n };\n if (typeof obj.loose !== \"function\" || typeof obj.strict !== \"function\") {\n return this; // not an object schema — no-op\n }\n const next = (mode === \"loose\"\n ? obj.loose()\n : obj.strict()) as unknown as S;\n // Carry the nested-field registry forward so DDL/create-shaping still see the subfields.\n const fields = objectFieldsRegistry.get(this.schema);\n if (fields) objectFieldsRegistry.set(next, fields);\n return this.rebuild(next, this.native) as unknown as this;\n }\n}\n\n/** Unwrap a field to its Zod schema (raw Zod schemas pass through). */\nexport const toZod = (v: AnyField | z.ZodType): z.ZodType =>\n v instanceof SFieldBase ? v.schema : v;\n"],"mappings":";AAWA,YAAY,OAAO;AAkDZ,IAAM,uBAAuB,oBAAI,QAGtC;AAQK,IAAe,aAAf,MAIL;AAAA,EACA,YACW,QACA,QACT;AAFS;AACA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAaH,OAAO,OAA6B;AAClC,WAAS,SAAO,KAAK,QAAQ,KAAc;AAAA,EAC7C;AAAA;AAAA,EAEA,OAAO,OAAgC;AACrC,WAAS,SAAO,KAAK,QAAQ,KAAK;AAAA,EACpC;AAAA,EACA,YAAY,OAAsC;AAChD,WAAS,cAAY,KAAK,QAAQ,KAAc;AAAA,EAClD;AAAA,EACA,YAAY,OAAyC;AACnD,WAAS,cAAY,KAAK,QAAQ,KAAK;AAAA,EACzC;AAAA,EACA,WAAW,OAAgB;AACzB,WAAS,aAAW,KAAK,QAAQ,KAAc;AAAA,EACjD;AAAA,EACA,WAAW,OAAoB;AAC7B,WAAS,aAAW,KAAK,QAAQ,KAAK;AAAA,EACxC;AAAA,EACA,gBAAgB,OAAgB;AAC9B,WAAS,kBAAgB,KAAK,QAAQ,KAAc;AAAA,EACtD;AAAA,EACA,gBAAgB,OAAoB;AAClC,WAAS,kBAAgB,KAAK,QAAQ,KAAK;AAAA,EAC7C;AAAA;AAAA;AAAA,EAGA,MAAM,OAA6B;AACjC,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA;AAAA,EAEA,UAAU,OAAgB;AACxB,WAAO,KAAK,WAAW,KAAK;AAAA,EAC9B;AAAA;AAAA,EAEA,WAAW,OAAsC;AAC/C,WAAO,KAAK,YAAY,KAAK;AAAA,EAC/B;AAAA;AAAA,EAEA,eAAe,OAAgB;AAC7B,WAAO,KAAK,gBAAgB,KAAK;AAAA,EACnC;AAAA;AAAA,EAGA,WAAmD;AACjD,WAAO,KAAK,QAAQ,KAAK,OAAO,SAAS,GAAG,KAAK,MAAM;AAAA,EACzD;AAAA,EACA,WAAmD;AACjD,WAAO,KAAK,QAAQ,KAAK,OAAO,SAAS,GAAG,KAAK,MAAM;AAAA,EACzD;AAAA,EACA,QAAQ,OAA0D;AAChE,WAAO,KAAK,QAAQ,KAAK,OAAO,QAAQ,KAAc,GAAG,KAAK,MAAM;AAAA,EACtE;AAAA;AAAA,EAEA,SAAS,OAA2D;AAClE,WAAO,KAAK,QAAU,WAAS,KAAK,QAAQ,KAAc,GAAG,KAAK,MAAM;AAAA,EAC1E;AAAA;AAAA,EAEA,MAAM,OAAyD;AAC7D,WAAO,KAAK,QAAQ,KAAK,OAAO,MAAM,KAAc,GAAG,KAAK,MAAM;AAAA,EACpE;AAAA,EACA,QAA6C;AAC3C,WAAO,KAAK,QAAU,QAAM,KAAK,MAAM,GAAG,KAAK,MAAM;AAAA,EACvD;AAAA,EACA,UAAiE;AAC/D,WAAO,KAAK,QAAQ,KAAK,OAAO,QAAQ,GAAG,KAAK,MAAM;AAAA,EACxD;AAAA;AAAA,EAEA,GACE,OACoD;AACpD,WAAO,KAAK;AAAA,MACR,QAAM,CAAC,KAAK,QAAQ,MAAM,KAAK,CAAC,CAAC;AAAA,MACnC,KAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA;AAAA,EAEA,IACE,OACyD;AACzD,WAAO,KAAK;AAAA,MACR,eAAa,KAAK,QAAQ,MAAM,KAAK,CAAgB;AAAA,MACvD,KAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,OACE,OACA,QACM;AACN,WAAO,KAAK;AAAA,MACV,KAAK,OAAO,OAAO,OAAO,MAAM;AAAA,MAChC,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,YACE,YAIM;AACN,WAAO,KAAK;AAAA,MACV,KAAK,OAAO,YAAY,UAAU;AAAA,MAClC,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,SACK,QACG;AACN,WAAO,KAAK;AAAA,MACV,KAAK,OAAO,MAAM,GAAG,MAAM;AAAA,MAC3B,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,UAAU,IAA2C;AACnD,WAAO,KAAK;AAAA,MACV,KAAK,OAAO,UAAU,EAAE;AAAA,MACxB,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,MAA2C,OAAiB;AAC1D,WAAO,KAAK;AAAA,MACV,KAAK,OAAO,MAAM,KAAK;AAAA,MACvB,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA,EAEA,SAAS,aAA2B;AAClC,WAAO,KAAK;AAAA,MACV,KAAK,OAAO,SAAS,WAAW;AAAA,MAChC,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,KAAK,MAA+B;AAClC,WAAO,KAAK;AAAA,MACV,KAAK,OAAO,KAAK,IAAI;AAAA,MACrB,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA,EAEA,WAAmD;AACjD,WAAO,KAAK,QAAQ,KAAK,OAAO,SAAS,GAAG,KAAK,MAAM;AAAA,EACzD;AAAA;AAAA,EAEA,UACE,IAKA;AACA,WAAO,KAAK,QAAQ,KAAK,OAAO,UAAU,EAAE,GAAG,KAAK,MAAM;AAAA,EAC5D;AAAA;AAAA,EAEA,KACE,QACuC;AACvC,WAAO,KAAK;AAAA,MACV,KAAK,OAAO,KAAK,MAAM;AAAA,MACvB,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA,EAEA,SAA2C;AACzC,UAAM,MAAM,KAAK,OAAO,KAAK;AAI7B,UAAM,QAAQ,IAAI,aAAa,IAAI,WAAW,KAAK;AACnD,WAAO,KAAK,QAAQ,OAAO,KAAK,MAAM;AAAA,EAKxC;AAAA;AAAA,EAGA,QAAc;AACZ,WAAO,KAAK,WAAW,OAAO;AAAA,EAChC;AAAA;AAAA,EAEA,SAAe;AACb,WAAO,KAAK,WAAW,QAAQ;AAAA,EACjC;AAAA;AAAA,EAEA,WAAiB;AACf,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EACQ,WAAW,MAAgC;AACjD,UAAM,MAAM,KAAK;AAIjB,QAAI,OAAO,IAAI,UAAU,cAAc,OAAO,IAAI,WAAW,YAAY;AACvE,aAAO;AAAA,IACT;AACA,UAAM,OAAQ,SAAS,UACnB,IAAI,MAAM,IACV,IAAI,OAAO;AAEf,UAAM,SAAS,qBAAqB,IAAI,KAAK,MAAM;AACnD,QAAI,OAAQ,sBAAqB,IAAI,MAAM,MAAM;AACjD,WAAO,KAAK,QAAQ,MAAM,KAAK,MAAM;AAAA,EACvC;AACF;AAGO,IAAM,QAAQ,CAAC,MACpB,aAAa,aAAa,EAAE,SAAS;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/authoring.ts"],"sourcesContent":["// The NEUTRAL, dialect-agnostic AUTHORING BASE (docs/AUTHORING-SPLIT.md — \"base builder in core\").\n// Each driver package builds its `s.*` on this: `class <D>Field extends SFieldBase<S, Flags, <D>Meta>`\n// adds the dialect's native authoring (`$`-methods) and its `$<driver>(type, codec)` escape hatch for\n// types not representable on the wire; the base provides the Zod codec, the Zod wrappers, the full\n// `z.*` passthrough, and the `rebuild`/`blank` seam that carries native metadata through a chain.\n//\n// It references NOTHING dialect-specific — it's generic over the per-dialect native-metadata slot `N`.\n// It is also Zod-CLEAN: app-side behaviour delegates to the inner Zod schema (`z.decode`/`z.encode`/\n// the wrappers) via Zod's public API, with side-channel metadata kept on WeakMaps — never patching\n// Zod internals.\n\nimport * as z from \"zod\";\n\n// `SFieldBase` is INVARIANT in its native-metadata slot `N` (the protected `rebuild(native: N)` makes\n// N contravariant while `native`/`blank` make it covariant). So a dialect field — `SField` with\n// `N = SurrealMeta` — is NOT assignable to a fixed `N = unknown`, which would make `AnyField` reject\n// real dialect fields (e.g. `.or(s.int())`). At THIS cross-dialect boundary `N` is honestly \"any\n// dialect's metadata\": erase it to `any` (bivariant) so every driver's field is an `AnyField`. The\n// concrete `N` is preserved everywhere it matters — each driver's own field type keeps `N = <D>Meta`.\n\n/** Any field of ANY dialect — the base type the helpers + wrappers accept. */\n// biome-ignore lint/suspicious/noExplicitAny: cross-dialect erasure of the invariant native slot N.\nexport type AnyField = SFieldBase<z.ZodType, string, any>;\n\n/** The Zod schema a field (or a raw Zod schema) carries. */\nexport type SchemaOf<F> =\n // biome-ignore lint/suspicious/noExplicitAny: match a field of any dialect (N is invariant).\n F extends SFieldBase<infer S, string, any>\n ? S\n : F extends z.ZodType\n ? F\n : never;\n\n/** The `Flags` channel a field carries (driver `$`-methods brand it; widens to `string` for `Shape`). */\nexport type FlagsOf<F> =\n // biome-ignore lint/suspicious/noExplicitAny: match a field of any dialect (N is invariant).\n F extends SFieldBase<z.ZodType, infer Fl, any> ? Fl : never;\n\n/** The schema one wrapper down — what `unwrap()` returns. */\nexport type InnerOf<S extends z.ZodType> =\n S extends z.ZodOptional<infer I extends z.ZodType>\n ? I\n : S extends z.ZodNullable<infer I extends z.ZodType>\n ? I\n : S extends z.ZodDefault<infer I extends z.ZodType>\n ? I\n : S extends z.ZodPrefault<infer I extends z.ZodType>\n ? I\n : S extends z.ZodCatch<infer I extends z.ZodType>\n ? I\n : S extends z.ZodReadonly<infer I extends z.ZodType>\n ? I\n : S extends z.ZodArray<infer I extends z.ZodType>\n ? I\n : S;\n\n/**\n * Maps an object schema (built via a driver's `s.object`) to its original field shape, so nested\n * fields keep their authoring metadata through generation. Kept on the schema, not the field, so it\n * composes through `array()`/`optional()`/nesting.\n */\nexport const objectFieldsRegistry = new WeakMap<\n z.ZodType,\n Record<string, AnyField>\n>();\n\n/**\n * The PORTABLE, dialect-agnostic field base. Holds the Zod schema, an opaque per-dialect `native`\n * metadata slot, the field-level codecs, and the app-land Zod wrappers (which carry `native` forward\n * via the `rebuild` hook so a chain keeps its concrete dialect type). Each dialect subclasses it to\n * add native authoring (`$`-methods) and re-type the wrappers so a chain stays its own field type.\n */\nexport abstract class SFieldBase<\n S extends z.ZodType = z.ZodType,\n Flags extends string = never,\n N = unknown,\n> {\n constructor(\n readonly schema: S,\n readonly native: N,\n ) {}\n\n /** Rebuild a sibling field of the SAME dialect with a new schema/flags. Each dialect overrides it. */\n protected abstract rebuild<S2 extends z.ZodType, F2 extends string>(\n schema: S2,\n native: N,\n ): SFieldBase<S2, F2, N>;\n /** A fresh, empty native-metadata bag (for wrappers like `or`/`and` that reset it). */\n protected abstract blank(): N;\n\n // --- Field-level codec (raw, on `this.schema`): `decode` reads (wire -> app), `encode` writes\n // (app -> wire). Create-shaping is a table concept, so these are NOT create-shaped. ---\n /** Decode a DB value to its app type (wire -> app). */\n decode(value: unknown): z.output<S> {\n return z.decode(this.schema, value as never);\n }\n /** Encode an app value to its DB wire type (app -> wire). */\n encode(value: z.output<S>): z.input<S> {\n return z.encode(this.schema, value);\n }\n decodeAsync(value: unknown): Promise<z.output<S>> {\n return z.decodeAsync(this.schema, value as never);\n }\n encodeAsync(value: z.output<S>): Promise<z.input<S>> {\n return z.encodeAsync(this.schema, value);\n }\n safeDecode(value: unknown) {\n return z.safeDecode(this.schema, value as never);\n }\n safeEncode(value: z.output<S>) {\n return z.safeEncode(this.schema, value);\n }\n safeDecodeAsync(value: unknown) {\n return z.safeDecodeAsync(this.schema, value as never);\n }\n safeEncodeAsync(value: z.output<S>) {\n return z.safeEncodeAsync(this.schema, value);\n }\n // Deprecated Zod-style aliases — `parse` runs the DECODE direction (wire -> app).\n /** @deprecated `parse` decodes a value (wire -> app). Use {@link decode}. */\n parse(value: unknown): z.output<S> {\n return this.decode(value);\n }\n /** @deprecated Use {@link safeDecode}. */\n safeParse(value: unknown) {\n return this.safeDecode(value);\n }\n /** @deprecated Use {@link decodeAsync}. */\n parseAsync(value: unknown): Promise<z.output<S>> {\n return this.decodeAsync(value);\n }\n /** @deprecated Use {@link safeDecodeAsync}. */\n safeParseAsync(value: unknown) {\n return this.safeDecodeAsync(value);\n }\n\n // Zod wrappers — delegate to the inner schema, carry native metadata + flags forward.\n optional(): SFieldBase<z.ZodOptional<S>, Flags, N> {\n return this.rebuild(this.schema.optional(), this.native);\n }\n nullable(): SFieldBase<z.ZodNullable<S>, Flags, N> {\n return this.rebuild(this.schema.nullable(), this.native);\n }\n default(value: z.input<S>): SFieldBase<z.ZodDefault<S>, Flags, N> {\n return this.rebuild(this.schema.default(value as never), this.native);\n }\n /** Zod prefault: fill an absent value with `value`, then validate it (unlike `.default`). */\n prefault(value: z.input<S>): SFieldBase<z.ZodPrefault<S>, Flags, N> {\n return this.rebuild(z.prefault(this.schema, value as never), this.native);\n }\n /** Zod catch: fall back to `value` when parsing fails. */\n catch(value: z.output<S>): SFieldBase<z.ZodCatch<S>, Flags, N> {\n return this.rebuild(this.schema.catch(value as never), this.native);\n }\n array(): SFieldBase<z.ZodArray<S>, Flags, N> {\n return this.rebuild(z.array(this.schema), this.native);\n }\n nullish(): SFieldBase<z.ZodOptional<z.ZodNullable<S>>, Flags, N> {\n return this.rebuild(this.schema.nullish(), this.native);\n }\n /** Zod union — `a.or(b)` accepts either. Mirrors Zod's `.or()`. */\n or<F extends AnyField | z.ZodType>(\n other: F,\n ): SFieldBase<z.ZodUnion<[S, SchemaOf<F>]>, never, N> {\n return this.rebuild<z.ZodUnion<[S, SchemaOf<F>]>, never>(\n z.union([this.schema, toZod(other)]) as z.ZodUnion<[S, SchemaOf<F>]>,\n this.blank(),\n );\n }\n /** Zod intersection — `a.and(b)`. Mirrors Zod's `.and()`. */\n and<F extends AnyField | z.ZodType>(\n other: F,\n ): SFieldBase<z.ZodIntersection<S, SchemaOf<F>>, never, N> {\n return this.rebuild<z.ZodIntersection<S, SchemaOf<F>>, never>(\n z.intersection(this.schema, toZod(other) as SchemaOf<F>),\n this.blank(),\n );\n }\n\n // --- Native Zod passthrough (drop-in for `z.*`): app-side validation / transform / metadata,\n // delegated to the inner schema. The dialect-DDL side stays under the driver's `$`-methods. ---\n refine(\n check: (arg: z.output<S>) => unknown,\n params?: string | z.core.$ZodCustomParams,\n ): this {\n return this.rebuild(\n this.schema.refine(check, params) as S,\n this.native,\n ) as unknown as this;\n }\n superRefine(\n refinement: (\n arg: z.output<S>,\n ctx: z.core.$RefinementCtx<z.output<S>>,\n ) => void,\n ): this {\n return this.rebuild(\n this.schema.superRefine(refinement) as S,\n this.native,\n ) as unknown as this;\n }\n check(\n ...checks: (z.core.CheckFn<z.output<S>> | z.core.$ZodCheck<z.output<S>>)[]\n ): this {\n return this.rebuild(\n this.schema.check(...checks) as S,\n this.native,\n ) as unknown as this;\n }\n overwrite(fn: (x: z.output<S>) => z.output<S>): this {\n return this.rebuild(\n this.schema.overwrite(fn) as S,\n this.native,\n ) as unknown as this;\n }\n brand<B extends PropertyKey = PropertyKey>(value?: B): this {\n return this.rebuild(\n this.schema.brand(value) as unknown as S,\n this.native,\n ) as unknown as this;\n }\n /** Zod's app-side metadata (JSON-schema/docs) — distinct from a driver's `$comment()`. */\n describe(description: string): this {\n return this.rebuild(\n this.schema.describe(description) as S,\n this.native,\n ) as unknown as this;\n }\n meta(data: z.core.GlobalMeta): this {\n return this.rebuild(\n this.schema.meta(data) as S,\n this.native,\n ) as unknown as this;\n }\n /** Zod's app-side readonly (TS-immutable output) — distinct from a driver's `$readonly()`. */\n readonly(): SFieldBase<z.ZodReadonly<S>, Flags, N> {\n return this.rebuild(this.schema.readonly(), this.native);\n }\n /** Zod transform — changes the decoded `App<>` value; the stored (wire) type is unchanged. */\n transform<NewOut>(\n fn: (arg: z.output<S>, ctx: z.core.$RefinementCtx<z.output<S>>) => NewOut,\n ): SFieldBase<\n z.ZodPipe<S, z.ZodTransform<Awaited<NewOut>, z.output<S>>>,\n Flags,\n N\n > {\n return this.rebuild(this.schema.transform(fn), this.native);\n }\n /** Zod pipe — feed this field's output into `target`; the stored (wire) type stays `this`. */\n pipe<T extends z.core.$ZodType<unknown, z.output<S>>>(\n target: T,\n ): SFieldBase<z.ZodPipe<S, T>, Flags, N> {\n return this.rebuild(\n this.schema.pipe(target) as z.ZodPipe<S, T>,\n this.native,\n );\n }\n /** Peel one wrapper (optional/nullable/default/prefault/catch/readonly/array) off the field. */\n unwrap(): SFieldBase<InnerOf<S>, Flags, N> {\n const def = this.schema._zod.def as {\n innerType?: z.ZodType;\n element?: z.ZodType;\n };\n const inner = def.innerType ?? def.element ?? this.schema;\n return this.rebuild(inner, this.native) as unknown as SFieldBase<\n InnerOf<S>,\n Flags,\n N\n >;\n }\n\n /** Object-only: allow arbitrary extra keys — `FLEXIBLE` in DDL. Mirrors Zod's `.loose()`. */\n loose(): this {\n return this.objectMode(\"loose\");\n }\n /** Object-only: reject unknown keys — the default. Mirrors Zod's `.strict()`. */\n strict(): this {\n return this.objectMode(\"strict\");\n }\n /** Alias for {@link loose} — a `FLEXIBLE` object accepting arbitrary keys. */\n flexible(): this {\n return this.loose();\n }\n private objectMode(mode: \"loose\" | \"strict\"): this {\n const obj = this.schema as unknown as {\n loose?: () => z.ZodType;\n strict?: () => z.ZodType;\n };\n if (typeof obj.loose !== \"function\" || typeof obj.strict !== \"function\") {\n return this; // not an object schema — no-op\n }\n const next = (mode === \"loose\"\n ? obj.loose()\n : obj.strict()) as unknown as S;\n // Carry the nested-field registry forward so DDL/create-shaping still see the subfields.\n const fields = objectFieldsRegistry.get(this.schema);\n if (fields) objectFieldsRegistry.set(next, fields);\n return this.rebuild(next, this.native) as unknown as this;\n }\n}\n\n/** Unwrap a field to its Zod schema (raw Zod schemas pass through). */\nexport const toZod = (v: AnyField | z.ZodType): z.ZodType =>\n v instanceof SFieldBase ? v.schema : v;\n"],"mappings":"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","names":[]}
|
|
@@ -271,7 +271,8 @@ var KindRegistry = class {
|
|
|
271
271
|
};
|
|
272
272
|
|
|
273
273
|
// src/driver/driver.ts
|
|
274
|
-
var
|
|
274
|
+
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("@schemic/core.driverRegistry");
|
|
275
|
+
var REGISTRY = globalThis[REGISTRY_KEY] ??= /* @__PURE__ */ new Map();
|
|
275
276
|
function registerDriver(driver) {
|
|
276
277
|
REGISTRY.set(driver.name, driver);
|
|
277
278
|
}
|
|
@@ -301,4 +302,4 @@ export {
|
|
|
301
302
|
getDriver,
|
|
302
303
|
driverNames
|
|
303
304
|
};
|
|
304
|
-
//# sourceMappingURL=chunk-
|
|
305
|
+
//# sourceMappingURL=chunk-LDKFTPH3.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/kind/plan.ts","../src/kind/registry.ts","../src/driver/driver.ts"],"sourcesContent":["// The GENERIC migration spine over a {@link KindRegistry} — core's kind-blind orchestration. It\n// classifies each portable object as add/change/remove, ORDERS them across kinds by a dependency\n// graph, and emits up/down DDL + the display {@link Diff}. It never names a kind: every kind-specific\n// decision is delegated to that kind's {@link KindEngine}.\n//\n// The spine works on PORTABLE objects (both sides already lowered), exactly like the fixed-slot\n// `Driver.diff(prev, next)`: the stored snapshot IS portable, and the authoring side is lowered once\n// via {@link lowerSchema}. So `prev` is a snapshot, `next` is `lowerSchema(registry, defs)`.\n//\n// Cross-kind ordering is the load-bearing part (docs/kind-registry.md §7.1). THREE layers:\n// 1. dependency GRAPH + topological sort -> CORRECTNESS (an object emits after everything it deps on)\n// 2. kind ORDINAL (registration order) -> stable TIE-BREAK among independent objects (layering)\n// 3. OWNER clustering -> READABILITY (an index right after its table)\n// A per-kind ordinal ALONE is wrong: a table's event can call a function, so the function must emit\n// BEFORE the table — a function-before-table the graph handles and an ordinal cannot. Drops reverse it.\n\n// NOTE: `Diff`/`DiffItem` are a type-only import (erased at compile — no runtime cli->kind coupling),\n// the same arrangement as ./driver/portable-diff.ts.\nimport type { Diff, DiffItem } from \"../cli-kit/diff\";\nimport type {\n Definable,\n KindEngine,\n KindRegistry,\n PortableObject,\n Ref,\n} from \"./registry\";\n\nconst refKey = (r: Ref) => `${r.kind}:${r.name}`;\n\n/** A node in the dependency graph: identity + the edges/owner used to order it. */\nexport interface OrderNode {\n readonly kind: string;\n readonly name: string;\n /** Objects this node must come AFTER (only intra-set refs constrain; external refs are ignored). */\n readonly deps: Ref[];\n /** Owning object to cluster next to (readability tie-break only; never overrides `deps`). */\n readonly owner?: Ref;\n}\n\n/**\n * Kahn's topological sort with two presentation tweaks among the nodes whose deps are all satisfied:\n * prefer one OWNED by the currently-open cluster (so a table's children follow it), then lowest\n * (kind-ordinal, then name). Correctness (deps) always wins — an owned/low-ordinal node can't jump a\n * dependency. A genuine cycle throws (a named error). Refs to nodes outside `nodes` are ignored (an\n * object may depend on something untouched by this diff — it already exists / isn't changing).\n */\nexport function orderObjects<T extends OrderNode>(\n nodes: T[],\n ordinalOf: (kind: string) => number,\n): T[] {\n const byKey = new Map(nodes.map((n) => [refKey(n), n]));\n const indeg = new Map<string, number>(nodes.map((n) => [refKey(n), 0]));\n const dependents = new Map<string, string[]>();\n for (const n of nodes)\n for (const d of n.deps) {\n if (!byKey.has(refKey(d))) continue; // external dep -> not a constraint within this set\n indeg.set(refKey(n), (indeg.get(refKey(n)) ?? 0) + 1);\n const list = dependents.get(refKey(d)) ?? [];\n list.push(refKey(n));\n dependents.set(refKey(d), list);\n }\n\n const out: T[] = [];\n const done = new Set<string>();\n let group: string | undefined; // the last unowned node emitted == the open cluster\n while (out.length < nodes.length) {\n const ready = nodes.filter(\n (n) => !done.has(refKey(n)) && indeg.get(refKey(n)) === 0,\n );\n if (ready.length === 0)\n throw new Error(\n `dependency cycle among: ${nodes\n .filter((n) => !done.has(refKey(n)))\n .map(refKey)\n .join(\", \")}`,\n );\n ready.sort((a, b) => {\n const ao = a.owner && refKey(a.owner) === group ? 0 : 1; // prefer the open cluster\n const bo = b.owner && refKey(b.owner) === group ? 0 : 1;\n return (\n ao - bo ||\n ordinalOf(a.kind) - ordinalOf(b.kind) ||\n refKey(a).localeCompare(refKey(b))\n );\n });\n const next = ready[0];\n out.push(next);\n done.add(refKey(next));\n if (!next.owner) group = refKey(next); // a top-level object opens a new cluster\n for (const dep of dependents.get(refKey(next)) ?? [])\n indeg.set(dep, (indeg.get(dep) ?? 1) - 1);\n }\n return out;\n}\n\n// --- lowering + snapshot ------------------------------------------------------------------------\n\n/**\n * Author -> portable: lower each definable through its kind's engine (skipping unregistered kinds).\n * The single place authoring becomes portable; everything downstream (diff/emit/snapshot) is portable.\n */\nexport function lowerSchema(\n registry: KindRegistry,\n defs: Definable[],\n): PortableObject[] {\n const out: PortableObject[] = [];\n for (const d of defs) {\n const engine = registry.engine(d.kind);\n if (engine) out.push(engine.lower(d));\n }\n return out;\n}\n\n/**\n * The registry SNAPSHOT — portable objects grouped by kind. The open, generic replacement for\n * `PortableDb`'s fixed slots; serializes as plain JSON (it is plain data). Pre-launch: the format is\n * free to change, no version migration.\n */\nexport interface KindSnapshot {\n kinds: Record<string, PortableObject[]>;\n}\n\n/** Group a flat portable schema into a snapshot (by kind). */\nexport function snapshotKinds(schema: PortableObject[]): KindSnapshot {\n const kinds: Record<string, PortableObject[]> = {};\n for (const o of schema) {\n const bucket = kinds[o.kind] ?? [];\n bucket.push(o);\n kinds[o.kind] = bucket;\n }\n return { kinds };\n}\n\n/** Flatten a snapshot back into a portable schema (the inverse of {@link snapshotKinds}). */\nexport function snapshotObjects(snap: KindSnapshot): PortableObject[] {\n return Object.values(snap.kinds).flat();\n}\n\n// --- diff / plan --------------------------------------------------------------------------------\n\n/** One classified object change, carrying its ordering metadata + the portable sides for DDL. */\ninterface Change extends OrderNode {\n readonly op: \"add\" | \"change\" | \"remove\";\n readonly prev?: PortableObject;\n readonly next?: PortableObject;\n}\n\n/** An up/down DDL program (each a list of statements). */\nexport interface KindPlan {\n up: string[];\n down: string[];\n}\n\n/** The canonical change-detection key for an object — the kind's `canonical`, else its emitted DDL. */\nconst canonicalOf = (engine: KindEngine, p: PortableObject): string =>\n engine.canonical?.(p) ?? engine.emit(p).join(\"\\n\");\n\nconst orderNodeOf = (\n engine: KindEngine,\n portable: PortableObject,\n): OrderNode => ({\n kind: portable.kind,\n name: portable.name,\n deps: engine.deps?.(portable) ?? [],\n owner: engine.owner?.(portable),\n});\n\n/** Display identity: `kind:owner:name` (owner blank for a top-level object) + the display owner. */\nconst itemKey = (n: OrderNode) => `${n.kind}:${n.owner?.name ?? \"\"}:${n.name}`;\nconst itemTable = (n: OrderNode) => n.owner?.name ?? n.name;\n\nconst byKey = (schema: PortableObject[]) =>\n new Map(schema.map((o) => [refKey(o), o]));\n\n/**\n * Classify both sides into ordered add/change/remove sets — the shared core of plan + diff. A `change`\n * is two objects of the same key whose emitted DDL differs (same test as the fixed-slot engine). Each\n * class is topologically ordered parent-first; the caller reverses one class for drops/inversion.\n */\nfunction orderedChanges(\n registry: KindRegistry,\n prev: PortableObject[],\n next: PortableObject[],\n): { nonRemoves: Change[]; removes: Change[] } {\n const prevByKey = byKey(prev);\n const nextByKey = byKey(next);\n const changes: Change[] = [];\n for (const k of new Set([...prevByKey.keys(), ...nextByKey.keys()])) {\n const p = prevByKey.get(k);\n const n = nextByKey.get(k);\n const portable = n ?? p;\n if (!portable) continue;\n const engine = registry.engine(portable.kind);\n if (!engine) continue;\n const node = orderNodeOf(engine, portable);\n if (p && !n) changes.push({ op: \"remove\", prev: p, ...node });\n else if (!p && n) changes.push({ op: \"add\", next: n, ...node });\n else if (p && n && canonicalOf(engine, p) !== canonicalOf(engine, n))\n changes.push({ op: \"change\", prev: p, next: n, ...node });\n }\n const ord = (kind: string) => registry.ordinal(kind);\n return {\n nonRemoves: orderObjects(\n changes.filter((c) => c.op !== \"remove\"),\n ord,\n ),\n removes: orderObjects(\n changes.filter((c) => c.op === \"remove\"),\n ord,\n ),\n };\n}\n\nconst overwriteUp = (\n engine: KindEngine,\n a: PortableObject,\n b: PortableObject,\n): string[] =>\n engine.overwrite?.(a, b) ?? [...engine.remove(a), ...engine.emit(b)];\n\n/**\n * Diff two portable schema states into an executable up/down program, generically over the registry.\n *\n * `up` runs creates/changes parent-first (the dependency graph) then drops child-first; `down` is the\n * mirror: recreate drops parent-first, then undo creates/changes child-first. We invert PER OBJECT (not\n * by reversing the flat DDL list) so a kind's multi-line block — a table emitted with its fields —\n * keeps its internal order in both directions.\n */\nexport function planKinds(\n registry: KindRegistry,\n prev: PortableObject[],\n next: PortableObject[],\n): KindPlan {\n const { nonRemoves, removes } = orderedChanges(registry, prev, next);\n const up: string[] = [];\n const down: string[] = [];\n for (const c of nonRemoves) {\n const e = registry.engine(c.kind);\n if (!e) continue;\n if (c.op === \"add\" && c.next) up.push(...e.emit(c.next));\n else if (c.op === \"change\" && c.prev && c.next)\n up.push(...overwriteUp(e, c.prev, c.next));\n }\n for (const c of [...removes].reverse()) {\n const e = registry.engine(c.kind); // drops child-first\n if (e && c.prev) up.push(...e.remove(c.prev));\n }\n for (const c of removes) {\n const e = registry.engine(c.kind); // recreate dropped objects parent-first\n if (e && c.prev) down.push(...e.emit(c.prev));\n }\n for (const c of [...nonRemoves].reverse()) {\n const e = registry.engine(c.kind); // undo creates/changes child-first\n if (!e) continue;\n if (c.op === \"add\" && c.next) down.push(...e.remove(c.next));\n else if (c.op === \"change\" && c.prev && c.next)\n down.push(...overwriteUp(e, c.next, c.prev));\n }\n return { up, down };\n}\n\n/**\n * Display items for a change set, in up order (creates/changes parent-first, drops child-first). A kind\n * with `displayItems` decomposes into FINE-grained sub-items (per-field, each carrying its `table` so\n * the display groups them under it); otherwise it falls back to ONE whole-object item.\n */\nfunction diffItems(\n registry: KindRegistry,\n nonRemoves: Change[],\n removes: Change[],\n): DiffItem[] {\n const items: DiffItem[] = [];\n const push = (c: Change) => {\n const e = registry.engine(c.kind);\n if (!e) return;\n if (e.displayItems) {\n items.push(...e.displayItems(c.prev, c.next));\n return;\n }\n const base = { key: itemKey(c), table: itemTable(c), kind: c.kind };\n if (c.op === \"add\" && c.next)\n items.push({ ...base, op: \"add\", ddl: e.emit(c.next).join(\"\\n\") });\n else if (c.op === \"remove\" && c.prev)\n items.push({\n ...base,\n op: \"remove\",\n ddl: e.remove(c.prev).join(\"\\n\"),\n old: e.emit(c.prev).join(\"\\n\"),\n });\n else if (c.op === \"change\" && c.prev && c.next)\n items.push({\n ...base,\n op: \"change\",\n before: e.emit(c.prev).join(\"\\n\"),\n after: e.emit(c.next).join(\"\\n\"),\n });\n };\n for (const c of nonRemoves) push(c);\n for (const c of [...removes].reverse()) push(c);\n return items;\n}\n\n/**\n * The full {@link Diff} the CLI + migration model consume — up/down DDL + per-object display items +\n * the whole desired schema (`full`, for `--full`). This is what a driver's `Driver.diff` returns once\n * its kinds are on the registry (the generic counterpart of the fixed-slot `buildDiff`). Source-file\n * linkage on the items is attached by the caller (the snapshot's `files` map), so `file` is left unset.\n */\nexport function buildKindDiff(\n registry: KindRegistry,\n prev: PortableObject[],\n next: PortableObject[],\n): Diff {\n const { nonRemoves, removes } = orderedChanges(registry, prev, next);\n const { up, down } = planKinds(registry, prev, next);\n // `full` mirrors the items' granularity: a kind with `displayItems` projects its object as per-\n // sub-object adds (displayItems(undefined, portable)); otherwise one whole-object entry.\n const full = orderedSchema(registry, next).flatMap(\n ({ engine, portable, node }) => {\n if (engine.displayItems)\n return engine.displayItems(undefined, portable).map((it) => ({\n key: it.key,\n table: it.table,\n ddl: it.op === \"add\" ? it.ddl : \"\",\n }));\n return [\n {\n key: itemKey(node),\n table: itemTable(node),\n ddl: engine.emit(portable).join(\"\\n\"),\n },\n ];\n },\n );\n return { up, down, items: diffItems(registry, nonRemoves, removes), full };\n}\n\n/** Lower-already portable schema, topologically ordered, paired with each object's engine + node. */\nfunction orderedSchema(\n registry: KindRegistry,\n schema: PortableObject[],\n): { engine: KindEngine; portable: PortableObject; node: OrderNode }[] {\n const items = schema.flatMap((portable) => {\n const engine = registry.engine(portable.kind);\n return engine\n ? [{ engine, portable, node: orderNodeOf(engine, portable) }]\n : [];\n });\n const pos = new Map(\n orderObjects(\n items.map((i) => i.node),\n (k) => registry.ordinal(k),\n ).map((n, i) => [itemKey(n), i]),\n );\n return items.sort(\n (a, b) => (pos.get(itemKey(a.node)) ?? 0) - (pos.get(itemKey(b.node)) ?? 0),\n );\n}\n\n/**\n * Fresh-apply DDL for a portable schema: every object created, ordered across kinds by the graph.\n * (The `up` of a diff from an empty state.) Lower authoring first via {@link lowerSchema}.\n */\nexport function emitKinds(\n registry: KindRegistry,\n schema: PortableObject[],\n): string[] {\n return orderedSchema(registry, schema).flatMap(({ engine, portable }) =>\n engine.emit(portable),\n );\n}\n\n/**\n * Reverse direction, fanned out across kinds: introspect every introspectable kind off one live\n * connection and flatten into portable objects. The RESOLUTION of \"per-kind vs one driver read\":\n * the contract is per-kind ({@link KindEngine.introspect}), but a driver backs all of its kinds with\n * ONE shared (memoized) read of `conn` and slices out each kind's objects — so the fan-out here costs\n * a single round-trip, not N. A kind without `introspect` contributes nothing (not introspectable).\n */\nexport async function introspectKinds(\n registry: KindRegistry,\n conn: unknown,\n): Promise<PortableObject[]> {\n const out: PortableObject[] = [];\n for (const [, engine] of registry.entries()) {\n if (!engine.introspect) continue;\n out.push(...(await engine.introspect(conn)));\n }\n return out;\n}\n","// The KIND REGISTRY — core-v2's generic, open replacement for the fixed object-kind slots.\n//\n// Today `PortableDb` hard-codes the object kinds a schema may contain (`tables`/`functions`/\n// `accesses`/`natives`) and the Driver's whole-DB methods switch on those slots. The kind registry\n// turns the slots into a REGISTRY a driver populates: each driver registers KINDS, and every kind\n// brings (a) its OWN authoring builder — any shape/chain it likes, fully typed — and (b) its engine\n// behavior (`lower`/`emit`/`remove`/`overwrite`/`deps`/`owner`/`introspect`) over THAT kind's objects.\n// Core orchestrates generically over the registry (see ./plan.ts) and never names a kind.\n//\n// What stays in core is the field/type VOCABULARY (`SFieldBase`, the Zod-drop-in `s.*`, `PortableType`,\n// codecs) — the substrate every kind builds on. Fields/types are NOT a kind: a table HAS fields, a\n// function's args ARE fields, an index REFERENCES fields. See docs/kind-registry.md.\n//\n// The registry is PER-DRIVER, not a module global: multiple drivers (`@schemic/surrealdb`,\n// `@schemic/postgres`) are registered at once and each defines its own `\"table\"`/`\"function\"`, so a\n// shared global map would collide. A driver builds one `KindRegistry` and registers its kinds into it.\n\n/**\n * An authored definable, tagged with the KIND that owns it. Core dispatches on `kind` alone — every\n * other field is the kind's own business, handed straight to {@link KindEngine.lower}. This is the\n * neutral upper bound for a kind's authoring-object type (a driver's concrete `TableDef`/`FnDef` is a\n * structural subtype).\n */\nexport interface Definable {\n readonly kind: string;\n readonly name: string;\n}\n\n/**\n * A kind's PORTABLE object — the dialect-independent data shape core stores + diffs. A kind chooses\n * how structured this is: a table's portable form carries fields/indexes (so core can field-level\n * diff it); an opaque kind (function/access) carries a neutral identity + a `native` payload it\n * round-trips. Either way it is tagged with `kind`/`name` for cross-kind dispatch + ordering.\n */\nexport interface PortableObject {\n readonly kind: string;\n readonly name: string;\n}\n\n/** A reference to another object in the schema graph — the unit of cross-kind dependency ordering. */\nexport interface Ref {\n readonly kind: string;\n readonly name: string;\n}\n\n// `DiffItem` is a type-only import (erased at compile) — the display contract the `displayItems` hook\n// produces; no runtime cli->kind coupling, same arrangement as ./plan.ts.\nimport type { DiffItem } from \"../cli-kit/diff\";\n\n/**\n * What core needs to orchestrate ONE kind generically — it never inspects the specifics. The\n * change-vocabulary (`emit`/`remove`/`overwrite`) mirrors the Driver contract's, so a kind's behavior\n * is parity-checkable against the fixed-slot engine. `A` is the kind's authoring object, `P` its\n * portable object; both are opaque to core beyond the {@link Definable}/{@link PortableObject} bounds.\n */\nexport interface KindEngine<\n A extends Definable = Definable,\n P extends PortableObject = PortableObject,\n> {\n /** Authoring object -> this kind's portable object (normalized; both lowerings must converge here). */\n lower(authored: A): P;\n /** CREATE DDL for one portable object (a fresh apply / migration `up` for an added object). */\n emit(portable: P): string[];\n /** DROP DDL for one portable object (`up` for a removed object, `down` for an added one). */\n remove(portable: P): string[];\n /**\n * In-place CHANGE DDL taking `prev` to `next` (the dialect's ALTER/OVERWRITE). The spine calls\n * `overwrite(next, prev)` to roll a change back. A kind with no in-place form recreates: implement\n * as `[...remove(prev), ...emit(next)]`. Default (omitted) = recreate via emit(next).\n */\n overwrite?(prev: P, next: P): string[];\n /**\n * The CANONICAL change-detection key: the spine treats prev/next of the same object as a CHANGE iff\n * their `canonical` differs. Default (omitted) = `emit(portable).join(\"\\n\")` — so a kind whose `emit`\n * is already its canonical form needs nothing. Override when `emit` is FAITHFUL but some clauses must\n * be EXCLUDED from equality — because the DB rewrites them on read (PG `'x'` -> `'x'::text`, `a>0` ->\n * `(a>0)`) or never introspects them (a COMMENT, an index) — so a faithful `emit` would phantom-diff a\n * freshly-applied schema against `introspect`. Return `emit` MINUS those clauses: they stay create-time\n * faithful in `emit`, but don't count as changes. `canonical(a) === canonical(b)` MUST mean \"no\n * migration needed\". Affects ONLY classification; `emit`/`overwrite` (the DDL) are unaffected.\n */\n canonical?(portable: P): string;\n /**\n * Fine-grained DISPLAY items for a change of this object — so `schemic diff` shows per-SUB-OBJECT\n * changes (a table decomposes into per-FIELD items: `field:user:name` changed), each carrying its\n * owner `table` so the display GROUPS them hierarchically under it, instead of one coarse whole-object\n * item. Called `(prev, next)`: a change diffs the two; `(undefined, next)` lists the object's\n * sub-items as adds — the `--full` projection core uses for the full desired-state view. Default\n * (omitted) = ONE whole-object item. DISPLAY ONLY — never affects up/down DDL (that is\n * `emit`/`overwrite`); a structured driver reuses the per-field diff it already computes. Leave\n * `DiffItem.file` unset (the caller attaches source linkage).\n */\n displayItems?(prev: P | undefined, next: P | undefined): DiffItem[];\n /**\n * Objects this one must be emitted AFTER — the cross-kind dependency edges (a field/index -> its\n * table; an edge table -> its in/out tables; an event -> its table + any function it calls). Drives\n * the topological sort in ./plan.ts. Omitted = no dependencies.\n */\n deps?(portable: P): Ref[];\n /**\n * The owning object to CLUSTER next to in the emitted order (an index's table) — readability only,\n * never overrides {@link deps}. Omitted = a top-level object.\n */\n owner?(portable: P): Ref | undefined;\n /**\n * Live connection -> all portable objects of THIS kind (the reverse direction). Introspection is\n * often one `INFO`/`pg_catalog` read yielding every kind at once; a driver backs all of its kinds'\n * `introspect` with one shared (memoized) read and slices out this kind's objects. Omitted -> this\n * kind isn't introspectable (diff/emit still work from authored state).\n */\n introspect?(conn: unknown): Promise<P[]>;\n /**\n * How this kind is PRESENTED — its human labels and the folder its objects render into. All optional\n * with sensible defaults off the kind name (see {@link KindRegistry.display}), so a kind only declares\n * what the defaults get wrong (e.g. `plural: \"Indexes\"`, or `folder: \"access\"`). DISPLAY ONLY.\n */\n display?: KindDisplay;\n}\n\n/** Per-kind presentation metadata (labels + output folder). All optional; core fills defaults. */\nexport interface KindDisplay {\n /** Title-Case singular, e.g. `\"Table\"`, `\"Field\"`. Default: the kind name, capitalized. */\n label?: string;\n /** Title-Case plural, e.g. `\"Tables\"`, `\"Indexes\"`. Default: the English plural of `label`. */\n plural?: string;\n /** The directory this kind's objects render into. Default: the lowercase slug of `plural`. */\n folder?: string;\n}\n\n/** A kind's resolved presentation — every field filled (the shape {@link KindRegistry.display} returns). */\nexport type ResolvedDisplay = Required<KindDisplay>;\n\n/** A kind's full spec: its `name`, its `build` (the driver's authoring entry), and its engine. */\nexport type KindSpec<\n Build extends (...args: never[]) => unknown,\n A extends Definable,\n P extends PortableObject,\n> = { name: string; build: Build } & KindEngine<A, P>;\n\n/** `\"table\"` -> `\"Table\"`. */\nfunction capitalize(s: string): string {\n return s ? s[0].toUpperCase() + s.slice(1) : s;\n}\n\n/** A plain English pluralizer for kind labels: `Index` -> `Indexes`, `Policy` -> `Policies`. */\nfunction pluralize(s: string): string {\n if (/[^aeiou]y$/i.test(s)) return `${s.slice(0, -1)}ies`;\n if (/(s|x|z|ch|sh)$/i.test(s)) return `${s}es`;\n return `${s}s`;\n}\n\n/** `\"Tables\"` -> `\"tables\"`; collapses non-alphanumerics to single dashes (a filesystem-safe folder). */\nfunction slugify(s: string): string {\n return s\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\n/**\n * A driver's set of registered kinds + the generic behavior the spine reads off them. Built once per\n * driver; `define` registers a kind and returns the driver's OWN `build` function UNCHANGED — so the\n * driver writes `export const defineTable = registry.define({ name: \"table\", build, ...engine })` and\n * keeps full type-safety + DX (TS preserves a generic `build`'s parameters across the passthrough).\n */\nexport class KindRegistry {\n // Heterogeneous kinds erase at the engine seam (engine ops are structural); the AUTHORING side\n // keeps full types via `define`'s `Build` passthrough.\n // biome-ignore lint/suspicious/noExplicitAny: the engine seam is intentionally type-erased.\n private readonly kinds = new Map<string, KindEngine<any, any>>();\n\n /**\n * Register a KIND. `build` is the driver's own authoring entry — ANY shape/chain — and its type\n * flows through unchanged (type-safety + DX are the driver's to design). The engine fns give core\n * the generic behavior. Registration ORDER is the kind's ordinal (the stable tie-break among\n * independent objects in {@link orderObjects}), so register coarse-to-fine (table before index).\n */\n define<\n Build extends (...args: never[]) => unknown,\n A extends Definable,\n P extends PortableObject,\n >(spec: KindSpec<Build, A, P>): Build {\n this.kinds.set(spec.name, spec);\n return spec.build;\n }\n\n /** The engine for `kind`, or undefined if no such kind is registered. */\n // biome-ignore lint/suspicious/noExplicitAny: the engine erases at this seam (see `kinds`).\n engine(kind: string): KindEngine<any, any> | undefined {\n return this.kinds.get(kind);\n }\n\n /**\n * A kind's resolved presentation — `label`/`plural`/`folder`, with defaults derived from the kind\n * name for whatever the driver left unset. Works for unregistered display sub-kinds too (e.g. the\n * `\"field\"` items a table's `displayItems` emits) — they just get the name-derived defaults.\n */\n display(kind: string): ResolvedDisplay {\n const d = this.kinds.get(kind)?.display ?? {};\n const label = d.label ?? capitalize(kind);\n const plural = d.plural ?? pluralize(label);\n return { label, plural, folder: d.folder ?? slugify(plural) };\n }\n\n /** Registered kind names, in registration order (== ordinal order). */\n names(): string[] {\n return [...this.kinds.keys()];\n }\n\n /**\n * A kind's ORDINAL = its registration index. Used ONLY as a tie-break among objects with no\n * dependency relation, so independent objects come out stably layered (readability); it never\n * overrides the dependency graph. An unknown kind sorts last.\n */\n ordinal(kind: string): number {\n const i = this.names().indexOf(kind);\n return i === -1 ? Number.MAX_SAFE_INTEGER : i;\n }\n\n /** [name, engine] pairs in registration order — the spine iterates these. */\n // biome-ignore lint/suspicious/noExplicitAny: the engine erases at this seam (see `kinds`).\n entries(): [string, KindEngine<any, any>][] {\n return [...this.kinds.entries()];\n }\n}\n","// The DRIVER interface — the dialect seam for multi-DB support (see docs/MULTI-DB-SPIKE.md).\n//\n// Everything dialect-specific lives behind a `Driver`: lowering authoring to the Struct-IR, emitting\n// DDL, introspecting a live DB, normalizing to a canonical form, and executing. Everything ABOVE the\n// driver (the diff algorithm, the magicast TS-merge, the migration model, the CLI shell) stays\n// dialect-free and calls these ops.\n//\n// The connection type is a driver-private parameter `Conn`: the orchestration treats it opaquely and\n// only ever hands it back to the SAME driver. So the Surreal driver is `Driver<Surreal>`, a future\n// Postgres driver is `Driver<PgClient>`, and core never sees either concrete type. The AUTHORING\n// types (`Tbl`/`Def`) are driver-private the same way — opaque to core beyond the neutral\n// `Authored`/`AuthoredDef` bounds — so the neutral engine never names a dialect's concrete builder\n// (`TableDef`/`StandaloneDef`).\n\nimport type { ResolvedConfig } from \"../cli-kit/config\";\nimport type { Diff } from \"../cli-kit/diff\";\nimport type { Filter } from \"../cli-kit/filter\";\nimport type { PullPlan } from \"../cli-kit/merge\";\nimport type { Definable, KindRegistry, PortableObject } from \"../kind\";\n\n/**\n * The dialect-NEUTRAL authoring contract — the only structure the orchestration reads off an\n * authored object (everything else is opaque and handed straight to {@link Driver.explode}). A table\n * contributes just its `name`; this is the upper bound for a driver's table-authoring type. The\n * Surreal `TableDef` is a structural subtype, as is any future dialect's table builder.\n */\nexport interface Authored {\n readonly name: string;\n}\n\n/**\n * The neutral contract for a standalone (non-table) authored object — an event/function/access. It\n * adds a `kind` discriminant and, for objects owned by a table (e.g. an event), the owner `table`\n * name (so the snapshot can file-link a child object under its parent). The Surreal `StandaloneDef`\n * union is a structural subtype.\n */\nexport interface AuthoredDef extends Authored {\n readonly kind: string;\n readonly table?: string;\n}\n\n/**\n * A single emitted DDL statement, structured: object identity (`kind`/`name`/`table`) + the dialect\n * `ddl` string, plus an optional clause map (each value an `ALTER … <set>` form) for dialects that\n * diff clause-level. `kind` is a dialect-defined string the orchestration treats opaquely — the\n * SurrealDB `DefineStatement` (with its fixed kind union) is a structural subtype of this.\n */\nexport interface Statement {\n kind: string;\n name: string;\n table?: string;\n ddl: string;\n clauses?: Record<string, string>;\n}\n\n/** Options for {@link Driver.emit} — mirrors the existing `DefineOptions` (e.g. IF NOT EXISTS). */\nexport interface EmitOptions {\n ifNotExists?: boolean;\n overwrite?: boolean;\n}\n\n/** Options for {@link Driver.apply}. */\nexport interface ApplyOptions {\n /**\n * Run the whole batch atomically. `migrate` wraps up/down + `_migrations` bookkeeping in one\n * transaction; a driver that can't MUST surface that (the migration model degrades to best-effort).\n */\n transactional?: boolean;\n}\n\n/** Per-connection overrides (url/namespace/credentials) — superset across dialects. */\nexport interface ConnectionOverrides {\n url?: string;\n namespace?: string;\n database?: string;\n username?: string;\n password?: string;\n authLevel?: string;\n}\n\n/** The direction a migration is applied in. */\nexport type MigrationDirection = \"up\" | \"down\";\n\n/** A migration's bookkeeping identity, recorded in the migrations-tracking table. */\nexport interface MigrationRecord {\n tag: string;\n file: string;\n /** sha of the migration file at apply time (drift detection). */\n checksum: string;\n}\n\n/**\n * The apply-time, dialect-specific half of the migration runner. The orchestration (which\n * migrations are pending, ordering, the lock-then-loop) stays driver-neutral in cli/migrate.ts;\n * this capability owns the SQL: the tracking table, the applied-records, the advisory lock, and the\n * atomic apply+record. A driver WITHOUT it can't run migrations (diff/gen still work). `Conn` is the\n * driver's own connection type.\n */\nexport interface MigrationStore<Conn = unknown> {\n /** This dialect's migration-file extension, e.g. `\".surql\"` (SurrealDB) or `\".sql\"` (Postgres). */\n readonly extension: string;\n /** Render a diff as this dialect's migration-file body (e.g. SurrealQL `IF $direction` up/down). */\n render(tag: string, diff: Diff): string;\n /** Ensure the migrations-tracking table exists. */\n ensure(conn: Conn, table: string): Promise<void>;\n /** Applied migrations: tag -> checksum recorded at apply time. */\n applied(conn: Conn, table: string): Promise<Map<string, string>>;\n /**\n * Apply one migration's `up`/`down` PROGRAM plus its bookkeeping write atomically: on `up` record\n * the migration, on `down` erase it — so the record is written iff the DDL actually applied.\n */\n apply(\n conn: Conn,\n table: string,\n m: {\n content: string;\n direction: MigrationDirection;\n record: MigrationRecord;\n },\n ): Promise<void>;\n /** Record a migration as applied WITHOUT running its DDL (baseline of an existing DB). */\n record(conn: Conn, table: string, record: MigrationRecord): Promise<void>;\n /** Drop all applied records (baseline-squash reconcile). */\n clear(conn: Conn, table: string): Promise<void>;\n /** Take an advisory lock so two runs can't race — throws if already held. */\n lock(conn: Conn, table: string): Promise<void>;\n /** Release the advisory lock (idempotent). */\n unlock(conn: Conn, table: string): Promise<void>;\n}\n\n/**\n * An OPTIONAL throwaway-instance capability for round-trip canonicalization and `sz check`'s\n * migration replay. Absent -> `check`/replay-verification is degraded/unavailable (diff/apply still\n * work, since a kind's `lower`/`introspectAll` already canonicalize).\n */\nexport interface ShadowCapability<Conn> {\n /** Apply `ddl` to a fresh scratch DB, introspect it back to portable objects, then drop it. */\n roundTrip(\n conn: Conn,\n config: ResolvedConfig,\n ddl: string,\n ): Promise<PortableObject[]>;\n /** Spin up a fully-isolated ephemeral instance (for migration replay). Caller must `stop()`. */\n ephemeral?(): Promise<{ conn: Conn; stop: () => Promise<void> }>;\n}\n\n/**\n * A database dialect, expressed as a SET OF KINDS (core-v2). The driver registers its object kinds on\n * `registry`; core orchestrates schema ops GENERICALLY over it (`lowerSchema`/`buildKindDiff`/\n * `emitKinds`/`orderObjects`) — it never names a kind. The driver owns only what isn't generic: the\n * authoring -> kinded `explode`, a single-read `introspectAll`, the connection lifecycle, and the\n * dialect-specific command capabilities. The field/type substrate (`PortableType`/`s.*`) stays core.\n * See docs/kind-registry-flip-plan.md.\n */\nexport interface Driver<\n Conn = unknown,\n Tbl extends Authored = Authored,\n Def extends AuthoredDef = AuthoredDef,\n> {\n readonly name: string;\n\n // --- kind registry (the schema engine) -----------------------------------------------------\n /** This driver's registered KINDS. Core runs lower/diff/emit/order generically over it. */\n readonly registry: KindRegistry;\n /**\n * Authoring (loaded `defineTable`/standalone defs) -> kinded {@link Definable}s. The driver-side\n * fan-out: one inline-authored table explodes into `[table, ...index, ...event/constraint]`, each\n * tagged with its `kind`. Core then lowers via `lowerSchema(registry, explode(...))` — so\n * `KindEngine.lower` stays 1:1 and the contract needs no explode hook.\n */\n explode(tables: Tbl[], defs: Def[]): Definable[];\n /**\n * Live connection -> ALL portable objects, fanned across kinds from ONE read (INFO STRUCTURE /\n * pg_catalog). Must canonicalize IDENTICALLY to lowering (a clean apply round-trips to a zero diff)\n * and be COMPLETE (return every diffable kind, else presence-phantom-diffs). `exclude` skips tables\n * by name.\n */\n introspectAll(conn: Conn, exclude?: Set<string>): Promise<PortableObject[]>;\n\n // --- execution -----------------------------------------------------------------------------\n connect(config: ResolvedConfig, over?: ConnectionOverrides): Promise<Conn>;\n apply(conn: Conn, statements: string[], opts?: ApplyOptions): Promise<void>;\n /** Tear down a connection opened by {@link connect} (the orchestration owns the lifecycle). */\n close(conn: Conn): Promise<void>;\n\n // --- optional capabilities -----------------------------------------------------------------\n readonly shadow?: ShadowCapability<Conn>;\n /** Apply-time migration bookkeeping. Absent -> this driver can't run migrations (diff/gen still do). */\n readonly migrations?: MigrationStore<Conn>;\n\n // --- optional COMMAND capabilities ---------------------------------------------------------\n // The dialect-agnostic CLI routes each schema-syncing command through one of these. A driver that\n // omits a capability makes that command unavailable on it — the CLI never hardcodes `if surreal`.\n\n /**\n * Diff the LIVE database against the loaded schema into executable up/down DDL. Owns every\n * dialect-specific normalization and apply-time fixup (Surreal: a shadow-DB round-trip to cancel\n * formatting noise, the redacted-access-key swap, and the implicit-wildcard OVERWRITE re-mark), so\n * the result is safe to apply as-is. Backs `diff --live`, `push`, and the baseline reconcile.\n */\n diffLive?(conn: Conn, config: ResolvedConfig, filter: Filter): Promise<Diff>;\n /** Reduce a live diff (from {@link diffLive}) to the statements `push` applies; `prune: false` keeps removals. */\n syncPlan?(diff: Diff, prune?: boolean): string[];\n /**\n * Render portable objects to per-file source in THIS dialect's `s.*` syntax, filtered — the codegen\n * behind the offline `diff --ts` and `pull`. Takes `PortableObject[]` (this driver's own portable\n * shape): `diff --ts` renders the SNAPSHOT side (stored portable) and the DESIRED side\n * (`lowerSchema(explode(...))`) at MATCHING fidelity so an in-sync schema yields identical files;\n * `pull` renders the introspected DB. The driver re-derives its structured form from the portable\n * objects (parsing its own DDL where needed — docs/kind-registry-flip-plan.md §6b). `single` (a file\n * key) folds everything into one module; otherwise `fileFor` maps each object to its own file.\n */\n renderSchema?(\n objects: PortableObject[],\n filter: Filter,\n fileFor: (kind: string, name: string) => string,\n single?: string,\n ): Map<string, string>;\n /**\n * The two sides of `diff --ts --live` rendered to per-file source: the live DB (`current`) and the\n * declared schema (`desired`), both normalized through the dialect so an unchanged schema yields\n * identical files.\n */\n diffTsLive?(\n conn: Conn,\n config: ResolvedConfig,\n filter: Filter,\n fileFor: (kind: string, name: string) => string,\n single?: string,\n ): Promise<{ current: Map<string, string>; desired: Map<string, string> }>;\n /**\n * Replay every migration into a throwaway engine and diff the result against the schema (`check`).\n * Owns ephemeral-engine selection + setup; `log` receives progress lines. Needs a {@link shadow}-\n * class capability. An empty diff means the migrations reproduce the schema.\n */\n checkReplay?(\n config: ResolvedConfig,\n over: ConnectionOverrides,\n filter: Filter,\n log: (msg: string) => void,\n ): Promise<Diff>;\n /** Introspect the live DB and plan schema-file codegen (`pull`); writing is the neutral `applyPull`. */\n planPull?(\n conn: Conn,\n config: ResolvedConfig,\n opts: { filter: Filter; keepLocal?: boolean },\n ): Promise<PullPlan>;\n /** A human-readable server identity for `doctor` (e.g. \"SurrealDB 3.1.3\"); throws if unreachable. */\n serverInfo?(conn: Conn): Promise<string>;\n /**\n * Run a raw READ query and return rows — for connection RESOLVERS (a multi-connection resolver's\n * `ctx.connections.<name>.query(...)`) and `seed`. The `sql` is this dialect's query language; the\n * orchestration treats the rows opaquely. Absent -> a resolver can't read from this connection.\n */\n query?<T = unknown>(\n conn: Conn,\n sql: string,\n vars?: Record<string, unknown>,\n ): Promise<T[]>;\n /**\n * The dialect-specific files `schemic init` scaffolds, keyed by project-relative path: a\n * connections-only `schemic.config.ts` (using this driver's `<driver>Connection` factory), a sample\n * schema module in this dialect's `s.*`, a seed stub, a `.env.example`, … The CLI writes them\n * verbatim (never overwriting) alongside the dialect-neutral migration snapshot it records itself.\n * Absent -> `schemic init` can't scaffold a project for this driver.\n */\n initScaffold?(): Record<string, string>;\n /**\n * Scaffold a NEW entity file's contents — the starter `s.*` / `define*` module for an object of\n * `kind` named `name` (e.g. `(\"table\", \"user\")` -> a `defineTable(\"user\", { … })` module in this\n * dialect's authoring). Returns the file text; the CLI writes it under the kind's\n * {@link KindRegistry.display} folder. THROW for a kind this driver can't author (the CLI surfaces\n * the message). Absent -> `schemic new` is unavailable for this driver.\n */\n scaffoldEntity?(kind: string, name: string): string;\n}\n\n// --- Registry -----------------------------------------------------------------------------------\n\nconst REGISTRY = new Map<string, Driver<unknown>>();\n\n/** Register a driver under its `name` (idempotent; last write wins). */\nexport function registerDriver(driver: Driver<unknown>): void {\n REGISTRY.set(driver.name, driver);\n}\n\n/** Look up a registered driver, or throw with the list of known names. */\nexport function getDriver(name: string): Driver<unknown> {\n const d = REGISTRY.get(name);\n if (!d) {\n const known = [...REGISTRY.keys()].join(\", \") || \"(none registered)\";\n throw new Error(`Unknown database driver \"${name}\". Registered: ${known}.`);\n }\n return d;\n}\n\n/** All registered driver names (for help text / config validation). */\nexport function driverNames(): string[] {\n return [...REGISTRY.keys()];\n}\n"],"mappings":";AA2BA,IAAM,SAAS,CAAC,MAAW,GAAG,EAAE,IAAI,IAAI,EAAE,IAAI;AAmBvC,SAAS,aACd,OACA,WACK;AACL,QAAMA,SAAQ,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACtD,QAAM,QAAQ,IAAI,IAAoB,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACtE,QAAM,aAAa,oBAAI,IAAsB;AAC7C,aAAW,KAAK;AACd,eAAW,KAAK,EAAE,MAAM;AACtB,UAAI,CAACA,OAAM,IAAI,OAAO,CAAC,CAAC,EAAG;AAC3B,YAAM,IAAI,OAAO,CAAC,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,CAAC;AACpD,YAAM,OAAO,WAAW,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC;AAC3C,WAAK,KAAK,OAAO,CAAC,CAAC;AACnB,iBAAW,IAAI,OAAO,CAAC,GAAG,IAAI;AAAA,IAChC;AAEF,QAAM,MAAW,CAAC;AAClB,QAAM,OAAO,oBAAI,IAAY;AAC7B,MAAI;AACJ,SAAO,IAAI,SAAS,MAAM,QAAQ;AAChC,UAAM,QAAQ,MAAM;AAAA,MAClB,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,MAAM;AAAA,IAC1D;AACA,QAAI,MAAM,WAAW;AACnB,YAAM,IAAI;AAAA,QACR,2BAA2B,MACxB,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,EAClC,IAAI,MAAM,EACV,KAAK,IAAI,CAAC;AAAA,MACf;AACF,UAAM,KAAK,CAAC,GAAG,MAAM;AACnB,YAAM,KAAK,EAAE,SAAS,OAAO,EAAE,KAAK,MAAM,QAAQ,IAAI;AACtD,YAAM,KAAK,EAAE,SAAS,OAAO,EAAE,KAAK,MAAM,QAAQ,IAAI;AACtD,aACE,KAAK,MACL,UAAU,EAAE,IAAI,IAAI,UAAU,EAAE,IAAI,KACpC,OAAO,CAAC,EAAE,cAAc,OAAO,CAAC,CAAC;AAAA,IAErC,CAAC;AACD,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,KAAK,IAAI;AACb,SAAK,IAAI,OAAO,IAAI,CAAC;AACrB,QAAI,CAAC,KAAK,MAAO,SAAQ,OAAO,IAAI;AACpC,eAAW,OAAO,WAAW,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC;AACjD,YAAM,IAAI,MAAM,MAAM,IAAI,GAAG,KAAK,KAAK,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAQO,SAAS,YACd,UACA,MACkB;AAClB,QAAM,MAAwB,CAAC;AAC/B,aAAW,KAAK,MAAM;AACpB,UAAM,SAAS,SAAS,OAAO,EAAE,IAAI;AACrC,QAAI,OAAQ,KAAI,KAAK,OAAO,MAAM,CAAC,CAAC;AAAA,EACtC;AACA,SAAO;AACT;AAYO,SAAS,cAAc,QAAwC;AACpE,QAAM,QAA0C,CAAC;AACjD,aAAW,KAAK,QAAQ;AACtB,UAAM,SAAS,MAAM,EAAE,IAAI,KAAK,CAAC;AACjC,WAAO,KAAK,CAAC;AACb,UAAM,EAAE,IAAI,IAAI;AAAA,EAClB;AACA,SAAO,EAAE,MAAM;AACjB;AAGO,SAAS,gBAAgB,MAAsC;AACpE,SAAO,OAAO,OAAO,KAAK,KAAK,EAAE,KAAK;AACxC;AAkBA,IAAM,cAAc,CAAC,QAAoB,MACvC,OAAO,YAAY,CAAC,KAAK,OAAO,KAAK,CAAC,EAAE,KAAK,IAAI;AAEnD,IAAM,cAAc,CAClB,QACA,cACe;AAAA,EACf,MAAM,SAAS;AAAA,EACf,MAAM,SAAS;AAAA,EACf,MAAM,OAAO,OAAO,QAAQ,KAAK,CAAC;AAAA,EAClC,OAAO,OAAO,QAAQ,QAAQ;AAChC;AAGA,IAAM,UAAU,CAAC,MAAiB,GAAG,EAAE,IAAI,IAAI,EAAE,OAAO,QAAQ,EAAE,IAAI,EAAE,IAAI;AAC5E,IAAM,YAAY,CAAC,MAAiB,EAAE,OAAO,QAAQ,EAAE;AAEvD,IAAM,QAAQ,CAAC,WACb,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AAO3C,SAAS,eACP,UACA,MACA,MAC6C;AAC7C,QAAM,YAAY,MAAM,IAAI;AAC5B,QAAM,YAAY,MAAM,IAAI;AAC5B,QAAM,UAAoB,CAAC;AAC3B,aAAW,KAAK,oBAAI,IAAI,CAAC,GAAG,UAAU,KAAK,GAAG,GAAG,UAAU,KAAK,CAAC,CAAC,GAAG;AACnE,UAAM,IAAI,UAAU,IAAI,CAAC;AACzB,UAAM,IAAI,UAAU,IAAI,CAAC;AACzB,UAAM,WAAW,KAAK;AACtB,QAAI,CAAC,SAAU;AACf,UAAM,SAAS,SAAS,OAAO,SAAS,IAAI;AAC5C,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,YAAY,QAAQ,QAAQ;AACzC,QAAI,KAAK,CAAC,EAAG,SAAQ,KAAK,EAAE,IAAI,UAAU,MAAM,GAAG,GAAG,KAAK,CAAC;AAAA,aACnD,CAAC,KAAK,EAAG,SAAQ,KAAK,EAAE,IAAI,OAAO,MAAM,GAAG,GAAG,KAAK,CAAC;AAAA,aACrD,KAAK,KAAK,YAAY,QAAQ,CAAC,MAAM,YAAY,QAAQ,CAAC;AACjE,cAAQ,KAAK,EAAE,IAAI,UAAU,MAAM,GAAG,MAAM,GAAG,GAAG,KAAK,CAAC;AAAA,EAC5D;AACA,QAAM,MAAM,CAAC,SAAiB,SAAS,QAAQ,IAAI;AACnD,SAAO;AAAA,IACL,YAAY;AAAA,MACV,QAAQ,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ;AAAA,MACvC;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,QAAQ,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,cAAc,CAClB,QACA,GACA,MAEA,OAAO,YAAY,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO,OAAO,CAAC,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC;AAU9D,SAAS,UACd,UACA,MACA,MACU;AACV,QAAM,EAAE,YAAY,QAAQ,IAAI,eAAe,UAAU,MAAM,IAAI;AACnE,QAAM,KAAe,CAAC;AACtB,QAAM,OAAiB,CAAC;AACxB,aAAW,KAAK,YAAY;AAC1B,UAAM,IAAI,SAAS,OAAO,EAAE,IAAI;AAChC,QAAI,CAAC,EAAG;AACR,QAAI,EAAE,OAAO,SAAS,EAAE,KAAM,IAAG,KAAK,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC;AAAA,aAC9C,EAAE,OAAO,YAAY,EAAE,QAAQ,EAAE;AACxC,SAAG,KAAK,GAAG,YAAY,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC;AAAA,EAC7C;AACA,aAAW,KAAK,CAAC,GAAG,OAAO,EAAE,QAAQ,GAAG;AACtC,UAAM,IAAI,SAAS,OAAO,EAAE,IAAI;AAChC,QAAI,KAAK,EAAE,KAAM,IAAG,KAAK,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9C;AACA,aAAW,KAAK,SAAS;AACvB,UAAM,IAAI,SAAS,OAAO,EAAE,IAAI;AAChC,QAAI,KAAK,EAAE,KAAM,MAAK,KAAK,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC;AAAA,EAC9C;AACA,aAAW,KAAK,CAAC,GAAG,UAAU,EAAE,QAAQ,GAAG;AACzC,UAAM,IAAI,SAAS,OAAO,EAAE,IAAI;AAChC,QAAI,CAAC,EAAG;AACR,QAAI,EAAE,OAAO,SAAS,EAAE,KAAM,MAAK,KAAK,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,aAClD,EAAE,OAAO,YAAY,EAAE,QAAQ,EAAE;AACxC,WAAK,KAAK,GAAG,YAAY,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC;AAAA,EAC/C;AACA,SAAO,EAAE,IAAI,KAAK;AACpB;AAOA,SAAS,UACP,UACA,YACA,SACY;AACZ,QAAM,QAAoB,CAAC;AAC3B,QAAM,OAAO,CAAC,MAAc;AAC1B,UAAM,IAAI,SAAS,OAAO,EAAE,IAAI;AAChC,QAAI,CAAC,EAAG;AACR,QAAI,EAAE,cAAc;AAClB,YAAM,KAAK,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC;AAC5C;AAAA,IACF;AACA,UAAM,OAAO,EAAE,KAAK,QAAQ,CAAC,GAAG,OAAO,UAAU,CAAC,GAAG,MAAM,EAAE,KAAK;AAClE,QAAI,EAAE,OAAO,SAAS,EAAE;AACtB,YAAM,KAAK,EAAE,GAAG,MAAM,IAAI,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;AAAA,aAC1D,EAAE,OAAO,YAAY,EAAE;AAC9B,YAAM,KAAK;AAAA,QACT,GAAG;AAAA,QACH,IAAI;AAAA,QACJ,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,QAC/B,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,MAC/B,CAAC;AAAA,aACM,EAAE,OAAO,YAAY,EAAE,QAAQ,EAAE;AACxC,YAAM,KAAK;AAAA,QACT,GAAG;AAAA,QACH,IAAI;AAAA,QACJ,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,QAChC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,MACjC,CAAC;AAAA,EACL;AACA,aAAW,KAAK,WAAY,MAAK,CAAC;AAClC,aAAW,KAAK,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAG,MAAK,CAAC;AAC9C,SAAO;AACT;AAQO,SAAS,cACd,UACA,MACA,MACM;AACN,QAAM,EAAE,YAAY,QAAQ,IAAI,eAAe,UAAU,MAAM,IAAI;AACnE,QAAM,EAAE,IAAI,KAAK,IAAI,UAAU,UAAU,MAAM,IAAI;AAGnD,QAAM,OAAO,cAAc,UAAU,IAAI,EAAE;AAAA,IACzC,CAAC,EAAE,QAAQ,UAAU,KAAK,MAAM;AAC9B,UAAI,OAAO;AACT,eAAO,OAAO,aAAa,QAAW,QAAQ,EAAE,IAAI,CAAC,QAAQ;AAAA,UAC3D,KAAK,GAAG;AAAA,UACR,OAAO,GAAG;AAAA,UACV,KAAK,GAAG,OAAO,QAAQ,GAAG,MAAM;AAAA,QAClC,EAAE;AACJ,aAAO;AAAA,QACL;AAAA,UACE,KAAK,QAAQ,IAAI;AAAA,UACjB,OAAO,UAAU,IAAI;AAAA,UACrB,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,IAAI;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,IAAI,MAAM,OAAO,UAAU,UAAU,YAAY,OAAO,GAAG,KAAK;AAC3E;AAGA,SAAS,cACP,UACA,QACqE;AACrE,QAAM,QAAQ,OAAO,QAAQ,CAAC,aAAa;AACzC,UAAM,SAAS,SAAS,OAAO,SAAS,IAAI;AAC5C,WAAO,SACH,CAAC,EAAE,QAAQ,UAAU,MAAM,YAAY,QAAQ,QAAQ,EAAE,CAAC,IAC1D,CAAC;AAAA,EACP,CAAC;AACD,QAAM,MAAM,IAAI;AAAA,IACd;AAAA,MACE,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,MACvB,CAAC,MAAM,SAAS,QAAQ,CAAC;AAAA,IAC3B,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAAA,EACjC;AACA,SAAO,MAAM;AAAA,IACX,CAAC,GAAG,OAAO,IAAI,IAAI,QAAQ,EAAE,IAAI,CAAC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,IAAI,CAAC,KAAK;AAAA,EAC3E;AACF;AAMO,SAAS,UACd,UACA,QACU;AACV,SAAO,cAAc,UAAU,MAAM,EAAE;AAAA,IAAQ,CAAC,EAAE,QAAQ,SAAS,MACjE,OAAO,KAAK,QAAQ;AAAA,EACtB;AACF;AASA,eAAsB,gBACpB,UACA,MAC2B;AAC3B,QAAM,MAAwB,CAAC;AAC/B,aAAW,CAAC,EAAE,MAAM,KAAK,SAAS,QAAQ,GAAG;AAC3C,QAAI,CAAC,OAAO,WAAY;AACxB,QAAI,KAAK,GAAI,MAAM,OAAO,WAAW,IAAI,CAAE;AAAA,EAC7C;AACA,SAAO;AACT;;;ACzPA,SAAS,WAAW,GAAmB;AACrC,SAAO,IAAI,EAAE,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,IAAI;AAC/C;AAGA,SAAS,UAAU,GAAmB;AACpC,MAAI,cAAc,KAAK,CAAC,EAAG,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC;AACnD,MAAI,kBAAkB,KAAK,CAAC,EAAG,QAAO,GAAG,CAAC;AAC1C,SAAO,GAAG,CAAC;AACb;AAGA,SAAS,QAAQ,GAAmB;AAClC,SAAO,EACJ,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE;AAC3B;AAQO,IAAM,eAAN,MAAmB;AAAA;AAAA;AAAA;AAAA,EAIP,QAAQ,oBAAI,IAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ/D,OAIE,MAAoC;AACpC,SAAK,MAAM,IAAI,KAAK,MAAM,IAAI;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA,EAIA,OAAO,MAAgD;AACrD,WAAO,KAAK,MAAM,IAAI,IAAI;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,MAA+B;AACrC,UAAM,IAAI,KAAK,MAAM,IAAI,IAAI,GAAG,WAAW,CAAC;AAC5C,UAAM,QAAQ,EAAE,SAAS,WAAW,IAAI;AACxC,UAAM,SAAS,EAAE,UAAU,UAAU,KAAK;AAC1C,WAAO,EAAE,OAAO,QAAQ,QAAQ,EAAE,UAAU,QAAQ,MAAM,EAAE;AAAA,EAC9D;AAAA;AAAA,EAGA,QAAkB;AAChB,WAAO,CAAC,GAAG,KAAK,MAAM,KAAK,CAAC;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,MAAsB;AAC5B,UAAM,IAAI,KAAK,MAAM,EAAE,QAAQ,IAAI;AACnC,WAAO,MAAM,KAAK,OAAO,mBAAmB;AAAA,EAC9C;AAAA;AAAA;AAAA,EAIA,UAA4C;AAC1C,WAAO,CAAC,GAAG,KAAK,MAAM,QAAQ,CAAC;AAAA,EACjC;AACF;;;ACuDA,IAAM,WAAW,oBAAI,IAA6B;AAG3C,SAAS,eAAe,QAA+B;AAC5D,WAAS,IAAI,OAAO,MAAM,MAAM;AAClC;AAGO,SAAS,UAAU,MAA+B;AACvD,QAAM,IAAI,SAAS,IAAI,IAAI;AAC3B,MAAI,CAAC,GAAG;AACN,UAAM,QAAQ,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE,KAAK,IAAI,KAAK;AACjD,UAAM,IAAI,MAAM,4BAA4B,IAAI,kBAAkB,KAAK,GAAG;AAAA,EAC5E;AACA,SAAO;AACT;AAGO,SAAS,cAAwB;AACtC,SAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAC5B;","names":["byKey"]}
|
|
1
|
+
{"version":3,"sources":["../src/kind/plan.ts","../src/kind/registry.ts","../src/driver/driver.ts"],"sourcesContent":["// The GENERIC migration spine over a {@link KindRegistry} — core's kind-blind orchestration. It\n// classifies each portable object as add/change/remove, ORDERS them across kinds by a dependency\n// graph, and emits up/down DDL + the display {@link Diff}. It never names a kind: every kind-specific\n// decision is delegated to that kind's {@link KindEngine}.\n//\n// The spine works on PORTABLE objects (both sides already lowered), exactly like the fixed-slot\n// `Driver.diff(prev, next)`: the stored snapshot IS portable, and the authoring side is lowered once\n// via {@link lowerSchema}. So `prev` is a snapshot, `next` is `lowerSchema(registry, defs)`.\n//\n// Cross-kind ordering is the load-bearing part (docs/kind-registry.md §7.1). THREE layers:\n// 1. dependency GRAPH + topological sort -> CORRECTNESS (an object emits after everything it deps on)\n// 2. kind ORDINAL (registration order) -> stable TIE-BREAK among independent objects (layering)\n// 3. OWNER clustering -> READABILITY (an index right after its table)\n// A per-kind ordinal ALONE is wrong: a table's event can call a function, so the function must emit\n// BEFORE the table — a function-before-table the graph handles and an ordinal cannot. Drops reverse it.\n\n// NOTE: `Diff`/`DiffItem` are a type-only import (erased at compile — no runtime cli->kind coupling),\n// the same arrangement as ./driver/portable-diff.ts.\nimport type { Diff, DiffItem } from \"../cli-kit/diff\";\nimport type {\n Definable,\n KindEngine,\n KindRegistry,\n PortableObject,\n Ref,\n} from \"./registry\";\n\nconst refKey = (r: Ref) => `${r.kind}:${r.name}`;\n\n/** A node in the dependency graph: identity + the edges/owner used to order it. */\nexport interface OrderNode {\n readonly kind: string;\n readonly name: string;\n /** Objects this node must come AFTER (only intra-set refs constrain; external refs are ignored). */\n readonly deps: Ref[];\n /** Owning object to cluster next to (readability tie-break only; never overrides `deps`). */\n readonly owner?: Ref;\n}\n\n/**\n * Kahn's topological sort with two presentation tweaks among the nodes whose deps are all satisfied:\n * prefer one OWNED by the currently-open cluster (so a table's children follow it), then lowest\n * (kind-ordinal, then name). Correctness (deps) always wins — an owned/low-ordinal node can't jump a\n * dependency. A genuine cycle throws (a named error). Refs to nodes outside `nodes` are ignored (an\n * object may depend on something untouched by this diff — it already exists / isn't changing).\n */\nexport function orderObjects<T extends OrderNode>(\n nodes: T[],\n ordinalOf: (kind: string) => number,\n): T[] {\n const byKey = new Map(nodes.map((n) => [refKey(n), n]));\n const indeg = new Map<string, number>(nodes.map((n) => [refKey(n), 0]));\n const dependents = new Map<string, string[]>();\n for (const n of nodes)\n for (const d of n.deps) {\n if (!byKey.has(refKey(d))) continue; // external dep -> not a constraint within this set\n indeg.set(refKey(n), (indeg.get(refKey(n)) ?? 0) + 1);\n const list = dependents.get(refKey(d)) ?? [];\n list.push(refKey(n));\n dependents.set(refKey(d), list);\n }\n\n const out: T[] = [];\n const done = new Set<string>();\n let group: string | undefined; // the last unowned node emitted == the open cluster\n while (out.length < nodes.length) {\n const ready = nodes.filter(\n (n) => !done.has(refKey(n)) && indeg.get(refKey(n)) === 0,\n );\n if (ready.length === 0)\n throw new Error(\n `dependency cycle among: ${nodes\n .filter((n) => !done.has(refKey(n)))\n .map(refKey)\n .join(\", \")}`,\n );\n ready.sort((a, b) => {\n const ao = a.owner && refKey(a.owner) === group ? 0 : 1; // prefer the open cluster\n const bo = b.owner && refKey(b.owner) === group ? 0 : 1;\n return (\n ao - bo ||\n ordinalOf(a.kind) - ordinalOf(b.kind) ||\n refKey(a).localeCompare(refKey(b))\n );\n });\n const next = ready[0];\n out.push(next);\n done.add(refKey(next));\n if (!next.owner) group = refKey(next); // a top-level object opens a new cluster\n for (const dep of dependents.get(refKey(next)) ?? [])\n indeg.set(dep, (indeg.get(dep) ?? 1) - 1);\n }\n return out;\n}\n\n// --- lowering + snapshot ------------------------------------------------------------------------\n\n/**\n * Author -> portable: lower each definable through its kind's engine (skipping unregistered kinds).\n * The single place authoring becomes portable; everything downstream (diff/emit/snapshot) is portable.\n */\nexport function lowerSchema(\n registry: KindRegistry,\n defs: Definable[],\n): PortableObject[] {\n const out: PortableObject[] = [];\n for (const d of defs) {\n const engine = registry.engine(d.kind);\n if (engine) out.push(engine.lower(d));\n }\n return out;\n}\n\n/**\n * The registry SNAPSHOT — portable objects grouped by kind. The open, generic replacement for\n * `PortableDb`'s fixed slots; serializes as plain JSON (it is plain data). Pre-launch: the format is\n * free to change, no version migration.\n */\nexport interface KindSnapshot {\n kinds: Record<string, PortableObject[]>;\n}\n\n/** Group a flat portable schema into a snapshot (by kind). */\nexport function snapshotKinds(schema: PortableObject[]): KindSnapshot {\n const kinds: Record<string, PortableObject[]> = {};\n for (const o of schema) {\n const bucket = kinds[o.kind] ?? [];\n bucket.push(o);\n kinds[o.kind] = bucket;\n }\n return { kinds };\n}\n\n/** Flatten a snapshot back into a portable schema (the inverse of {@link snapshotKinds}). */\nexport function snapshotObjects(snap: KindSnapshot): PortableObject[] {\n return Object.values(snap.kinds).flat();\n}\n\n// --- diff / plan --------------------------------------------------------------------------------\n\n/** One classified object change, carrying its ordering metadata + the portable sides for DDL. */\ninterface Change extends OrderNode {\n readonly op: \"add\" | \"change\" | \"remove\";\n readonly prev?: PortableObject;\n readonly next?: PortableObject;\n}\n\n/** An up/down DDL program (each a list of statements). */\nexport interface KindPlan {\n up: string[];\n down: string[];\n}\n\n/** The canonical change-detection key for an object — the kind's `canonical`, else its emitted DDL. */\nconst canonicalOf = (engine: KindEngine, p: PortableObject): string =>\n engine.canonical?.(p) ?? engine.emit(p).join(\"\\n\");\n\nconst orderNodeOf = (\n engine: KindEngine,\n portable: PortableObject,\n): OrderNode => ({\n kind: portable.kind,\n name: portable.name,\n deps: engine.deps?.(portable) ?? [],\n owner: engine.owner?.(portable),\n});\n\n/** Display identity: `kind:owner:name` (owner blank for a top-level object) + the display owner. */\nconst itemKey = (n: OrderNode) => `${n.kind}:${n.owner?.name ?? \"\"}:${n.name}`;\nconst itemTable = (n: OrderNode) => n.owner?.name ?? n.name;\n\nconst byKey = (schema: PortableObject[]) =>\n new Map(schema.map((o) => [refKey(o), o]));\n\n/**\n * Classify both sides into ordered add/change/remove sets — the shared core of plan + diff. A `change`\n * is two objects of the same key whose emitted DDL differs (same test as the fixed-slot engine). Each\n * class is topologically ordered parent-first; the caller reverses one class for drops/inversion.\n */\nfunction orderedChanges(\n registry: KindRegistry,\n prev: PortableObject[],\n next: PortableObject[],\n): { nonRemoves: Change[]; removes: Change[] } {\n const prevByKey = byKey(prev);\n const nextByKey = byKey(next);\n const changes: Change[] = [];\n for (const k of new Set([...prevByKey.keys(), ...nextByKey.keys()])) {\n const p = prevByKey.get(k);\n const n = nextByKey.get(k);\n const portable = n ?? p;\n if (!portable) continue;\n const engine = registry.engine(portable.kind);\n if (!engine) continue;\n const node = orderNodeOf(engine, portable);\n if (p && !n) changes.push({ op: \"remove\", prev: p, ...node });\n else if (!p && n) changes.push({ op: \"add\", next: n, ...node });\n else if (p && n && canonicalOf(engine, p) !== canonicalOf(engine, n))\n changes.push({ op: \"change\", prev: p, next: n, ...node });\n }\n const ord = (kind: string) => registry.ordinal(kind);\n return {\n nonRemoves: orderObjects(\n changes.filter((c) => c.op !== \"remove\"),\n ord,\n ),\n removes: orderObjects(\n changes.filter((c) => c.op === \"remove\"),\n ord,\n ),\n };\n}\n\nconst overwriteUp = (\n engine: KindEngine,\n a: PortableObject,\n b: PortableObject,\n): string[] =>\n engine.overwrite?.(a, b) ?? [...engine.remove(a), ...engine.emit(b)];\n\n/**\n * Diff two portable schema states into an executable up/down program, generically over the registry.\n *\n * `up` runs creates/changes parent-first (the dependency graph) then drops child-first; `down` is the\n * mirror: recreate drops parent-first, then undo creates/changes child-first. We invert PER OBJECT (not\n * by reversing the flat DDL list) so a kind's multi-line block — a table emitted with its fields —\n * keeps its internal order in both directions.\n */\nexport function planKinds(\n registry: KindRegistry,\n prev: PortableObject[],\n next: PortableObject[],\n): KindPlan {\n const { nonRemoves, removes } = orderedChanges(registry, prev, next);\n const up: string[] = [];\n const down: string[] = [];\n for (const c of nonRemoves) {\n const e = registry.engine(c.kind);\n if (!e) continue;\n if (c.op === \"add\" && c.next) up.push(...e.emit(c.next));\n else if (c.op === \"change\" && c.prev && c.next)\n up.push(...overwriteUp(e, c.prev, c.next));\n }\n for (const c of [...removes].reverse()) {\n const e = registry.engine(c.kind); // drops child-first\n if (e && c.prev) up.push(...e.remove(c.prev));\n }\n for (const c of removes) {\n const e = registry.engine(c.kind); // recreate dropped objects parent-first\n if (e && c.prev) down.push(...e.emit(c.prev));\n }\n for (const c of [...nonRemoves].reverse()) {\n const e = registry.engine(c.kind); // undo creates/changes child-first\n if (!e) continue;\n if (c.op === \"add\" && c.next) down.push(...e.remove(c.next));\n else if (c.op === \"change\" && c.prev && c.next)\n down.push(...overwriteUp(e, c.next, c.prev));\n }\n return { up, down };\n}\n\n/**\n * Display items for a change set, in up order (creates/changes parent-first, drops child-first). A kind\n * with `displayItems` decomposes into FINE-grained sub-items (per-field, each carrying its `table` so\n * the display groups them under it); otherwise it falls back to ONE whole-object item.\n */\nfunction diffItems(\n registry: KindRegistry,\n nonRemoves: Change[],\n removes: Change[],\n): DiffItem[] {\n const items: DiffItem[] = [];\n const push = (c: Change) => {\n const e = registry.engine(c.kind);\n if (!e) return;\n if (e.displayItems) {\n items.push(...e.displayItems(c.prev, c.next));\n return;\n }\n const base = { key: itemKey(c), table: itemTable(c), kind: c.kind };\n if (c.op === \"add\" && c.next)\n items.push({ ...base, op: \"add\", ddl: e.emit(c.next).join(\"\\n\") });\n else if (c.op === \"remove\" && c.prev)\n items.push({\n ...base,\n op: \"remove\",\n ddl: e.remove(c.prev).join(\"\\n\"),\n old: e.emit(c.prev).join(\"\\n\"),\n });\n else if (c.op === \"change\" && c.prev && c.next)\n items.push({\n ...base,\n op: \"change\",\n before: e.emit(c.prev).join(\"\\n\"),\n after: e.emit(c.next).join(\"\\n\"),\n });\n };\n for (const c of nonRemoves) push(c);\n for (const c of [...removes].reverse()) push(c);\n return items;\n}\n\n/**\n * The full {@link Diff} the CLI + migration model consume — up/down DDL + per-object display items +\n * the whole desired schema (`full`, for `--full`). This is what a driver's `Driver.diff` returns once\n * its kinds are on the registry (the generic counterpart of the fixed-slot `buildDiff`). Source-file\n * linkage on the items is attached by the caller (the snapshot's `files` map), so `file` is left unset.\n */\nexport function buildKindDiff(\n registry: KindRegistry,\n prev: PortableObject[],\n next: PortableObject[],\n): Diff {\n const { nonRemoves, removes } = orderedChanges(registry, prev, next);\n const { up, down } = planKinds(registry, prev, next);\n // `full` mirrors the items' granularity: a kind with `displayItems` projects its object as per-\n // sub-object adds (displayItems(undefined, portable)); otherwise one whole-object entry.\n const full = orderedSchema(registry, next).flatMap(\n ({ engine, portable, node }) => {\n if (engine.displayItems)\n return engine.displayItems(undefined, portable).map((it) => ({\n key: it.key,\n table: it.table,\n ddl: it.op === \"add\" ? it.ddl : \"\",\n }));\n return [\n {\n key: itemKey(node),\n table: itemTable(node),\n ddl: engine.emit(portable).join(\"\\n\"),\n },\n ];\n },\n );\n return { up, down, items: diffItems(registry, nonRemoves, removes), full };\n}\n\n/** Lower-already portable schema, topologically ordered, paired with each object's engine + node. */\nfunction orderedSchema(\n registry: KindRegistry,\n schema: PortableObject[],\n): { engine: KindEngine; portable: PortableObject; node: OrderNode }[] {\n const items = schema.flatMap((portable) => {\n const engine = registry.engine(portable.kind);\n return engine\n ? [{ engine, portable, node: orderNodeOf(engine, portable) }]\n : [];\n });\n const pos = new Map(\n orderObjects(\n items.map((i) => i.node),\n (k) => registry.ordinal(k),\n ).map((n, i) => [itemKey(n), i]),\n );\n return items.sort(\n (a, b) => (pos.get(itemKey(a.node)) ?? 0) - (pos.get(itemKey(b.node)) ?? 0),\n );\n}\n\n/**\n * Fresh-apply DDL for a portable schema: every object created, ordered across kinds by the graph.\n * (The `up` of a diff from an empty state.) Lower authoring first via {@link lowerSchema}.\n */\nexport function emitKinds(\n registry: KindRegistry,\n schema: PortableObject[],\n): string[] {\n return orderedSchema(registry, schema).flatMap(({ engine, portable }) =>\n engine.emit(portable),\n );\n}\n\n/**\n * Reverse direction, fanned out across kinds: introspect every introspectable kind off one live\n * connection and flatten into portable objects. The RESOLUTION of \"per-kind vs one driver read\":\n * the contract is per-kind ({@link KindEngine.introspect}), but a driver backs all of its kinds with\n * ONE shared (memoized) read of `conn` and slices out each kind's objects — so the fan-out here costs\n * a single round-trip, not N. A kind without `introspect` contributes nothing (not introspectable).\n */\nexport async function introspectKinds(\n registry: KindRegistry,\n conn: unknown,\n): Promise<PortableObject[]> {\n const out: PortableObject[] = [];\n for (const [, engine] of registry.entries()) {\n if (!engine.introspect) continue;\n out.push(...(await engine.introspect(conn)));\n }\n return out;\n}\n","// The KIND REGISTRY — core-v2's generic, open replacement for the fixed object-kind slots.\n//\n// Today `PortableDb` hard-codes the object kinds a schema may contain (`tables`/`functions`/\n// `accesses`/`natives`) and the Driver's whole-DB methods switch on those slots. The kind registry\n// turns the slots into a REGISTRY a driver populates: each driver registers KINDS, and every kind\n// brings (a) its OWN authoring builder — any shape/chain it likes, fully typed — and (b) its engine\n// behavior (`lower`/`emit`/`remove`/`overwrite`/`deps`/`owner`/`introspect`) over THAT kind's objects.\n// Core orchestrates generically over the registry (see ./plan.ts) and never names a kind.\n//\n// What stays in core is the field/type VOCABULARY (`SFieldBase`, the Zod-drop-in `s.*`, `PortableType`,\n// codecs) — the substrate every kind builds on. Fields/types are NOT a kind: a table HAS fields, a\n// function's args ARE fields, an index REFERENCES fields. See docs/kind-registry.md.\n//\n// The registry is PER-DRIVER, not a module global: multiple drivers (`@schemic/surrealdb`,\n// `@schemic/postgres`) are registered at once and each defines its own `\"table\"`/`\"function\"`, so a\n// shared global map would collide. A driver builds one `KindRegistry` and registers its kinds into it.\n\n/**\n * An authored definable, tagged with the KIND that owns it. Core dispatches on `kind` alone — every\n * other field is the kind's own business, handed straight to {@link KindEngine.lower}. This is the\n * neutral upper bound for a kind's authoring-object type (a driver's concrete `TableDef`/`FnDef` is a\n * structural subtype).\n */\nexport interface Definable {\n readonly kind: string;\n readonly name: string;\n}\n\n/**\n * A kind's PORTABLE object — the dialect-independent data shape core stores + diffs. A kind chooses\n * how structured this is: a table's portable form carries fields/indexes (so core can field-level\n * diff it); an opaque kind (function/access) carries a neutral identity + a `native` payload it\n * round-trips. Either way it is tagged with `kind`/`name` for cross-kind dispatch + ordering.\n */\nexport interface PortableObject {\n readonly kind: string;\n readonly name: string;\n}\n\n/** A reference to another object in the schema graph — the unit of cross-kind dependency ordering. */\nexport interface Ref {\n readonly kind: string;\n readonly name: string;\n}\n\n// `DiffItem` is a type-only import (erased at compile) — the display contract the `displayItems` hook\n// produces; no runtime cli->kind coupling, same arrangement as ./plan.ts.\nimport type { DiffItem } from \"../cli-kit/diff\";\n\n/**\n * What core needs to orchestrate ONE kind generically — it never inspects the specifics. The\n * change-vocabulary (`emit`/`remove`/`overwrite`) mirrors the Driver contract's, so a kind's behavior\n * is parity-checkable against the fixed-slot engine. `A` is the kind's authoring object, `P` its\n * portable object; both are opaque to core beyond the {@link Definable}/{@link PortableObject} bounds.\n */\nexport interface KindEngine<\n A extends Definable = Definable,\n P extends PortableObject = PortableObject,\n> {\n /** Authoring object -> this kind's portable object (normalized; both lowerings must converge here). */\n lower(authored: A): P;\n /** CREATE DDL for one portable object (a fresh apply / migration `up` for an added object). */\n emit(portable: P): string[];\n /** DROP DDL for one portable object (`up` for a removed object, `down` for an added one). */\n remove(portable: P): string[];\n /**\n * In-place CHANGE DDL taking `prev` to `next` (the dialect's ALTER/OVERWRITE). The spine calls\n * `overwrite(next, prev)` to roll a change back. A kind with no in-place form recreates: implement\n * as `[...remove(prev), ...emit(next)]`. Default (omitted) = recreate via emit(next).\n */\n overwrite?(prev: P, next: P): string[];\n /**\n * The CANONICAL change-detection key: the spine treats prev/next of the same object as a CHANGE iff\n * their `canonical` differs. Default (omitted) = `emit(portable).join(\"\\n\")` — so a kind whose `emit`\n * is already its canonical form needs nothing. Override when `emit` is FAITHFUL but some clauses must\n * be EXCLUDED from equality — because the DB rewrites them on read (PG `'x'` -> `'x'::text`, `a>0` ->\n * `(a>0)`) or never introspects them (a COMMENT, an index) — so a faithful `emit` would phantom-diff a\n * freshly-applied schema against `introspect`. Return `emit` MINUS those clauses: they stay create-time\n * faithful in `emit`, but don't count as changes. `canonical(a) === canonical(b)` MUST mean \"no\n * migration needed\". Affects ONLY classification; `emit`/`overwrite` (the DDL) are unaffected.\n */\n canonical?(portable: P): string;\n /**\n * Fine-grained DISPLAY items for a change of this object — so `schemic diff` shows per-SUB-OBJECT\n * changes (a table decomposes into per-FIELD items: `field:user:name` changed), each carrying its\n * owner `table` so the display GROUPS them hierarchically under it, instead of one coarse whole-object\n * item. Called `(prev, next)`: a change diffs the two; `(undefined, next)` lists the object's\n * sub-items as adds — the `--full` projection core uses for the full desired-state view. Default\n * (omitted) = ONE whole-object item. DISPLAY ONLY — never affects up/down DDL (that is\n * `emit`/`overwrite`); a structured driver reuses the per-field diff it already computes. Leave\n * `DiffItem.file` unset (the caller attaches source linkage).\n */\n displayItems?(prev: P | undefined, next: P | undefined): DiffItem[];\n /**\n * Objects this one must be emitted AFTER — the cross-kind dependency edges (a field/index -> its\n * table; an edge table -> its in/out tables; an event -> its table + any function it calls). Drives\n * the topological sort in ./plan.ts. Omitted = no dependencies.\n */\n deps?(portable: P): Ref[];\n /**\n * The owning object to CLUSTER next to in the emitted order (an index's table) — readability only,\n * never overrides {@link deps}. Omitted = a top-level object.\n */\n owner?(portable: P): Ref | undefined;\n /**\n * Live connection -> all portable objects of THIS kind (the reverse direction). Introspection is\n * often one `INFO`/`pg_catalog` read yielding every kind at once; a driver backs all of its kinds'\n * `introspect` with one shared (memoized) read and slices out this kind's objects. Omitted -> this\n * kind isn't introspectable (diff/emit still work from authored state).\n */\n introspect?(conn: unknown): Promise<P[]>;\n /**\n * How this kind is PRESENTED — its human labels and the folder its objects render into. All optional\n * with sensible defaults off the kind name (see {@link KindRegistry.display}), so a kind only declares\n * what the defaults get wrong (e.g. `plural: \"Indexes\"`, or `folder: \"access\"`). DISPLAY ONLY.\n */\n display?: KindDisplay;\n}\n\n/** Per-kind presentation metadata (labels + output folder). All optional; core fills defaults. */\nexport interface KindDisplay {\n /** Title-Case singular, e.g. `\"Table\"`, `\"Field\"`. Default: the kind name, capitalized. */\n label?: string;\n /** Title-Case plural, e.g. `\"Tables\"`, `\"Indexes\"`. Default: the English plural of `label`. */\n plural?: string;\n /** The directory this kind's objects render into. Default: the lowercase slug of `plural`. */\n folder?: string;\n}\n\n/** A kind's resolved presentation — every field filled (the shape {@link KindRegistry.display} returns). */\nexport type ResolvedDisplay = Required<KindDisplay>;\n\n/** A kind's full spec: its `name`, its `build` (the driver's authoring entry), and its engine. */\nexport type KindSpec<\n Build extends (...args: never[]) => unknown,\n A extends Definable,\n P extends PortableObject,\n> = { name: string; build: Build } & KindEngine<A, P>;\n\n/** `\"table\"` -> `\"Table\"`. */\nfunction capitalize(s: string): string {\n return s ? s[0].toUpperCase() + s.slice(1) : s;\n}\n\n/** A plain English pluralizer for kind labels: `Index` -> `Indexes`, `Policy` -> `Policies`. */\nfunction pluralize(s: string): string {\n if (/[^aeiou]y$/i.test(s)) return `${s.slice(0, -1)}ies`;\n if (/(s|x|z|ch|sh)$/i.test(s)) return `${s}es`;\n return `${s}s`;\n}\n\n/** `\"Tables\"` -> `\"tables\"`; collapses non-alphanumerics to single dashes (a filesystem-safe folder). */\nfunction slugify(s: string): string {\n return s\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\n/**\n * A driver's set of registered kinds + the generic behavior the spine reads off them. Built once per\n * driver; `define` registers a kind and returns the driver's OWN `build` function UNCHANGED — so the\n * driver writes `export const defineTable = registry.define({ name: \"table\", build, ...engine })` and\n * keeps full type-safety + DX (TS preserves a generic `build`'s parameters across the passthrough).\n */\nexport class KindRegistry {\n // Heterogeneous kinds erase at the engine seam (engine ops are structural); the AUTHORING side\n // keeps full types via `define`'s `Build` passthrough.\n // biome-ignore lint/suspicious/noExplicitAny: the engine seam is intentionally type-erased.\n private readonly kinds = new Map<string, KindEngine<any, any>>();\n\n /**\n * Register a KIND. `build` is the driver's own authoring entry — ANY shape/chain — and its type\n * flows through unchanged (type-safety + DX are the driver's to design). The engine fns give core\n * the generic behavior. Registration ORDER is the kind's ordinal (the stable tie-break among\n * independent objects in {@link orderObjects}), so register coarse-to-fine (table before index).\n */\n define<\n Build extends (...args: never[]) => unknown,\n A extends Definable,\n P extends PortableObject,\n >(spec: KindSpec<Build, A, P>): Build {\n this.kinds.set(spec.name, spec);\n return spec.build;\n }\n\n /** The engine for `kind`, or undefined if no such kind is registered. */\n // biome-ignore lint/suspicious/noExplicitAny: the engine erases at this seam (see `kinds`).\n engine(kind: string): KindEngine<any, any> | undefined {\n return this.kinds.get(kind);\n }\n\n /**\n * A kind's resolved presentation — `label`/`plural`/`folder`, with defaults derived from the kind\n * name for whatever the driver left unset. Works for unregistered display sub-kinds too (e.g. the\n * `\"field\"` items a table's `displayItems` emits) — they just get the name-derived defaults.\n */\n display(kind: string): ResolvedDisplay {\n const d = this.kinds.get(kind)?.display ?? {};\n const label = d.label ?? capitalize(kind);\n const plural = d.plural ?? pluralize(label);\n return { label, plural, folder: d.folder ?? slugify(plural) };\n }\n\n /** Registered kind names, in registration order (== ordinal order). */\n names(): string[] {\n return [...this.kinds.keys()];\n }\n\n /**\n * A kind's ORDINAL = its registration index. Used ONLY as a tie-break among objects with no\n * dependency relation, so independent objects come out stably layered (readability); it never\n * overrides the dependency graph. An unknown kind sorts last.\n */\n ordinal(kind: string): number {\n const i = this.names().indexOf(kind);\n return i === -1 ? Number.MAX_SAFE_INTEGER : i;\n }\n\n /** [name, engine] pairs in registration order — the spine iterates these. */\n // biome-ignore lint/suspicious/noExplicitAny: the engine erases at this seam (see `kinds`).\n entries(): [string, KindEngine<any, any>][] {\n return [...this.kinds.entries()];\n }\n}\n","// The DRIVER interface — the dialect seam for multi-DB support (see docs/MULTI-DB-SPIKE.md).\n//\n// Everything dialect-specific lives behind a `Driver`: lowering authoring to the Struct-IR, emitting\n// DDL, introspecting a live DB, normalizing to a canonical form, and executing. Everything ABOVE the\n// driver (the diff algorithm, the magicast TS-merge, the migration model, the CLI shell) stays\n// dialect-free and calls these ops.\n//\n// The connection type is a driver-private parameter `Conn`: the orchestration treats it opaquely and\n// only ever hands it back to the SAME driver. So the Surreal driver is `Driver<Surreal>`, a future\n// Postgres driver is `Driver<PgClient>`, and core never sees either concrete type. The AUTHORING\n// types (`Tbl`/`Def`) are driver-private the same way — opaque to core beyond the neutral\n// `Authored`/`AuthoredDef` bounds — so the neutral engine never names a dialect's concrete builder\n// (`TableDef`/`StandaloneDef`).\n\nimport type { ResolvedConfig } from \"../cli-kit/config\";\nimport type { Diff } from \"../cli-kit/diff\";\nimport type { Filter } from \"../cli-kit/filter\";\nimport type { PullPlan } from \"../cli-kit/merge\";\nimport type { Definable, KindRegistry, PortableObject } from \"../kind\";\n\n/**\n * The dialect-NEUTRAL authoring contract — the only structure the orchestration reads off an\n * authored object (everything else is opaque and handed straight to {@link Driver.explode}). A table\n * contributes just its `name`; this is the upper bound for a driver's table-authoring type. The\n * Surreal `TableDef` is a structural subtype, as is any future dialect's table builder.\n */\nexport interface Authored {\n readonly name: string;\n}\n\n/**\n * The neutral contract for a standalone (non-table) authored object — an event/function/access. It\n * adds a `kind` discriminant and, for objects owned by a table (e.g. an event), the owner `table`\n * name (so the snapshot can file-link a child object under its parent). The Surreal `StandaloneDef`\n * union is a structural subtype.\n */\nexport interface AuthoredDef extends Authored {\n readonly kind: string;\n readonly table?: string;\n}\n\n/**\n * A single emitted DDL statement, structured: object identity (`kind`/`name`/`table`) + the dialect\n * `ddl` string, plus an optional clause map (each value an `ALTER … <set>` form) for dialects that\n * diff clause-level. `kind` is a dialect-defined string the orchestration treats opaquely — the\n * SurrealDB `DefineStatement` (with its fixed kind union) is a structural subtype of this.\n */\nexport interface Statement {\n kind: string;\n name: string;\n table?: string;\n ddl: string;\n clauses?: Record<string, string>;\n}\n\n/** Options for {@link Driver.emit} — mirrors the existing `DefineOptions` (e.g. IF NOT EXISTS). */\nexport interface EmitOptions {\n ifNotExists?: boolean;\n overwrite?: boolean;\n}\n\n/** Options for {@link Driver.apply}. */\nexport interface ApplyOptions {\n /**\n * Run the whole batch atomically. `migrate` wraps up/down + `_migrations` bookkeeping in one\n * transaction; a driver that can't MUST surface that (the migration model degrades to best-effort).\n */\n transactional?: boolean;\n}\n\n/** Per-connection overrides (url/namespace/credentials) — superset across dialects. */\nexport interface ConnectionOverrides {\n url?: string;\n namespace?: string;\n database?: string;\n username?: string;\n password?: string;\n authLevel?: string;\n}\n\n/** The direction a migration is applied in. */\nexport type MigrationDirection = \"up\" | \"down\";\n\n/** A migration's bookkeeping identity, recorded in the migrations-tracking table. */\nexport interface MigrationRecord {\n tag: string;\n file: string;\n /** sha of the migration file at apply time (drift detection). */\n checksum: string;\n}\n\n/**\n * The apply-time, dialect-specific half of the migration runner. The orchestration (which\n * migrations are pending, ordering, the lock-then-loop) stays driver-neutral in cli/migrate.ts;\n * this capability owns the SQL: the tracking table, the applied-records, the advisory lock, and the\n * atomic apply+record. A driver WITHOUT it can't run migrations (diff/gen still work). `Conn` is the\n * driver's own connection type.\n */\nexport interface MigrationStore<Conn = unknown> {\n /** This dialect's migration-file extension, e.g. `\".surql\"` (SurrealDB) or `\".sql\"` (Postgres). */\n readonly extension: string;\n /** Render a diff as this dialect's migration-file body (e.g. SurrealQL `IF $direction` up/down). */\n render(tag: string, diff: Diff): string;\n /** Ensure the migrations-tracking table exists. */\n ensure(conn: Conn, table: string): Promise<void>;\n /** Applied migrations: tag -> checksum recorded at apply time. */\n applied(conn: Conn, table: string): Promise<Map<string, string>>;\n /**\n * Apply one migration's `up`/`down` PROGRAM plus its bookkeeping write atomically: on `up` record\n * the migration, on `down` erase it — so the record is written iff the DDL actually applied.\n */\n apply(\n conn: Conn,\n table: string,\n m: {\n content: string;\n direction: MigrationDirection;\n record: MigrationRecord;\n },\n ): Promise<void>;\n /** Record a migration as applied WITHOUT running its DDL (baseline of an existing DB). */\n record(conn: Conn, table: string, record: MigrationRecord): Promise<void>;\n /** Drop all applied records (baseline-squash reconcile). */\n clear(conn: Conn, table: string): Promise<void>;\n /** Take an advisory lock so two runs can't race — throws if already held. */\n lock(conn: Conn, table: string): Promise<void>;\n /** Release the advisory lock (idempotent). */\n unlock(conn: Conn, table: string): Promise<void>;\n}\n\n/**\n * An OPTIONAL throwaway-instance capability for round-trip canonicalization and `sz check`'s\n * migration replay. Absent -> `check`/replay-verification is degraded/unavailable (diff/apply still\n * work, since a kind's `lower`/`introspectAll` already canonicalize).\n */\nexport interface ShadowCapability<Conn> {\n /** Apply `ddl` to a fresh scratch DB, introspect it back to portable objects, then drop it. */\n roundTrip(\n conn: Conn,\n config: ResolvedConfig,\n ddl: string,\n ): Promise<PortableObject[]>;\n /** Spin up a fully-isolated ephemeral instance (for migration replay). Caller must `stop()`. */\n ephemeral?(): Promise<{ conn: Conn; stop: () => Promise<void> }>;\n}\n\n/**\n * A database dialect, expressed as a SET OF KINDS (core-v2). The driver registers its object kinds on\n * `registry`; core orchestrates schema ops GENERICALLY over it (`lowerSchema`/`buildKindDiff`/\n * `emitKinds`/`orderObjects`) — it never names a kind. The driver owns only what isn't generic: the\n * authoring -> kinded `explode`, a single-read `introspectAll`, the connection lifecycle, and the\n * dialect-specific command capabilities. The field/type substrate (`PortableType`/`s.*`) stays core.\n * See docs/kind-registry-flip-plan.md.\n */\nexport interface Driver<\n Conn = unknown,\n Tbl extends Authored = Authored,\n Def extends AuthoredDef = AuthoredDef,\n> {\n readonly name: string;\n\n // --- kind registry (the schema engine) -----------------------------------------------------\n /** This driver's registered KINDS. Core runs lower/diff/emit/order generically over it. */\n readonly registry: KindRegistry;\n /**\n * Authoring (loaded `defineTable`/standalone defs) -> kinded {@link Definable}s. The driver-side\n * fan-out: one inline-authored table explodes into `[table, ...index, ...event/constraint]`, each\n * tagged with its `kind`. Core then lowers via `lowerSchema(registry, explode(...))` — so\n * `KindEngine.lower` stays 1:1 and the contract needs no explode hook.\n */\n explode(tables: Tbl[], defs: Def[]): Definable[];\n /**\n * Live connection -> ALL portable objects, fanned across kinds from ONE read (INFO STRUCTURE /\n * pg_catalog). Must canonicalize IDENTICALLY to lowering (a clean apply round-trips to a zero diff)\n * and be COMPLETE (return every diffable kind, else presence-phantom-diffs). `exclude` skips tables\n * by name.\n */\n introspectAll(conn: Conn, exclude?: Set<string>): Promise<PortableObject[]>;\n\n // --- execution -----------------------------------------------------------------------------\n connect(config: ResolvedConfig, over?: ConnectionOverrides): Promise<Conn>;\n apply(conn: Conn, statements: string[], opts?: ApplyOptions): Promise<void>;\n /** Tear down a connection opened by {@link connect} (the orchestration owns the lifecycle). */\n close(conn: Conn): Promise<void>;\n\n // --- optional capabilities -----------------------------------------------------------------\n readonly shadow?: ShadowCapability<Conn>;\n /** Apply-time migration bookkeeping. Absent -> this driver can't run migrations (diff/gen still do). */\n readonly migrations?: MigrationStore<Conn>;\n\n // --- optional COMMAND capabilities ---------------------------------------------------------\n // The dialect-agnostic CLI routes each schema-syncing command through one of these. A driver that\n // omits a capability makes that command unavailable on it — the CLI never hardcodes `if surreal`.\n\n /**\n * Diff the LIVE database against the loaded schema into executable up/down DDL. Owns every\n * dialect-specific normalization and apply-time fixup (Surreal: a shadow-DB round-trip to cancel\n * formatting noise, the redacted-access-key swap, and the implicit-wildcard OVERWRITE re-mark), so\n * the result is safe to apply as-is. Backs `diff --live`, `push`, and the baseline reconcile.\n */\n diffLive?(conn: Conn, config: ResolvedConfig, filter: Filter): Promise<Diff>;\n /** Reduce a live diff (from {@link diffLive}) to the statements `push` applies; `prune: false` keeps removals. */\n syncPlan?(diff: Diff, prune?: boolean): string[];\n /**\n * Render portable objects to per-file source in THIS dialect's `s.*` syntax, filtered — the codegen\n * behind the offline `diff --ts` and `pull`. Takes `PortableObject[]` (this driver's own portable\n * shape): `diff --ts` renders the SNAPSHOT side (stored portable) and the DESIRED side\n * (`lowerSchema(explode(...))`) at MATCHING fidelity so an in-sync schema yields identical files;\n * `pull` renders the introspected DB. The driver re-derives its structured form from the portable\n * objects (parsing its own DDL where needed — docs/kind-registry-flip-plan.md §6b). `single` (a file\n * key) folds everything into one module; otherwise `fileFor` maps each object to its own file.\n */\n renderSchema?(\n objects: PortableObject[],\n filter: Filter,\n fileFor: (kind: string, name: string) => string,\n single?: string,\n ): Map<string, string>;\n /**\n * The two sides of `diff --ts --live` rendered to per-file source: the live DB (`current`) and the\n * declared schema (`desired`), both normalized through the dialect so an unchanged schema yields\n * identical files.\n */\n diffTsLive?(\n conn: Conn,\n config: ResolvedConfig,\n filter: Filter,\n fileFor: (kind: string, name: string) => string,\n single?: string,\n ): Promise<{ current: Map<string, string>; desired: Map<string, string> }>;\n /**\n * Replay every migration into a throwaway engine and diff the result against the schema (`check`).\n * Owns ephemeral-engine selection + setup; `log` receives progress lines. Needs a {@link shadow}-\n * class capability. An empty diff means the migrations reproduce the schema.\n */\n checkReplay?(\n config: ResolvedConfig,\n over: ConnectionOverrides,\n filter: Filter,\n log: (msg: string) => void,\n ): Promise<Diff>;\n /** Introspect the live DB and plan schema-file codegen (`pull`); writing is the neutral `applyPull`. */\n planPull?(\n conn: Conn,\n config: ResolvedConfig,\n opts: { filter: Filter; keepLocal?: boolean },\n ): Promise<PullPlan>;\n /** A human-readable server identity for `doctor` (e.g. \"SurrealDB 3.1.3\"); throws if unreachable. */\n serverInfo?(conn: Conn): Promise<string>;\n /**\n * Run a raw READ query and return rows — for connection RESOLVERS (a multi-connection resolver's\n * `ctx.connections.<name>.query(...)`) and `seed`. The `sql` is this dialect's query language; the\n * orchestration treats the rows opaquely. Absent -> a resolver can't read from this connection.\n */\n query?<T = unknown>(\n conn: Conn,\n sql: string,\n vars?: Record<string, unknown>,\n ): Promise<T[]>;\n /**\n * The dialect-specific files `schemic init` scaffolds, keyed by project-relative path: a\n * connections-only `schemic.config.ts` (using this driver's `<driver>Connection` factory), a sample\n * schema module in this dialect's `s.*`, a seed stub, a `.env.example`, … The CLI writes them\n * verbatim (never overwriting) alongside the dialect-neutral migration snapshot it records itself.\n * Absent -> `schemic init` can't scaffold a project for this driver.\n */\n initScaffold?(): Record<string, string>;\n /**\n * Scaffold a NEW entity file's contents — the starter `s.*` / `define*` module for an object of\n * `kind` named `name` (e.g. `(\"table\", \"user\")` -> a `defineTable(\"user\", { … })` module in this\n * dialect's authoring). Returns the file text; the CLI writes it under the kind's\n * {@link KindRegistry.display} folder. THROW for a kind this driver can't author (the CLI surfaces\n * the message). Absent -> `schemic new` is unavailable for this driver.\n */\n scaffoldEntity?(kind: string, name: string): string;\n}\n\n// --- Registry -----------------------------------------------------------------------------------\n\n// Shared across every loaded copy of `@schemic/core` so the registry is process-global — the CLI run\n// via `bunx` resolves its own core, while a driver loaded from the user's project resolves the\n// project's core; without sharing, the driver self-registers in one Map and the CLI reads an empty\n// one. Keyed by a REGISTERED symbol (`Symbol.for`) — same key in every instance, but no string-keyed\n// `globalThis` pollution and namespaced so it can't collide.\nconst REGISTRY_KEY = Symbol.for(\"@schemic/core.driverRegistry\");\nconst REGISTRY: Map<string, Driver<unknown>> = ((\n globalThis as Record<symbol, Map<string, Driver<unknown>> | undefined>\n)[REGISTRY_KEY] ??= new Map<string, Driver<unknown>>());\n\n/** Register a driver under its `name` (idempotent; last write wins). */\nexport function registerDriver(driver: Driver<unknown>): void {\n REGISTRY.set(driver.name, driver);\n}\n\n/** Look up a registered driver, or throw with the list of known names. */\nexport function getDriver(name: string): Driver<unknown> {\n const d = REGISTRY.get(name);\n if (!d) {\n const known = [...REGISTRY.keys()].join(\", \") || \"(none registered)\";\n throw new Error(`Unknown database driver \"${name}\". Registered: ${known}.`);\n }\n return d;\n}\n\n/** All registered driver names (for help text / config validation). */\nexport function driverNames(): string[] {\n return [...REGISTRY.keys()];\n}\n"],"mappings":"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","names":["byKey"]}
|
|
@@ -94,4 +94,4 @@ interface SchemicConfig {
|
|
|
94
94
|
/** Identity helper that types a `schemic.config.ts` default export. */
|
|
95
95
|
declare function defineConfig(config: SchemicConfig): SchemicConfig;
|
|
96
96
|
|
|
97
|
-
export { type ConnectionConfigBase as C, type ResolveContext as R, type SchemicConfig as S, type ConnectionEntry as a, type ConnectionInput as b,
|
|
97
|
+
export { type ConnectionConfigBase as C, type ResolveContext as R, type SchemicConfig as S, type ConnectionEntry as a, type ConnectionInput as b, type ResolvedConnectionHandle as c, connectionEntry as d, defineConfig as e, isConnectionEntry as i };
|
package/lib/config.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { S as SchemicConfig, e as defineConfig } from './config-
|
|
1
|
+
export { S as SchemicConfig, e as defineConfig } from './config-v3H_2lwA.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as jiti from 'jiti';
|
|
2
|
-
import { S as SchemicConfig, C as ConnectionConfigBase } from './config-
|
|
2
|
+
import { S as SchemicConfig, C as ConnectionConfigBase } from './config-v3H_2lwA.js';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -733,4 +733,4 @@ declare function getDriver(name: string): Driver<unknown>;
|
|
|
733
733
|
/** All registered driver names (for help text / config validation). */
|
|
734
734
|
declare function driverNames(): string[];
|
|
735
735
|
|
|
736
|
-
export {
|
|
736
|
+
export { listMigrations as $, type Authored as A, buildKindDiff as B, type ConnectionOverrides as C, type Driver as D, EMPTY_STORED as E, type Filter as F, checksum as G, driverNames as H, emitKinds as I, filterKinds as J, type KindDisplay as K, type LocalOnly as L, type MergeOptions as M, formatDiff as N, type OrderNode as O, type PortableObject as P, formatItems as Q, type Ref as R, type ShadowCapability as S, formatPatch as T, getDriver as U, inCat as V, intersectKinds as W, introspectKinds as X, isEmptyDiff as Y, kindFlags as Z, lineDiff as _, type AuthoredDef as a, loadConfig as a0, loadProject as a1, lowerSchema as a2, makeJiti as a3, mergeStored as a4, mergeUnits as a5, orderObjects as a6, parseFilter as a7, passesFilter as a8, planKinds as a9, readSnapshot as aa, registerDriver as ab, resolveConnectionConfig as ac, slug as ad, snapshotKinds as ae, snapshotObjects as af, summarizeKinds as ag, timestamp as ah, tokenDiff as ai, unifiedDiff as aj, writeSnapshot as ak, type ApplyOptions as b, type Definable as c, type Diff as d, type DiffItem as e, type EmitOptions as f, type FilterOpts as g, type KindEngine as h, type KindPlan as i, KindRegistry as j, type KindSnapshot as k, type KindSpec as l, type MergeResult as m, type Migration as n, type MigrationDirection as o, type MigrationRecord as p, type MigrationStore as q, type PullFilePlan as r, type PullPlan as s, type RenderedUnit as t, type ResolvedConfig as u, type ResolvedDisplay as v, type Statement as w, type StoredSnapshot as x, actionLabel as y, applyPull as z };
|
package/lib/driver.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { C as ConnectionConfigBase, a as ConnectionEntry, b as ConnectionInput, R as ResolveContext,
|
|
1
|
+
export { b as ApplyOptions, A as Authored, a as AuthoredDef, C as ConnectionOverrides, c as Definable, d as Diff, e as DiffItem, D as Driver, f as EmitOptions, h as KindEngine, i as KindPlan, j as KindRegistry, k as KindSnapshot, l as KindSpec, o as MigrationDirection, p as MigrationRecord, q as MigrationStore, O as OrderNode, P as PortableObject, R as Ref, u as ResolvedConfig, S as ShadowCapability, w as Statement, B as buildKindDiff, H as driverNames, I as emitKinds, U as getDriver, X as introspectKinds, a2 as lowerSchema, a6 as orderObjects, a9 as planKinds, ab as registerDriver, ae as snapshotKinds, af as snapshotObjects } from './driver-BTaJ2ryZ.js';
|
|
2
|
+
export { C as ConnectionConfigBase, a as ConnectionEntry, b as ConnectionInput, R as ResolveContext, d as connectionEntry } from './config-v3H_2lwA.js';
|
|
3
3
|
import 'jiti';
|
|
4
4
|
import 'commander';
|
|
5
5
|
|
package/lib/driver.js
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as Authored, a as AuthoredDef } from './driver-
|
|
2
|
-
export {
|
|
3
|
-
export { C as ConnectionConfigBase, a as ConnectionEntry, b as ConnectionInput, R as ResolveContext,
|
|
1
|
+
import { A as Authored, a as AuthoredDef } from './driver-BTaJ2ryZ.js';
|
|
2
|
+
export { b as ApplyOptions, C as ConnectionOverrides, c as Definable, d as Diff, e as DiffItem, D as Driver, E as EMPTY_STORED, f as EmitOptions, F as Filter, g as FilterOpts, K as KindDisplay, h as KindEngine, i as KindPlan, j as KindRegistry, k as KindSnapshot, l as KindSpec, L as LocalOnly, M as MergeOptions, m as MergeResult, n as Migration, o as MigrationDirection, p as MigrationRecord, q as MigrationStore, O as OrderNode, P as PortableObject, r as PullFilePlan, s as PullPlan, R as Ref, t as RenderedUnit, u as ResolvedConfig, v as ResolvedDisplay, S as ShadowCapability, w as Statement, x as StoredSnapshot, y as actionLabel, z as applyPull, B as buildKindDiff, G as checksum, H as driverNames, I as emitKinds, J as filterKinds, N as formatDiff, Q as formatItems, T as formatPatch, U as getDriver, V as inCat, W as intersectKinds, X as introspectKinds, Y as isEmptyDiff, Z as kindFlags, _ as lineDiff, $ as listMigrations, a0 as loadConfig, a1 as loadProject, a2 as lowerSchema, a3 as makeJiti, a4 as mergeStored, a5 as mergeUnits, a6 as orderObjects, a7 as parseFilter, a8 as passesFilter, a9 as planKinds, aa as readSnapshot, ab as registerDriver, ac as resolveConnectionConfig, ad as slug, ae as snapshotKinds, af as snapshotObjects, ag as summarizeKinds, ah as timestamp, ai as tokenDiff, aj as unifiedDiff, ak as writeSnapshot } from './driver-BTaJ2ryZ.js';
|
|
3
|
+
export { C as ConnectionConfigBase, a as ConnectionEntry, b as ConnectionInput, R as ResolveContext, c as ResolvedConnectionHandle, d as connectionEntry, i as isConnectionEntry } from './config-v3H_2lwA.js';
|
|
4
4
|
export { PortableField, PortablePermissions, PortableType, ScalarName, array, literal, nullable, option, record, scalar, union } from './driver.js';
|
|
5
5
|
import 'jiti';
|
|
6
6
|
import 'commander';
|
package/lib/index.js
CHANGED
package/lib/testing.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as Driver } from './driver-
|
|
1
|
+
import { D as Driver } from './driver-BTaJ2ryZ.js';
|
|
2
2
|
import 'jiti';
|
|
3
|
-
import './config-
|
|
3
|
+
import './config-v3H_2lwA.js';
|
|
4
4
|
import 'commander';
|
|
5
5
|
|
|
6
6
|
/** The driver's authoring namespace (`s`) — a bag of field builders. Loosely typed (cross-driver). */
|
package/lib/testing.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schemic/core",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
4
|
"description": "The dialect-neutral engine for Schemic — Driver contract, portable schema IR, and the migration/diff/snapshot engine.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Vertio Solutions",
|
package/src/driver/driver.ts
CHANGED
|
@@ -277,7 +277,15 @@ export interface Driver<
|
|
|
277
277
|
|
|
278
278
|
// --- Registry -----------------------------------------------------------------------------------
|
|
279
279
|
|
|
280
|
-
|
|
280
|
+
// Shared across every loaded copy of `@schemic/core` so the registry is process-global — the CLI run
|
|
281
|
+
// via `bunx` resolves its own core, while a driver loaded from the user's project resolves the
|
|
282
|
+
// project's core; without sharing, the driver self-registers in one Map and the CLI reads an empty
|
|
283
|
+
// one. Keyed by a REGISTERED symbol (`Symbol.for`) — same key in every instance, but no string-keyed
|
|
284
|
+
// `globalThis` pollution and namespaced so it can't collide.
|
|
285
|
+
const REGISTRY_KEY = Symbol.for("@schemic/core.driverRegistry");
|
|
286
|
+
const REGISTRY: Map<string, Driver<unknown>> = ((
|
|
287
|
+
globalThis as Record<symbol, Map<string, Driver<unknown>> | undefined>
|
|
288
|
+
)[REGISTRY_KEY] ??= new Map<string, Driver<unknown>>());
|
|
281
289
|
|
|
282
290
|
/** Register a driver under its `name` (idempotent; last write wins). */
|
|
283
291
|
export function registerDriver(driver: Driver<unknown>): void {
|