@better-schemic/core 0.1.0-alpha.1

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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -0
  3. package/lib/authoring.d.ts +114 -0
  4. package/lib/authoring.js +242 -0
  5. package/lib/authoring.js.map +1 -0
  6. package/lib/chunk-26D7WX7Q.js +31 -0
  7. package/lib/chunk-26D7WX7Q.js.map +1 -0
  8. package/lib/chunk-IUPOUD4L.js +330 -0
  9. package/lib/chunk-IUPOUD4L.js.map +1 -0
  10. package/lib/chunk-LC3VHUM2.js +56 -0
  11. package/lib/chunk-LC3VHUM2.js.map +1 -0
  12. package/lib/chunk-RSGP7GVO.js +252 -0
  13. package/lib/chunk-RSGP7GVO.js.map +1 -0
  14. package/lib/client-HZF4ZWGO.js +13 -0
  15. package/lib/client-HZF4ZWGO.js.map +1 -0
  16. package/lib/config-BYh7WA4P.d.ts +259 -0
  17. package/lib/config.d.ts +2 -0
  18. package/lib/config.js +27 -0
  19. package/lib/config.js.map +1 -0
  20. package/lib/driver-LVldBEhS.d.ts +818 -0
  21. package/lib/driver.d.ts +151 -0
  22. package/lib/driver.js +47 -0
  23. package/lib/driver.js.map +1 -0
  24. package/lib/index.d.ts +154 -0
  25. package/lib/index.js +758 -0
  26. package/lib/index.js.map +1 -0
  27. package/lib/query.d.ts +81 -0
  28. package/lib/query.js +30 -0
  29. package/lib/query.js.map +1 -0
  30. package/lib/secrets-BETi5p8g.d.ts +26 -0
  31. package/lib/testing.d.ts +99 -0
  32. package/lib/testing.js +212 -0
  33. package/lib/testing.js.map +1 -0
  34. package/package.json +102 -0
  35. package/src/authoring.ts +360 -0
  36. package/src/cli-kit/config.ts +226 -0
  37. package/src/cli-kit/diff.ts +273 -0
  38. package/src/cli-kit/filter.ts +159 -0
  39. package/src/cli-kit/merge.ts +380 -0
  40. package/src/cli-kit/meta.ts +123 -0
  41. package/src/cli-kit/pager.ts +42 -0
  42. package/src/cli-kit/schema.ts +214 -0
  43. package/src/cli-kit/style.ts +24 -0
  44. package/src/client.ts +244 -0
  45. package/src/config.ts +199 -0
  46. package/src/connection.ts +120 -0
  47. package/src/driver/driver.ts +413 -0
  48. package/src/driver/index.ts +31 -0
  49. package/src/driver/portable-ir.ts +51 -0
  50. package/src/driver/portable.ts +124 -0
  51. package/src/driver/sdk.ts +73 -0
  52. package/src/index.ts +185 -0
  53. package/src/kind/index.ts +28 -0
  54. package/src/kind/plan.ts +412 -0
  55. package/src/kind/registry.ts +270 -0
  56. package/src/query/call.ts +21 -0
  57. package/src/query/codec.ts +33 -0
  58. package/src/query/index.ts +22 -0
  59. package/src/query/project.ts +25 -0
  60. package/src/query/ref.ts +32 -0
  61. package/src/query.ts +5 -0
  62. package/src/secrets.ts +61 -0
  63. package/src/seed.ts +14 -0
  64. package/src/testing.ts +402 -0
