@vertz/cli 0.2.12 → 0.2.14

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.
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env bun
2
+ import { createRequire } from "node:module";
3
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
+
5
+ // src/commands/load-db-context.ts
6
+ import {
7
+ access,
8
+ readFile as fsReadFile,
9
+ writeFile as fsWriteFile,
10
+ mkdir,
11
+ readdir
12
+ } from "node:fs/promises";
13
+ import { dirname, join, resolve } from "node:path";
14
+ import {
15
+ createSnapshot,
16
+ defaultPostgresDialect,
17
+ defaultSqliteDialect,
18
+ parseMigrationName
19
+ } from "@vertz/db";
20
+ import { NodeSnapshotStorage } from "@vertz/db/internals";
21
+ import { createJiti } from "jiti";
22
+ var DEFAULT_SQLITE_PATH = "./app.db";
23
+ async function loadDbContext() {
24
+ const configPath = resolve(process.cwd(), "vertz.config.ts");
25
+ const jiti = createJiti(import.meta.url, { interopDefault: true });
26
+ let configModule;
27
+ try {
28
+ configModule = await jiti.import(configPath);
29
+ } catch {
30
+ try {
31
+ await access(configPath);
32
+ } catch {
33
+ throw new Error(`Could not find vertz.config.ts in ${process.cwd()}. Create it with a db export:
34
+
35
+ ` + ` export const db = {
36
+ ` + ` dialect: 'sqlite',
37
+ ` + ` schema: './src/schema.ts',
38
+ ` + ` };
39
+ `);
40
+ }
41
+ throw new Error(`Failed to load vertz.config.ts: the file exists but could not be parsed. Check for syntax errors.`);
42
+ }
43
+ const dbConfig = configModule.db;
44
+ if (!dbConfig) {
45
+ throw new Error(`No \`db\` export found in ${configPath}. Add a named export:
46
+
47
+ ` + ` export const db = {
48
+ ` + ` dialect: 'sqlite',
49
+ ` + ` schema: './src/schema.ts',
50
+ ` + ` };
51
+ `);
52
+ }
53
+ if (!dbConfig.dialect) {
54
+ throw new Error('Missing `dialect` in db config (expected "sqlite" or "postgres")');
55
+ }
56
+ if (!dbConfig.schema) {
57
+ throw new Error("Missing `schema` in db config (path to schema file)");
58
+ }
59
+ const cwd = process.cwd();
60
+ const migrationsDir = resolve(cwd, dbConfig.migrationsDir ?? "./migrations");
61
+ const snapshotPath = dbConfig.snapshotPath ? resolve(cwd, dbConfig.snapshotPath) : join(migrationsDir, "_snapshot.json");
62
+ const schemaPath = resolve(cwd, dbConfig.schema);
63
+ let schemaModule;
64
+ try {
65
+ schemaModule = await jiti.import(schemaPath);
66
+ } catch {
67
+ try {
68
+ await access(schemaPath);
69
+ } catch {
70
+ throw new Error(`Schema file not found: ${schemaPath}. Check the \`schema\` path in your db config.`);
71
+ }
72
+ throw new Error(`Failed to load schema file at ${schemaPath}. Check for syntax errors.`);
73
+ }
74
+ const entries = extractSchemaEntries(schemaModule);
75
+ if (entries.length === 0) {
76
+ throw new Error(`No table definitions found in ${schemaPath}. Export your tables as named exports:
77
+
78
+ ` + ` export const users = d.table('users', { ... });
79
+ `);
80
+ }
81
+ const currentSnapshot = createSnapshot(entries);
82
+ const storage = new NodeSnapshotStorage;
83
+ const savedSnapshot = await storage.load(snapshotPath);
84
+ const previousSnapshot = savedSnapshot ?? { version: 1, tables: {}, enums: {} };
85
+ const dialect = dbConfig.dialect === "sqlite" ? defaultSqliteDialect : defaultPostgresDialect;
86
+ const connection = await createConnection(dbConfig);
87
+ const migrationFiles = await loadMigrationFiles(migrationsDir);
88
+ const existingFiles = migrationFiles.map((f) => f.name);
89
+ const writeFile = async (path, content) => {
90
+ await mkdir(dirname(path), { recursive: true });
91
+ await fsWriteFile(path, content, "utf-8");
92
+ };
93
+ const readFile = (path) => fsReadFile(path, "utf-8");
94
+ return {
95
+ queryFn: connection.queryFn,
96
+ currentSnapshot,
97
+ previousSnapshot,
98
+ savedSnapshot: savedSnapshot ?? undefined,
99
+ migrationFiles,
100
+ migrationsDir,
101
+ existingFiles,
102
+ dialect,
103
+ writeFile,
104
+ readFile,
105
+ close: connection.close
106
+ };
107
+ }
108
+ function isTableDef(v) {
109
+ return v !== null && typeof v === "object" && "_name" in v && "_columns" in v && typeof v._columns === "object" && v._columns !== null;
110
+ }
111
+ function isModelDef(v) {
112
+ return v !== null && typeof v === "object" && "table" in v && "relations" in v && isTableDef(v.table);
113
+ }
114
+ function extractSchemaEntries(module) {
115
+ const models = [];
116
+ const tables = [];
117
+ for (const value of Object.values(module)) {
118
+ if (isModelDef(value)) {
119
+ models.push(value);
120
+ } else if (isTableDef(value)) {
121
+ tables.push(value);
122
+ }
123
+ }
124
+ const modelTableNames = new Set(models.map((m) => m.table._name));
125
+ const dedupedTables = tables.filter((t) => !modelTableNames.has(t._name));
126
+ return [...models, ...dedupedTables];
127
+ }
128
+ function parseSqliteUrl(url) {
129
+ if (!url)
130
+ return DEFAULT_SQLITE_PATH;
131
+ if (!url.startsWith("sqlite:"))
132
+ return url;
133
+ const stripped = url.slice("sqlite:".length);
134
+ if (stripped.startsWith("///"))
135
+ return stripped.slice(2);
136
+ if (stripped.startsWith("//"))
137
+ return stripped.slice(2) || DEFAULT_SQLITE_PATH;
138
+ return stripped || DEFAULT_SQLITE_PATH;
139
+ }
140
+ async function createConnection(config) {
141
+ if (config.dialect === "sqlite") {
142
+ const dbPath = parseSqliteUrl(config.url);
143
+ let db;
144
+ try {
145
+ const { Database } = await import("bun:sqlite");
146
+ db = new Database(dbPath);
147
+ } catch (err) {
148
+ throw new Error(`Failed to load bun:sqlite. The vertz CLI requires the Bun runtime for SQLite support.
149
+ Run your command with: bun vertz db <command>`, { cause: err });
150
+ }
151
+ const queryFn2 = async (sql, params) => {
152
+ const stmt = db.prepare(sql);
153
+ const rows = stmt.all(...params);
154
+ return { rows, rowCount: rows.length };
155
+ };
156
+ const close2 = async () => {
157
+ db.close();
158
+ };
159
+ return { queryFn: queryFn2, close: close2 };
160
+ }
161
+ let client;
162
+ try {
163
+ const pg = (await import("postgres")).default;
164
+ client = pg(config.url ?? "");
165
+ } catch (err) {
166
+ throw new Error("Failed to load the `postgres` package. Install it in your project:\n npm install postgres # or: bun add postgres", { cause: err });
167
+ }
168
+ const queryFn = async (query, params) => {
169
+ const result = await client.unsafe(query, params);
170
+ const rows = Array.from(result);
171
+ return { rows, rowCount: rows.length };
172
+ };
173
+ const close = async () => {
174
+ await client.end();
175
+ };
176
+ return { queryFn, close };
177
+ }
178
+ async function loadMigrationFiles(dir) {
179
+ let entries;
180
+ try {
181
+ entries = await readdir(dir);
182
+ } catch (error) {
183
+ if (error.code === "ENOENT") {
184
+ return [];
185
+ }
186
+ throw error;
187
+ }
188
+ const files = [];
189
+ for (const filename of entries.filter((f) => f.endsWith(".sql"))) {
190
+ const parsed = parseMigrationName(filename);
191
+ if (!parsed)
192
+ continue;
193
+ const content = await fsReadFile(join(dir, filename), "utf-8");
194
+ files.push({
195
+ name: parsed.name,
196
+ sql: content,
197
+ timestamp: parsed.timestamp
198
+ });
199
+ }
200
+ return files.sort((a, b) => a.timestamp - b.timestamp);
201
+ }
202
+ async function loadAutoMigrateContext() {
203
+ const configPath = resolve(process.cwd(), "vertz.config.ts");
204
+ const jiti = createJiti(import.meta.url, { interopDefault: true });
205
+ let configModule;
206
+ try {
207
+ configModule = await jiti.import(configPath);
208
+ } catch {
209
+ try {
210
+ await access(configPath);
211
+ } catch {
212
+ throw new Error(`Could not find vertz.config.ts in ${process.cwd()}.`);
213
+ }
214
+ throw new Error("Failed to load vertz.config.ts.");
215
+ }
216
+ const dbConfig = configModule.db;
217
+ if (!dbConfig || !dbConfig.dialect || !dbConfig.schema) {
218
+ throw new Error("No valid `db` config found in vertz.config.ts.");
219
+ }
220
+ if (dbConfig.dialect !== "sqlite") {
221
+ throw new Error("Auto-migrate in dev currently only supports sqlite.");
222
+ }
223
+ const cwd = process.cwd();
224
+ const migrationsDir = resolve(cwd, dbConfig.migrationsDir ?? "./migrations");
225
+ const snapshotPath = dbConfig.snapshotPath ? resolve(cwd, dbConfig.snapshotPath) : join(migrationsDir, "_snapshot.json");
226
+ const schemaPath = resolve(cwd, dbConfig.schema);
227
+ try {
228
+ await access(schemaPath);
229
+ } catch {
230
+ throw new Error(`Schema file not found: ${schemaPath}.`);
231
+ }
232
+ const schemaModule = await import(`${schemaPath}?t=${Date.now()}`);
233
+ const entries = extractSchemaEntries(schemaModule);
234
+ if (entries.length === 0) {
235
+ throw new Error(`No table definitions found in ${schemaPath}.`);
236
+ }
237
+ const currentSchema = createSnapshot(entries);
238
+ const connection = await createConnection(dbConfig);
239
+ return {
240
+ currentSchema,
241
+ snapshotPath,
242
+ dialect: "sqlite",
243
+ db: connection.queryFn,
244
+ close: connection.close
245
+ };
246
+ }
247
+
248
+ export { __require, loadDbContext, extractSchemaEntries, parseSqliteUrl, createConnection, loadMigrationFiles, loadAutoMigrateContext };
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env bun
2
+ import {
3
+ createConnection,
4
+ extractSchemaEntries,
5
+ loadAutoMigrateContext,
6
+ loadDbContext,
7
+ loadMigrationFiles,
8
+ parseSqliteUrl
9
+ } from "./chunk-08ajrqm8.js";
10
+ export {
11
+ parseSqliteUrl,
12
+ loadMigrationFiles,
13
+ loadDbContext,
14
+ loadAutoMigrateContext,
15
+ extractSchemaEntries,
16
+ createConnection
17
+ };
@@ -0,0 +1,247 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/commands/load-db-context.ts
5
+ import {
6
+ access,
7
+ readFile as fsReadFile,
8
+ writeFile as fsWriteFile,
9
+ mkdir,
10
+ readdir
11
+ } from "node:fs/promises";
12
+ import { dirname, join, resolve } from "node:path";
13
+ import {
14
+ createSnapshot,
15
+ defaultPostgresDialect,
16
+ defaultSqliteDialect,
17
+ parseMigrationName
18
+ } from "@vertz/db";
19
+ import { NodeSnapshotStorage } from "@vertz/db/internals";
20
+ import { createJiti } from "jiti";
21
+ var DEFAULT_SQLITE_PATH = "./app.db";
22
+ async function loadDbContext() {
23
+ const configPath = resolve(process.cwd(), "vertz.config.ts");
24
+ const jiti = createJiti(import.meta.url, { interopDefault: true });
25
+ let configModule;
26
+ try {
27
+ configModule = await jiti.import(configPath);
28
+ } catch {
29
+ try {
30
+ await access(configPath);
31
+ } catch {
32
+ throw new Error(`Could not find vertz.config.ts in ${process.cwd()}. Create it with a db export:
33
+
34
+ ` + ` export const db = {
35
+ ` + ` dialect: 'sqlite',
36
+ ` + ` schema: './src/schema.ts',
37
+ ` + ` };
38
+ `);
39
+ }
40
+ throw new Error(`Failed to load vertz.config.ts: the file exists but could not be parsed. Check for syntax errors.`);
41
+ }
42
+ const dbConfig = configModule.db;
43
+ if (!dbConfig) {
44
+ throw new Error(`No \`db\` export found in ${configPath}. Add a named export:
45
+
46
+ ` + ` export const db = {
47
+ ` + ` dialect: 'sqlite',
48
+ ` + ` schema: './src/schema.ts',
49
+ ` + ` };
50
+ `);
51
+ }
52
+ if (!dbConfig.dialect) {
53
+ throw new Error('Missing `dialect` in db config (expected "sqlite" or "postgres")');
54
+ }
55
+ if (!dbConfig.schema) {
56
+ throw new Error("Missing `schema` in db config (path to schema file)");
57
+ }
58
+ const cwd = process.cwd();
59
+ const migrationsDir = resolve(cwd, dbConfig.migrationsDir ?? "./migrations");
60
+ const snapshotPath = dbConfig.snapshotPath ? resolve(cwd, dbConfig.snapshotPath) : join(migrationsDir, "_snapshot.json");
61
+ const schemaPath = resolve(cwd, dbConfig.schema);
62
+ let schemaModule;
63
+ try {
64
+ schemaModule = await jiti.import(schemaPath);
65
+ } catch {
66
+ try {
67
+ await access(schemaPath);
68
+ } catch {
69
+ throw new Error(`Schema file not found: ${schemaPath}. Check the \`schema\` path in your db config.`);
70
+ }
71
+ throw new Error(`Failed to load schema file at ${schemaPath}. Check for syntax errors.`);
72
+ }
73
+ const entries = extractSchemaEntries(schemaModule);
74
+ if (entries.length === 0) {
75
+ throw new Error(`No table definitions found in ${schemaPath}. Export your tables as named exports:
76
+
77
+ ` + ` export const users = d.table('users', { ... });
78
+ `);
79
+ }
80
+ const currentSnapshot = createSnapshot(entries);
81
+ const storage = new NodeSnapshotStorage;
82
+ const savedSnapshot = await storage.load(snapshotPath);
83
+ const previousSnapshot = savedSnapshot ?? { version: 1, tables: {}, enums: {} };
84
+ const dialect = dbConfig.dialect === "sqlite" ? defaultSqliteDialect : defaultPostgresDialect;
85
+ const connection = await createConnection(dbConfig);
86
+ const migrationFiles = await loadMigrationFiles(migrationsDir);
87
+ const existingFiles = migrationFiles.map((f) => f.name);
88
+ const writeFile = async (path, content) => {
89
+ await mkdir(dirname(path), { recursive: true });
90
+ await fsWriteFile(path, content, "utf-8");
91
+ };
92
+ const readFile = (path) => fsReadFile(path, "utf-8");
93
+ return {
94
+ queryFn: connection.queryFn,
95
+ currentSnapshot,
96
+ previousSnapshot,
97
+ savedSnapshot: savedSnapshot ?? undefined,
98
+ migrationFiles,
99
+ migrationsDir,
100
+ existingFiles,
101
+ dialect,
102
+ writeFile,
103
+ readFile,
104
+ close: connection.close
105
+ };
106
+ }
107
+ function isTableDef(v) {
108
+ return v !== null && typeof v === "object" && "_name" in v && "_columns" in v && typeof v._columns === "object" && v._columns !== null;
109
+ }
110
+ function isModelDef(v) {
111
+ return v !== null && typeof v === "object" && "table" in v && "relations" in v && isTableDef(v.table);
112
+ }
113
+ function extractSchemaEntries(module) {
114
+ const models = [];
115
+ const tables = [];
116
+ for (const value of Object.values(module)) {
117
+ if (isModelDef(value)) {
118
+ models.push(value);
119
+ } else if (isTableDef(value)) {
120
+ tables.push(value);
121
+ }
122
+ }
123
+ const modelTableNames = new Set(models.map((m) => m.table._name));
124
+ const dedupedTables = tables.filter((t) => !modelTableNames.has(t._name));
125
+ return [...models, ...dedupedTables];
126
+ }
127
+ function parseSqliteUrl(url) {
128
+ if (!url)
129
+ return DEFAULT_SQLITE_PATH;
130
+ if (!url.startsWith("sqlite:"))
131
+ return url;
132
+ const stripped = url.slice("sqlite:".length);
133
+ if (stripped.startsWith("///"))
134
+ return stripped.slice(2);
135
+ if (stripped.startsWith("//"))
136
+ return stripped.slice(2) || DEFAULT_SQLITE_PATH;
137
+ return stripped || DEFAULT_SQLITE_PATH;
138
+ }
139
+ async function createConnection(config) {
140
+ if (config.dialect === "sqlite") {
141
+ const dbPath = parseSqliteUrl(config.url);
142
+ let db;
143
+ try {
144
+ const { Database } = await import("bun:sqlite");
145
+ db = new Database(dbPath);
146
+ } catch (err) {
147
+ throw new Error(`Failed to load bun:sqlite. The vertz CLI requires the Bun runtime for SQLite support.
148
+ Run your command with: bun vertz db <command>`, { cause: err });
149
+ }
150
+ const queryFn2 = async (sql, params) => {
151
+ const stmt = db.prepare(sql);
152
+ const rows = stmt.all(...params);
153
+ return { rows, rowCount: rows.length };
154
+ };
155
+ const close2 = async () => {
156
+ db.close();
157
+ };
158
+ return { queryFn: queryFn2, close: close2 };
159
+ }
160
+ let client;
161
+ try {
162
+ const pg = (await import("postgres")).default;
163
+ client = pg(config.url ?? "");
164
+ } catch (err) {
165
+ throw new Error("Failed to load the `postgres` package. Install it in your project:\n npm install postgres # or: bun add postgres", { cause: err });
166
+ }
167
+ const queryFn = async (query, params) => {
168
+ const result = await client.unsafe(query, params);
169
+ const rows = Array.from(result);
170
+ return { rows, rowCount: rows.length };
171
+ };
172
+ const close = async () => {
173
+ await client.end();
174
+ };
175
+ return { queryFn, close };
176
+ }
177
+ async function loadMigrationFiles(dir) {
178
+ let entries;
179
+ try {
180
+ entries = await readdir(dir);
181
+ } catch (error) {
182
+ if (error.code === "ENOENT") {
183
+ return [];
184
+ }
185
+ throw error;
186
+ }
187
+ const files = [];
188
+ for (const filename of entries.filter((f) => f.endsWith(".sql"))) {
189
+ const parsed = parseMigrationName(filename);
190
+ if (!parsed)
191
+ continue;
192
+ const content = await fsReadFile(join(dir, filename), "utf-8");
193
+ files.push({
194
+ name: parsed.name,
195
+ sql: content,
196
+ timestamp: parsed.timestamp
197
+ });
198
+ }
199
+ return files.sort((a, b) => a.timestamp - b.timestamp);
200
+ }
201
+ async function loadAutoMigrateContext() {
202
+ const configPath = resolve(process.cwd(), "vertz.config.ts");
203
+ const jiti = createJiti(import.meta.url, { interopDefault: true });
204
+ let configModule;
205
+ try {
206
+ configModule = await jiti.import(configPath);
207
+ } catch {
208
+ try {
209
+ await access(configPath);
210
+ } catch {
211
+ throw new Error(`Could not find vertz.config.ts in ${process.cwd()}.`);
212
+ }
213
+ throw new Error("Failed to load vertz.config.ts.");
214
+ }
215
+ const dbConfig = configModule.db;
216
+ if (!dbConfig || !dbConfig.dialect || !dbConfig.schema) {
217
+ throw new Error("No valid `db` config found in vertz.config.ts.");
218
+ }
219
+ if (dbConfig.dialect !== "sqlite") {
220
+ throw new Error("Auto-migrate in dev currently only supports sqlite.");
221
+ }
222
+ const cwd = process.cwd();
223
+ const migrationsDir = resolve(cwd, dbConfig.migrationsDir ?? "./migrations");
224
+ const snapshotPath = dbConfig.snapshotPath ? resolve(cwd, dbConfig.snapshotPath) : join(migrationsDir, "_snapshot.json");
225
+ const schemaPath = resolve(cwd, dbConfig.schema);
226
+ try {
227
+ await access(schemaPath);
228
+ } catch {
229
+ throw new Error(`Schema file not found: ${schemaPath}.`);
230
+ }
231
+ const schemaModule = await import(`${schemaPath}?t=${Date.now()}`);
232
+ const entries = extractSchemaEntries(schemaModule);
233
+ if (entries.length === 0) {
234
+ throw new Error(`No table definitions found in ${schemaPath}.`);
235
+ }
236
+ const currentSchema = createSnapshot(entries);
237
+ const connection = await createConnection(dbConfig);
238
+ return {
239
+ currentSchema,
240
+ snapshotPath,
241
+ dialect: "sqlite",
242
+ db: connection.queryFn,
243
+ close: connection.close
244
+ };
245
+ }
246
+
247
+ export { __require, loadDbContext, extractSchemaEntries, parseSqliteUrl, createConnection, loadMigrationFiles, loadAutoMigrateContext };
@@ -0,0 +1,16 @@
1
+ import {
2
+ createConnection,
3
+ extractSchemaEntries,
4
+ loadAutoMigrateContext,
5
+ loadDbContext,
6
+ loadMigrationFiles,
7
+ parseSqliteUrl
8
+ } from "./chunk-tb59xfvg.js";
9
+ export {
10
+ parseSqliteUrl,
11
+ loadMigrationFiles,
12
+ loadDbContext,
13
+ loadAutoMigrateContext,
14
+ extractSchemaEntries,
15
+ createConnection
16
+ };