@schemic/cli 0.1.0-alpha.3 → 0.1.0-alpha.5

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/cli.js CHANGED
@@ -7,11 +7,11 @@ import {
7
7
  mkdirSync as mkdirSync3,
8
8
  writeFileSync as writeFileSync3
9
9
  } from "fs";
10
- import { dirname as dirname2, join as join3, relative as relative2 } from "path";
10
+ import { dirname as dirname3, join as join3, relative as relative2 } from "path";
11
11
  import { createInterface } from "readline/promises";
12
12
 
13
13
  // package.json
14
- var version = "0.1.0-alpha.3";
14
+ var version = "0.1.0-alpha.5";
15
15
 
16
16
  // src/cli/index.ts
17
17
  import {
@@ -428,8 +428,9 @@ async function closeQuietly(conn) {
428
428
  }
429
429
 
430
430
  // src/cli/resolve.ts
431
+ import { readFileSync as readFileSync2 } from "fs";
431
432
  import { createRequire } from "module";
432
- import { join as join2 } from "path";
433
+ import { dirname as dirname2, join as join2 } from "path";
433
434
  import { pathToFileURL } from "url";
434
435
  import {
435
436
  driverNames,
@@ -438,23 +439,54 @@ import {
438
439
  loadProject,
439
440
  resolveConnectionConfig
440
441
  } from "@schemic/core";
442
+ function pickCompiled(node) {
443
+ if (typeof node === "string") return node;
444
+ if (node && typeof node === "object") {
445
+ const o = node;
446
+ return pickCompiled(o.import) ?? pickCompiled(o.default) ?? pickCompiled(o.require);
447
+ }
448
+ return void 0;
449
+ }
450
+ function compiledEntry(pkg, base) {
451
+ try {
452
+ const manifestPath = createRequire(base).resolve(`${pkg}/package.json`);
453
+ const m = JSON.parse(readFileSync2(manifestPath, "utf8"));
454
+ const rel = pickCompiled(m.exports?.["."]) ?? m.module ?? m.main ?? "index.js";
455
+ return join2(dirname2(manifestPath), rel);
456
+ } catch {
457
+ return null;
458
+ }
459
+ }
441
460
  async function ensureDriver(name) {
442
461
  if (driverNames().includes(name)) return;
443
462
  const pkg = `@schemic/${name}`;
444
- try {
445
- const fromCwd = createRequire(join2(process.cwd(), "noop.js"));
446
- await import(pathToFileURL(fromCwd.resolve(pkg)).href);
447
- } catch {
463
+ let lastErr;
464
+ let loaded = false;
465
+ for (const base of [join2(process.cwd(), "noop.js"), import.meta.url]) {
466
+ const entry = compiledEntry(pkg, base);
467
+ if (!entry) continue;
468
+ try {
469
+ await import(pathToFileURL(entry).href);
470
+ loaded = true;
471
+ break;
472
+ } catch (e) {
473
+ lastErr = e;
474
+ }
475
+ }
476
+ if (!loaded) {
448
477
  try {
449
478
  await import(pkg);
479
+ loaded = true;
450
480
  } catch (e) {
451
- throw new Error(
452
- `could not load the "${name}" database driver (package ${pkg}). Install it in your project, then re-run:
453
- bun add ${pkg}
454
- (${e instanceof Error ? e.message : String(e)})`
455
- );
481
+ lastErr = e;
456
482
  }
457
483
  }
484
+ if (!loaded)
485
+ throw new Error(
486
+ `could not load the "${name}" database driver (package ${pkg}). Install it in your project, then re-run:
487
+ bun add ${pkg}
488
+ (${lastErr instanceof Error ? lastErr.message : String(lastErr)})`
489
+ );
458
490
  if (!driverNames().includes(name))
459
491
  throw new Error(`package ${pkg} did not register a "${name}" driver.`);
460
492
  }
@@ -1285,7 +1317,7 @@ configFlag(
1285
1317
  );
1286
1318
  if (existsSync3(target))
1287
1319
  throw new Error(`${relative2(config.root, target)} already exists.`);
1288
- mkdirSync3(dirname2(target), { recursive: true });
1320
+ mkdirSync3(dirname3(target), { recursive: true });
1289
1321
  writeFileSync3(target, content);
1290
1322
  console.log(
1291
1323
  `${ok2(relative2(config.root, target))} ${style2.dim("\u2014 author its fields, then `schemic gen`")}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schemic/cli",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.5",
4
4
  "description": "The Schemic CLI — driver-agnostic schema migrations (gen/migrate/diff/push/pull/check).",
5
5
  "license": "MIT",
6
6
  "author": "Vertio Solutions",
@@ -35,14 +35,14 @@
35
35
  "lint": "biome check ."
36
36
  },
37
37
  "dependencies": {
38
- "@schemic/core": "0.1.0-alpha.2",
38
+ "@schemic/core": "0.1.0-alpha.5",
39
39
  "commander": "^14.0.2"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@biomejs/biome": "^2.3.11",
43
43
  "@electric-sql/pglite": "^0.5.2",
44
- "@schemic/postgres": "0.1.0-alpha.2",
45
- "@schemic/surrealdb": "0.1.0-alpha.2",
44
+ "@schemic/postgres": "0.1.0-alpha.5",
45
+ "@schemic/surrealdb": "0.1.0-alpha.5",
46
46
  "@types/bun": "latest",
47
47
  "surrealdb": "^2.0.3",
48
48
  "tsup": "^8",
@@ -10,8 +10,9 @@
10
10
  // connects the sibling on demand (the dependency graph falls out of access; cycles error) and we close
11
11
  // anything it opened once resolution settles. The returned configs are connected FRESH by each command.
12
12
 
13
+ import { readFileSync } from "node:fs";
13
14
  import { createRequire } from "node:module";
14
- import { join } from "node:path";
15
+ import { dirname, join } from "node:path";
15
16
  import { pathToFileURL } from "node:url";
16
17
  import {
17
18
  type ConnectionEntry,
@@ -32,27 +33,77 @@ import {
32
33
  * (`@schemic/<name>`) that self-register with the core registry on import; the CLI itself contains no
33
34
  * dialect code and discovers the driver from the project's connection config at runtime. Idempotent.
34
35
  */
36
+ /** Pick a package's COMPILED entry from its exports, deliberately skipping the `bun` condition. */
37
+ function pickCompiled(node: unknown): string | undefined {
38
+ if (typeof node === "string") return node;
39
+ if (node && typeof node === "object") {
40
+ const o = node as Record<string, unknown>;
41
+ // import/default/require are the published (compiled) conditions; never `bun` (raw src/*.ts).
42
+ return (
43
+ pickCompiled(o.import) ??
44
+ pickCompiled(o.default) ??
45
+ pickCompiled(o.require)
46
+ );
47
+ }
48
+ return undefined;
49
+ }
50
+
51
+ /**
52
+ * Resolve a driver package to its COMPILED entry file, from `base`'s module scope. We read the
53
+ * manifest and pick the `import`/`default` export rather than letting the runtime choose the `bun`
54
+ * export condition (which points at raw `src/*.ts` for monorepo dev) — loading a PUBLISHED package's
55
+ * TypeScript source is fragile (every transitive src import must re-resolve at the consumer).
56
+ */
57
+ function compiledEntry(pkg: string, base: string): string | null {
58
+ try {
59
+ const manifestPath = createRequire(base).resolve(`${pkg}/package.json`);
60
+ const m = JSON.parse(readFileSync(manifestPath, "utf8")) as {
61
+ exports?: Record<string, unknown>;
62
+ module?: string;
63
+ main?: string;
64
+ };
65
+ const rel =
66
+ pickCompiled(m.exports?.["."]) ?? m.module ?? m.main ?? "index.js";
67
+ return join(dirname(manifestPath), rel);
68
+ } catch {
69
+ return null;
70
+ }
71
+ }
72
+
35
73
  export async function ensureDriver(name: string): Promise<void> {
36
74
  if (driverNames().includes(name)) return;
37
75
  const pkg = `@schemic/${name}`;
38
- // Resolve the driver from the USER's project (cwd) first, then fall back to the CLI's own location.
39
- // The CLI is often run via `bunx`/`npx` from a temp dir, so a plain `import(pkg)` (resolved relative
40
- // to the CLI module) would MISS a driver installed in the user's project — resolve from cwd instead.
41
- try {
42
- const fromCwd = createRequire(join(process.cwd(), "noop.js"));
43
- await import(pathToFileURL(fromCwd.resolve(pkg)).href);
44
- } catch {
76
+ // Try the USER's project (cwd) first, then the CLI's own module scope — the CLI is often run via
77
+ // `bunx`/`npx` from a temp dir, so a driver installed in the user's project must be found by cwd.
78
+ let lastErr: unknown;
79
+ let loaded = false;
80
+ for (const base of [join(process.cwd(), "noop.js"), import.meta.url]) {
81
+ const entry = compiledEntry(pkg, base);
82
+ if (!entry) continue;
83
+ try {
84
+ await import(pathToFileURL(entry).href);
85
+ loaded = true;
86
+ break;
87
+ } catch (e) {
88
+ lastErr = e;
89
+ }
90
+ }
91
+ // Last resort: a plain specifier import (covers an unbuilt monorepo checkout, where lib is absent).
92
+ if (!loaded) {
45
93
  try {
46
94
  await import(pkg);
95
+ loaded = true;
47
96
  } catch (e) {
48
- throw new Error(
49
- `could not load the "${name}" database driver (package ${pkg}). ` +
50
- `Install it in your project, then re-run:\n bun add ${pkg}\n (${
51
- e instanceof Error ? e.message : String(e)
52
- })`,
53
- );
97
+ lastErr = e;
54
98
  }
55
99
  }
100
+ if (!loaded)
101
+ throw new Error(
102
+ `could not load the "${name}" database driver (package ${pkg}). ` +
103
+ `Install it in your project, then re-run:\n bun add ${pkg}\n (${
104
+ lastErr instanceof Error ? lastErr.message : String(lastErr)
105
+ })`,
106
+ );
56
107
  if (!driverNames().includes(name))
57
108
  throw new Error(`package ${pkg} did not register a "${name}" driver.`);
58
109
  }