vibeorm 1.1.10 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -327,13 +327,18 @@ Config is resolved in this order (last wins):
327
327
 
328
328
  ### vibeorm.config.ts
329
329
 
330
+ The loader expects a **default export**. It will also accept `export const config = { ... }`
331
+ as a fallback for ergonomics, but `export default` is the canonical form.
332
+
330
333
  ```ts
331
- export const config = {
334
+ import type { VibeOrmConfig } from "vibeorm/config";
335
+
336
+ export default {
332
337
  schema: "./prisma/schema.prisma",
333
338
  output: "./generated/vibeorm",
334
339
  migrations: "./migrations",
335
340
  seed: "./prisma/seed.ts",
336
- };
341
+ } satisfies VibeOrmConfig;
337
342
  ```
338
343
 
339
344
  ### Typical migration workflow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeorm",
3
- "version": "1.1.10",
3
+ "version": "1.2.0",
4
4
  "description": "CLI for VibeORM — generate clients, run migrations, introspect databases",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -20,6 +20,10 @@
20
20
  ".": {
21
21
  "default": "./src/index.ts",
22
22
  "types": "./src/index.ts"
23
+ },
24
+ "./config": {
25
+ "default": "./src/config.ts",
26
+ "types": "./src/config.ts"
23
27
  }
24
28
  },
25
29
  "files": [
@@ -41,10 +45,10 @@
41
45
  "bun": ">=1.1.0"
42
46
  },
43
47
  "dependencies": {
44
- "@vibeorm/parser": "1.1.7",
45
- "@vibeorm/generator": "1.1.8",
46
- "@vibeorm/migrate": "1.1.8",
47
- "@vibeorm/runtime": "1.1.7",
48
- "@vibeorm/adapter-bun": "1.1.7"
48
+ "@vibeorm/parser": "1.2.0",
49
+ "@vibeorm/generator": "1.2.0",
50
+ "@vibeorm/migrate": "1.2.0",
51
+ "@vibeorm/runtime": "1.2.0",
52
+ "@vibeorm/adapter-bun": "1.2.0"
49
53
  }
50
54
  }
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * vibeorm db seed
3
3
  *
4
- * Run a user-defined seed script.
4
+ * Run a user-defined seed script. Any arguments passed after the `--`
5
+ * separator are forwarded verbatim to the seed script (npm/bun convention):
6
+ *
7
+ * bunx vibeorm db seed -- --scenario=medium --seed-count 10
8
+ *
9
+ * The seed script can then read these from `process.argv.slice(2)`.
5
10
  */
6
11
 
7
12
  import { existsSync } from "fs";