@@ -0,0 +1,151 @@
1
+ export { A as AnyConnectionEntry, d as ConnectionConfigBase, e as ConnectionEntry, f as ConnectionInput, h as ResolveContext, R as ResolvedConfig, k as StandardSchemaLike, l as connectionEntry } from './config-BYh7WA4P.js';
2
+ export { b as ApplyOptions, A as Authored, a as AuthoredDef, c as CommandArgs, d as CommandContext, e as CommandIo, f as ConnectionOverrides, g as Definable, h as Diff, i as DiffItem, D as Driver, j as DriverCommand, k as EmitOptions, n as KindEngine, o as KindPlan, K as KindRegistry, p as KindSnapshot, q as KindSpec, t as MigrationDirection, u as MigrationRecord, v as MigrationStore, O as OrderNode, P as ParsedCommandArgs, w as PortableObject, R as Ref, S as ShadowCapability, G as Statement, N as buildKindDiff, T as driverNames, U as emitKinds, Z as getDriver, a0 as introspectKinds, a5 as lowerSchema, a8 as orderObjects, ab as planKinds, ad as registerDriver, af as snapshotKinds, ag as snapshotObjects } from './driver-LVldBEhS.js';
3
+ import 'jiti';
4
+ import './secrets-BETi5p8g.js';
5
+ import 'commander';
6
+
7
+ /**
8
+ * The portable scalar set — the common denominator every driver maps to a concrete column type and
9
+ * back. A driver MAY reject scalars it cannot represent (and authoring can pin a richer DB-native
10
+ * type via `{ t: "native" }`). Names are lowercase and dialect-neutral.
11
+ */
12
+ type ScalarName = "any" | "bool" | "string" | "int" | "float" | "decimal" | "number" | "datetime" | "duration" | "uuid" | "bytes" | "null";
13
+ /**
14
+ * A dialect-independent field type. Drivers translate this to their own type expression (`emitType`)
15
+ * and parse their introspection back into it (`parseType`). `option` and `nullable` are ORTHOGONAL
16
+ * and BOTH equality-relevant — see the note on `nullable` below; never collapse them.
17
+ */
18
+ type PortableType =
19
+ /** A primitive scalar. */
20
+ {
21
+ t: "scalar";
22
+ name: ScalarName;
23
+ }
24
+ /** A literal value type, e.g. the `'active'` in `'active' | 'archived'`. */
25
+ | {
26
+ t: "literal";
27
+ value: string | number | boolean;
28
+ }
29
+ /**
30
+ * The field may be ABSENT / NONE (Surreal `option<T>`; SQL "column omitted / has a DEFAULT").
31
+ * Orthogonal to `nullable`.
32
+ */
33
+ | {
34
+ t: "option";
35
+ inner: PortableType;
36
+ }
37
+ /**
38
+ * The field may be NULL (Surreal `T | null`; SQL `NULL` vs `NOT NULL`). Orthogonal to `option`:
39
+ * `option<T>`, `T | null`, and `option<T | null>` are THREE DISTINCT types. `normalize()` folds
40
+ * `nullable(option(X))` -> `option(nullable(X))` so `.optional().nullable()` ≡ `.nullish()`.
41
+ */
42
+ | {
43
+ t: "nullable";
44
+ inner: PortableType;
45
+ }
46
+ /** An ordered, possibly length-bounded list. */
47
+ | {
48
+ t: "array";
49
+ elem: PortableType;
50
+ size?: number;
51
+ }
52
+ /** A set (distinct elements), possibly length-bounded. */
53
+ | {
54
+ t: "set";
55
+ elem: PortableType;
56
+ size?: number;
57
+ }
58
+ /** A discriminated/plain union. `normalize()` keeps `members` canonically sorted. */
59
+ | {
60
+ t: "union";
61
+ members: PortableType[];
62
+ }
63
+ /** A nested object/record literal. `flexible` allows undeclared keys (Surreal FLEXIBLE). */
64
+ | {
65
+ t: "object";
66
+ fields: Record<string, PortableType>;
67
+ flexible?: boolean;
68
+ }
69
+ /**
70
+ * A link to a row in one of `tables` (Surreal `record<a | b>`; SQL foreign key). The id-VALUE type
71
+ * is intentionally NOT modelled here — the DDL never encodes it; it lives App/Wire-side (TS-only).
72
+ */
73
+ | {
74
+ t: "record";
75
+ tables: string[];
76
+ }
77
+ /** A geometry type (Surreal-native; PostGIS or unsupported elsewhere). */
78
+ | {
79
+ t: "geometry";
80
+ kind: GeometryKind;
81
+ }
82
+ /** The bottom type (no value). */
83
+ | {
84
+ t: "never";
85
+ }
86
+ /**
87
+ * An escape hatch for a DB-specific type with no portable meaning (a full-text vector type, etc.). Carries
88
+ * the owning driver `db` so a schema authored for one DB can't silently typecheck against another.
89
+ * `params` carries the type's parameters for parameterized natives — `numeric(p,s)`, `varchar(n)`,
90
+ * `timestamp(p)` — so a driver round-trips `numeric(10,2)` exactly. Order matters; ignored when empty.
91
+ */
92
+ | {
93
+ t: "native";
94
+ db: string;
95
+ name: string;
96
+ params?: (string | number)[];
97
+ };
98
+ type GeometryKind = "feature" | "point" | "line" | "polygon" | "multipoint" | "multiline" | "multipolygon" | "collection";
99
+ declare const scalar: (name: ScalarName) => PortableType;
100
+ declare const literal: (value: string | number | boolean) => PortableType;
101
+ /** `option<T>` — but `option<any>` collapses to `any` (any already admits NONE), matching ddl.ts. */
102
+ declare const option: (inner: PortableType) => PortableType;
103
+ /**
104
+ * `T | null` — with the fold rule `nullable(option(X))` -> `option(nullable(X))` so
105
+ * `.optional().nullable()` ≡ `.nullish()`, and `nullable(any)` collapses to `any`.
106
+ */
107
+ declare const nullable: (inner: PortableType) => PortableType;
108
+ declare const array: (elem: PortableType, size?: number) => PortableType;
109
+ declare const union: (members: PortableType[]) => PortableType;
110
+ declare const record: (tables: string[]) => PortableType;
111
+
112
+ /** CRUD permissions — each a boolean (FULL/NONE) or a dialect WHERE-expression string (carried verbatim). */
113
+ interface PortablePermissions {
114
+ select?: boolean | string;
115
+ create?: boolean | string;
116
+ update?: boolean | string;
117
+ delete?: boolean | string;
118
+ }
119
+ /** A field in the portable substrate: a structured {@link PortableType} + its dialect clauses (verbatim). */
120
+ interface PortableField {
121
+ name: string;
122
+ type: PortableType;
123
+ flexible?: boolean;
124
+ readonly?: boolean;
125
+ default?: string;
126
+ default_always?: boolean;
127
+ value?: string;
128
+ computed?: string;
129
+ assert?: string;
130
+ /**
131
+ * A field-level CHECK constraint (dialect boolean expression, carried verbatim). DISTINCT from
132
+ * `assert`: that is Surreal's `ASSERT`; this is the SQL `CHECK` a SQL driver emits. A
133
+ * driver maps whichever of the two it supports and surfaces the other as a capability gap.
134
+ */
135
+ check?: string;
136
+ comment?: string;
137
+ /** Referential action(s) on a foreign reference. A driver honors the actions it supports. */
138
+ reference?: {
139
+ on_delete?: string;
140
+ on_update?: string;
141
+ };
142
+ /**
143
+ * Auto-generated identity column — `GENERATED ALWAYS`/`BY DEFAULT AS IDENTITY`; a `serial`/
144
+ * auto-increment column maps here too. Absent → an ordinary column. Drivers without identity ignore it.
145
+ */
146
+ identity?: "always" | "by-default";
147
+ permissions?: PortablePermissions;
148
+ table: string;
149
+ }
150
+
151
+ export { type GeometryKind, type PortableField, type PortablePermissions, type PortableType, type ScalarName, array, literal, nullable, option, record, scalar, union };
package/lib/driver.js ADDED
@@ -0,0 +1,47 @@
1
+ import {
2
+ array,
3
+ connectionEntry,
4
+ literal,
5
+ nullable,
6
+ option,
7
+ record,
8
+ scalar,
9
+ union
10
+ } from "./chunk-LC3VHUM2.js";
11
+ import {
12
+ KindRegistry,
13
+ buildKindDiff,
14
+ driverNames,
15
+ emitKinds,
16
+ getDriver,
17
+ introspectKinds,
18
+ lowerSchema,
19
+ orderObjects,
20
+ planKinds,
21
+ registerDriver,
22
+ snapshotKinds,
23
+ snapshotObjects
24
+ } from "./chunk-IUPOUD4L.js";
25
+ export {
26
+ KindRegistry,
27
+ array,
28
+ buildKindDiff,
29
+ connectionEntry,
30
+ driverNames,
31
+ emitKinds,
32
+ getDriver,
33
+ introspectKinds,
34
+ literal,
35
+ lowerSchema,
36
+ nullable,
37
+ option,
38
+ orderObjects,
39
+ planKinds,
40
+ record,
41
+ registerDriver,
42
+ scalar,
43
+ snapshotKinds,
44
+ snapshotObjects,
45
+ union
46
+ };
47
+ //# sourceMappingURL=driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/lib/index.d.ts ADDED
@@ -0,0 +1,154 @@
1
+ import { B as BetterSchemicConfig, R as ResolvedConfig, A as AnyConnectionEntry } from './config-BYh7WA4P.js';
2
+ export { a as BetterSchemicProject, C as ChainCtx, b as ChainableDriverFactory, c as ChainedConfig, d as ConnectionConfigBase, e as ConnectionEntry, f as ConnectionInput, E as EntryArgs, g as EntryClient, h as ResolveContext, i as ResolvedConnectionHandle, S as SchemicConfig, j as SchemicProject, k as StandardSchemaLike, l as connectionEntry, m as isConnectionEntry, n as loadConfig, o as loadProject, p as makeJiti, r as resolveConnectionConfig } from './config-BYh7WA4P.js';
3
+ import { A as Authored, a as AuthoredDef } from './driver-LVldBEhS.js';
4
+ export { b as ApplyOptions, C as CallableFunctions, c as CommandArgs, d as CommandContext, e as CommandIo, f as ConnectionOverrides, g as Definable, h as Diff, i as DiffItem, D as Driver, j as DriverCommand, E as EMPTY_STORED, k as EmitOptions, F as Filter, l as FilterOpts, m as KindDisplay, n as KindEngine, o as KindPlan, K as KindRegistry, p as KindSnapshot, q as KindSpec, L as LocalOnly, M as MergeOptions, r as MergeResult, s as Migration, t as MigrationDirection, u as MigrationRecord, v as MigrationStore, O as OrderNode, P as ParsedCommandArgs, w as PortableObject, x as PullFilePlan, y as PullPlan, R as Ref, z as RenderedUnit, B as ResolvedDisplay, S as ShadowCapability, G as Statement, H as StoredSnapshot, I as actionLabel, J as applyPull, N as buildKindDiff, Q as checksum, T as driverNames, U as emitKinds, V as filterKinds, W as formatDiff, X as formatItems, Y as formatPatch, Z as getDriver, _ as inCat, $ as intersectKinds, a0 as introspectKinds, a1 as isEmptyDiff, a2 as kindFlags, a3 as lineDiff, a4 as listMigrations, a5 as lowerSchema, a6 as mergeStored, a7 as mergeUnits, a8 as orderObjects, a9 as parseFilter, aa as passesFilter, ab as planKinds, ac as readSnapshot, ad as registerDriver, ae as slug, af as snapshotKinds, ag as snapshotObjects, ah as summarizeKinds, ai as timestamp, aj as tokenDiff, ak as unifiedDiff, al as writeSnapshot } from './driver-LVldBEhS.js';
5
+ export { PortableField, PortablePermissions, PortableType, ScalarName, array, literal, nullable, option, record, scalar, union } from './driver.js';
6
+ export { S as SecretProvider, a as SecretRef, e as env, b as envSecretProvider, i as isSecretRef, s as secret } from './secrets-BETi5p8g.js';
7
+ import 'jiti';
8
+ import 'commander';
9
+
10
+ /**
11
+ * The diff pager, resolved the way git does: `pager.diff` → `core.pager` → `$GIT_PAGER` →
12
+ * `$PAGER`. So a user with `core.pager = delta` gets delta for free, with their own config.
13
+ */
14
+ declare function resolvePager(): string | undefined;
15
+ /** Pipe `text` through `pager` (a shell command, possibly with args); resolve when it exits. */
16
+ declare function pipeThroughPager(pager: string, text: string): Promise<void>;
17
+
18
+ interface AnyTable extends Authored {
19
+ readonly config: {
20
+ readonly relation?: unknown;
21
+ };
22
+ }
23
+ /**
24
+ * Load every schema object from `schemaPath` (a single `.ts` module, or a directory of them): the
25
+ * tables/relations (ordered normal-before-relation, then by name, for stable DDL) and the standalone
26
+ * defs (any non-table `{ kind, name }` definable — the driver's registry owns the kinds). One pass.
27
+ */
28
+ declare function loadDefs(schemaPath: string): Promise<{
29
+ tables: AnyTable[];
30
+ defs: AuthoredDef[];
31
+ /** Absolute source file each table/def was loaded from (for `diff`'s file annotations). */
32
+ fileOf: Map<AnyTable | AuthoredDef, string>;
33
+ }>;
34
+ /** The tables/relations from `schemaPath` (standalone events excluded — see {@link loadDefs}). */
35
+ declare function loadSchemas(schemaPath: string): Promise<AnyTable[]>;
36
+ /** A schema file's exported entities (tables/functions/accesses) and whether it holds ONLY those. */
37
+ interface LocalFileEntities {
38
+ /** Each schema entity by its export-const identifier + its DB name (table/function/access name). */
39
+ entities: {
40
+ exportName: string;
41
+ name: string;
42
+ kind: "table" | "def";
43
+ }[];
44
+ /** True when EVERY runtime export of the file is a schema entity (no helpers / other exports). */
45
+ pureSchema: boolean;
46
+ }
47
+ /**
48
+ * Scan each schema file for the tables/functions/accesses it exports (by export-const name), and
49
+ * whether the file is purely schema. `pull` uses this to find whole-entity local-only schema
50
+ * (entities the live DB doesn't have) and to decide whether a file is safe to delete when mirroring
51
+ * the DB. Standalone events are not whole entities (they attach to a table), so they don't count as
52
+ * entities — a file exporting one is therefore not `pureSchema` and won't be auto-deleted.
53
+ */
54
+ declare function scanLocalEntities(schemaPath: string): Promise<Map<string, LocalFileEntities>>;
55
+ /** Map of table name → the file that defines it (for `pull`'s duplicate-definition check). */
56
+ declare function existingTables(schemaPath: string): Promise<Map<string, string>>;
57
+ /**
58
+ * Names defined in more than one place, mapped to the files that define them (a file repeats if it
59
+ * defines the same name twice). `loadSchemas` silently lets the last definition win, so this is how
60
+ * `doctor` surfaces the otherwise-invisible conflict.
61
+ */
62
+ declare function duplicateTables(schemaPath: string): Promise<Map<string, string[]>>;
63
+
64
+ /** Whether colored output is enabled (a TTY and `NO_COLOR` unset). */
65
+ declare const colorEnabled: () => boolean;
66
+ declare const style: {
67
+ green: (s: string) => string;
68
+ red: (s: string) => string;
69
+ yellow: (s: string) => string;
70
+ cyan: (s: string) => string;
71
+ dim: (s: string) => string;
72
+ bold: (s: string) => string;
73
+ };
74
+ /** A green ✓ success line. */
75
+ declare const ok: (s: string) => string;
76
+ /** A red ✗ failure line. */
77
+ declare const fail: (s: string) => string;
78
+ /** Pluralize `n thing` / `n things`. */
79
+ declare const plural: (n: number, word: string) => string;
80
+
81
+ /**
82
+ * The neutral bound-client contract. A driver's client extends this and adds its typed query surface.
83
+ * It is an `AsyncDisposable`, so `await using db = await connect()` closes it at block exit.
84
+ *
85
+ * DISPOSE RULE (hard): a MANAGED client (opened by {@link resolveConnection} + the driver's `connect`)
86
+ * closes the connection it opened; a BYO client (wrapping the user's own pool) MUST make `close` a
87
+ * NO-OP — we never close a connection the user owns. The driver enforces this at construction.
88
+ */
89
+ interface OrmClientBase extends AsyncDisposable {
90
+ /** Close the underlying connection (managed only; a BYO client is a no-op — see the dispose rule). */
91
+ close(): Promise<void>;
92
+ }
93
+ /** Mixin the default `[Symbol.asyncDispose]` (= `close`) onto a client class's prototype. */
94
+ declare function asyncDisposable<T extends {
95
+ close(): Promise<void>;
96
+ }>(proto: T): void;
97
+ /** Options for {@link resolveConnection}: which connection, and where the config lives. */
98
+ interface ResolveConnectionOptions {
99
+ /** Connection name; defaults to `defaultConnection`, else the sole connection, else `"default"`. */
100
+ name?: string;
101
+ /** Path to `better-schemic.config.ts` (else auto-discovered from `cwd`). */
102
+ config?: string;
103
+ /** Working directory to discover the config + resolve relative paths from. */
104
+ cwd?: string;
105
+ /** The resolver's typed args (its declared 2nd param) for a PARAMETERIZED connection. */
106
+ args?: unknown;
107
+ }
108
+ /**
109
+ * Resolve ONE named connection from the disk-discovered project config — the MANAGED path a driver's
110
+ * standalone `connect(name?)` uses before `driver.connect(config)`. Single-config or a teaching
111
+ * error (a bulk resolution must be arg-selected).
112
+ */
113
+ declare function resolveConnection(opts?: ResolveConnectionOptions): Promise<ResolvedConfig>;
114
+ /**
115
+ * The shared single-name resolution over an IN-MEMORY config: pick the entry (named /
116
+ * defaultConnection / sole / `"default"`), run the resolver with its typed `args`, and build one
117
+ * {@link ResolvedConfig} per returned config, each with a display label (config `key` > the entry's
118
+ * `label` hook > positional `name[i]`). Resolvers may query siblings via `ctx.connections` (lazy,
119
+ * cycle-checked; opened siblings are closed when resolution settles). Used by both
120
+ * {@link resolveConnection} (disk-discovered config) and {@link connectFromConfig} (`config.connect`).
121
+ */
122
+ declare function resolveFromConfig(config: BetterSchemicConfig, root: string, opts?: {
123
+ name?: string;
124
+ args?: unknown;
125
+ }): Promise<{
126
+ entry: AnyConnectionEntry;
127
+ name: string;
128
+ resolved: ResolvedConfig[];
129
+ labels: string[];
130
+ }>;
131
+ /**
132
+ * The runtime behind `config.connect(name, args?)` (see `defineConfig`): resolve the entry from the
133
+ * in-memory config and open its bound ORM client via the factory-embedded
134
+ * {@link AnyConnectionEntry.client} opener. The static return type is the entry's own client type
135
+ * (inferred per entry in `BetterSchemicProject`).
136
+ */
137
+ declare function connectFromConfig(config: BetterSchemicConfig, name?: string, args?: unknown): Promise<unknown>;
138
+
139
+ /**
140
+ * The context the seed runner hands to each seed as its second argument — a small filesystem helper
141
+ * scoped to the seed's own directory, so a seed can load supporting files (raw `.surql`/`.sql`, JSON,
142
+ * …) without an `import … with { type: "text" }` declaration or any `import.meta.url` path juggling.
143
+ *
144
+ * A driver types its `defineSeed(fn)` helper as `(db: Conn, ctx: SeedContext) => …`; the connection is
145
+ * the driver's own type, this context is dialect-neutral.
146
+ */
147
+ interface SeedContext {
148
+ /** Absolute path of the directory containing the running seed. */
149
+ readonly dir: string;
150
+ /** Read a supporting file (resolved relative to {@link SeedContext.dir}) as a UTF-8 string. */
151
+ file(name: string): string;
152
+ }
153
+
154
+ export { AnyConnectionEntry, type AnyTable, Authored, AuthoredDef, BetterSchemicConfig, type OrmClientBase, type ResolveConnectionOptions, ResolvedConfig, type SeedContext, asyncDisposable, colorEnabled, connectFromConfig, duplicateTables, existingTables, fail, loadDefs, loadSchemas, ok, pipeThroughPager, plural, resolveConnection, resolveFromConfig, resolvePager, scanLocalEntities, style };