@@ -10,8 +15,9 @@ import type { VibeOrmConfig } from "../config.ts";
10
15
  export async function runDbSeed(params: {
11
16
  config: VibeOrmConfig;
12
17
  flags: Record<string, string>;
18
+ passthroughArgs?: string[];
13
19
  }): Promise<void> {
14
- const { config } = params;
20
+ const { config, passthroughArgs = [] } = params;
15
21
 
16
22
  console.log("VibeORM DB Seed");
17
23
  console.log("");
@@ -30,9 +36,12 @@ export async function runDbSeed(params: {
30
36
  }
31
37
 
32
38
  console.log(`Running seed: ${seedPath}`);
39
+ if (passthroughArgs.length > 0) {
40
+ console.log(` Forwarding args: ${passthroughArgs.join(" ")}`);
41
+ }
33
42
  console.log("");
34
43
 
35
- const proc = Bun.spawn(["bun", "run", seedPath], {
44
+ const proc = Bun.spawn(["bun", "run", seedPath, ...passthroughArgs], {
36
45
  stdout: "inherit",
37
46
  stderr: "inherit",
38
47
  });
package/src/config.ts CHANGED
@@ -55,20 +55,58 @@ function loadPackageJsonConfig(): Partial<VibeOrmConfig> {
55
55
  return {};
56
56
  }
57
57
 
58
+ const KNOWN_CONFIG_KEYS = new Set<keyof VibeOrmConfig>(["schema", "output", "migrations", "seed"]);
59
+
58
60
  async function loadConfigFile(): Promise<Partial<VibeOrmConfig>> {
59
61
  const configPath = resolve(process.cwd(), "vibeorm.config.ts");
60
62
  if (!existsSync(configPath)) return {};
61
63
 
64
+ let mod: Record<string, unknown>;
62
65
  try {
63
- const mod = await import(configPath);
64
- const config = mod.default ?? mod;
65
- if (config && typeof config === "object") {
66
- return config as Partial<VibeOrmConfig>;
67
- }
68
- } catch {
69
- // Ignore import errors
66
+ mod = await import(configPath);
67
+ } catch (err) {
68
+ console.warn(`[vibeorm] Failed to import vibeorm.config.ts: ${err instanceof Error ? err.message : String(err)}`);
69
+ return {};
70
70
  }
71
- return {};
71
+
72
+ // Accept either `export default { ... }` (recommended) or `export const config = { ... }`.
73
+ // We prefer `default` for consistency with most TS config conventions.
74
+ let raw: unknown = mod.default;
75
+ let source: "default" | "config" | "module" = "default";
76
+ if (raw === undefined && mod.config !== undefined) {
77
+ raw = mod.config;
78
+ source = "config";
79
+ }
80
+ if (raw === undefined) {
81
+ raw = mod;
82
+ source = "module";
83
+ }
84
+
85
+ if (!raw || typeof raw !== "object") {
86
+ console.warn(`[vibeorm] vibeorm.config.ts loaded but does not export a config object.`);
87
+ return {};
88
+ }
89
+
90
+ const cfg = raw as Record<string, unknown>;
91
+ const hasKnown = Array.from(KNOWN_CONFIG_KEYS).some((k) => cfg[k] !== undefined);
92
+ if (!hasKnown) {
93
+ console.warn(
94
+ `[vibeorm] vibeorm.config.ts loaded but no recognised keys (schema/output/migrations/seed) were found. ` +
95
+ `Did you mean \`export default { ... }\`? Falling back to defaults.`,
96
+ );
97
+ return {};
98
+ }
99
+
100
+ if (source === "module") {
101
+ // The user almost certainly forgot `export default`; their config is being read off the
102
+ // module namespace by accident. Surface a hint so they don't lose minutes to silent fallback.
103
+ console.warn(
104
+ `[vibeorm] vibeorm.config.ts is missing a default export. ` +
105
+ `Recommended: \`export default { ... } satisfies VibeOrmConfig\`.`,
106
+ );
107
+ }
108
+
109
+ return cfg as Partial<VibeOrmConfig>;
72
110
  }
73
111
 
74
112
  export async function resolveConfig(params: { flags?: Record<string, string> }): Promise<VibeOrmConfig> {
package/src/index.ts CHANGED
@@ -36,7 +36,19 @@ import { runMigrateRollback } from "./commands/migrate-rollback.ts";
36
36
 
37
37
  // ─── Command Router ───────────────────────────────────────────────
38
38
 
39
- const COMMANDS: Record<string, (params: { config: VibeOrmConfig; flags: Record<string, string> }) => Promise<void>> = {
39
+ /**
40
+ * Standard handler signature. `passthroughArgs` contains everything after the
41
+ * first standalone `--` token in the original argv — the canonical
42
+ * npm/bun/pnpm convention for forwarding flags to a wrapped script. Most
43
+ * commands ignore it; `db seed` forwards it to the user's seed script.
44
+ */
45
+ type CommandHandler = (params: {
46
+ config: VibeOrmConfig;
47
+ flags: Record<string, string>;
48
+ passthroughArgs: string[];
49
+ }) => Promise<void>;
50
+
51
+ const COMMANDS: Record<string, CommandHandler> = {
40
52
  "init": runInit,
41
53
  "generate": runGenerate,
42
54
  "db push": runDbPush,
@@ -80,7 +92,14 @@ function printHelp(): void {
80
92
  }
81
93
 
82
94
  async function main(): Promise<void> {
83
- const args = process.argv.slice(2);
95
+ const rawArgs = process.argv.slice(2);
96
+
97
+ // Split at the first standalone `--` token (npm/bun/pnpm convention).
98
+ // Everything before is for vibeorm; everything after is forwarded to the
99
+ // wrapped script (currently only consumed by `db seed`).
100
+ const separatorIdx = rawArgs.indexOf("--");
101
+ const args = separatorIdx === -1 ? rawArgs : rawArgs.slice(0, separatorIdx);
102
+ const passthroughArgs = separatorIdx === -1 ? [] : rawArgs.slice(separatorIdx + 1);
84
103
 
85
104
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
86
105
  printHelp();
@@ -109,7 +128,7 @@ async function main(): Promise<void> {
109
128
  const config = await resolveConfig({ flags });
110
129
 
111
130
  const handler = COMMANDS[command]!;
112
- await handler({ config, flags });
131
+ await handler({ config, flags, passthroughArgs });
113
132
  }
114
133
 
115
134
  main().catch((err) => {
@@ -1,14 +1,45 @@
1
1
  /**
2
2
  * Schema Loader — supports both single .prisma files and directories
3
- * containing multiple .prisma files.
3
+ * containing multiple .prisma files (including nested subdirectories,
4
+ * matching Prisma 7's multi-file mode).
4
5
  *
5
6
  * If the path is a file, reads it directly.
6
- * If the path is a directory, reads all *.prisma files within it
7
- * (sorted alphabetically) and concatenates them.
7
+ * If the path is a directory, walks recursively and reads every `.prisma` file
8
+ * (sorted by relative path so concatenation order is deterministic across OSes).
9
+ * Dotfile-prefixed files (e.g. `.cache.prisma`) are skipped so generated
10
+ * artefacts don't accidentally get included.
8
11
  */
9
12
 
10
13
  import { existsSync, readFileSync, readdirSync, statSync } from "fs";
11
- import { join } from "path";
14
+ import { join, sep } from "path";
15
+
16
+ function collectPrismaFiles(params: { root: string }): string[] {
17
+ const { root } = params;
18
+ // Node 18.17+/Bun supports { recursive: true } — returns string[] of paths
19
+ // relative to `root`, with platform-native separators.
20
+ const entries = readdirSync(root, { recursive: true }) as string[];
21
+
22
+ const files: string[] = [];
23
+ for (const entry of entries) {
24
+ if (!entry.endsWith(".prisma")) continue;
25
+ // Skip dotfile-prefixed segments at any depth (e.g. `.cache/foo.prisma`,
26
+ // `models/.tmp.prisma`). This protects against accidentally bundling
27
+ // editor scratch files or third-party-tool artefacts.
28
+ const segments = entry.split(sep);
29
+ if (segments.some((s) => s.startsWith("."))) continue;
30
+
31
+ const absolute = join(root, entry);
32
+ // Skip directories that happen to end in `.prisma` (rare but possible).
33
+ if (!statSync(absolute).isFile()) continue;
34
+
35
+ files.push(entry);
36
+ }
37
+
38
+ // Sort by normalised forward-slash path so output is deterministic regardless
39
+ // of the platform's readdir ordering or path separator.
40
+ files.sort((a, b) => a.split(sep).join("/").localeCompare(b.split(sep).join("/")));
41
+ return files;
42
+ }
12
43
 
13
44
  export function loadSchemaSource(params: { schemaPath: string }): string {
14
45
  const { schemaPath } = params;
@@ -26,22 +57,22 @@ export function loadSchemaSource(params: { schemaPath: string }): string {
26
57
  }
27
58
 
28
59
  if (stat.isDirectory()) {
29
- const files = readdirSync(schemaPath)
30
- .filter((f: string) => f.endsWith(".prisma"))
31
- .sort();
60
+ const files = collectPrismaFiles({ root: schemaPath });
32
61
 
33
62
  if (files.length === 0) {
34
- console.error(`Error: No .prisma files found in ${schemaPath}`);
63
+ console.error(`Error: No .prisma files found under ${schemaPath} (searched recursively)`);
35
64
  process.exit(1);
36
65
  }
37
66
 
38
67
  const sources: string[] = [];
39
68
  for (const file of files) {
40
69
  const filePath = join(schemaPath, file);
41
- sources.push(`// --- ${file} ---\n` + readFileSync(filePath, "utf-8"));
70
+ // Use the forward-slash form in the header so diffs are stable across OSes.
71
+ const displayPath = file.split(sep).join("/");
72
+ sources.push(`// --- ${displayPath} ---\n` + readFileSync(filePath, "utf-8"));
42
73
  }
43
74
 
44
- console.log(` Loaded ${files.length} schema files from ${schemaPath}`);
75
+ console.log(` Loaded ${files.length} schema file${files.length === 1 ? "" : "s"} from ${schemaPath}`);
45
76
  return sources.join("\n\n");
46
77
  }
47
78