@vertz/cli 0.2.11 → 0.2.13
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/dist/index.d.ts +18 -2
- package/dist/index.js +313 -199
- package/dist/shared/chunk-08ajrqm8.js +248 -0
- package/dist/shared/chunk-f6hd0h7q.js +17 -0
- package/dist/shared/chunk-tb59xfvg.js +247 -0
- package/dist/shared/chunk-wvn2b9k8.js +16 -0
- package/dist/vertz.js +298 -185
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
__require,
|
|
3
|
+
loadDbContext
|
|
4
|
+
} from "./shared/chunk-tb59xfvg.js";
|
|
3
5
|
|
|
4
6
|
// src/index.ts
|
|
5
7
|
import {
|
|
@@ -14,7 +16,7 @@ import {
|
|
|
14
16
|
|
|
15
17
|
// src/cli.ts
|
|
16
18
|
import { Command } from "commander";
|
|
17
|
-
import { createJiti
|
|
19
|
+
import { createJiti } from "jiti";
|
|
18
20
|
|
|
19
21
|
// src/commands/build.ts
|
|
20
22
|
import { err, ok } from "@vertz/errors";
|
|
@@ -63,8 +65,11 @@ import { createCompiler as createCompiler2 } from "@vertz/compiler";
|
|
|
63
65
|
import * as esbuild from "esbuild";
|
|
64
66
|
|
|
65
67
|
// src/pipeline/orchestrator.ts
|
|
66
|
-
import {
|
|
67
|
-
import {
|
|
68
|
+
import { createCodegenPipeline, generate } from "@vertz/codegen";
|
|
69
|
+
import {
|
|
70
|
+
createCompiler,
|
|
71
|
+
OpenAPIGenerator
|
|
72
|
+
} from "@vertz/compiler";
|
|
68
73
|
var defaultPipelineConfig = {
|
|
69
74
|
sourceDir: "src",
|
|
70
75
|
outputDir: ".vertz/generated",
|
|
@@ -117,6 +122,13 @@ class PipelineOrchestrator {
|
|
|
117
122
|
if (!analyzeResult.success) {
|
|
118
123
|
success = false;
|
|
119
124
|
}
|
|
125
|
+
if (success) {
|
|
126
|
+
const dbSyncResult = await this.runDbSync();
|
|
127
|
+
stages.push(dbSyncResult);
|
|
128
|
+
if (!dbSyncResult.success) {
|
|
129
|
+
success = false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
120
132
|
if (success && this.appIR) {
|
|
121
133
|
const generateResult = await this.runCodegen();
|
|
122
134
|
stages.push(generateResult);
|
|
@@ -281,12 +293,60 @@ class PipelineOrchestrator {
|
|
|
281
293
|
}
|
|
282
294
|
async runDbSync() {
|
|
283
295
|
const startTime = performance.now();
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
296
|
+
if (!this.config.autoSyncDb) {
|
|
297
|
+
return {
|
|
298
|
+
stage: "db-sync",
|
|
299
|
+
success: true,
|
|
300
|
+
durationMs: performance.now() - startTime,
|
|
301
|
+
output: "DB sync skipped (disabled)"
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
let runner;
|
|
305
|
+
try {
|
|
306
|
+
if (this.config._dbSyncRunner) {
|
|
307
|
+
runner = await this.config._dbSyncRunner();
|
|
308
|
+
} else {
|
|
309
|
+
const { loadAutoMigrateContext } = await import("./shared/chunk-wvn2b9k8.js");
|
|
310
|
+
const ctx = await loadAutoMigrateContext();
|
|
311
|
+
const { autoMigrate } = await import("@vertz/db/internals");
|
|
312
|
+
runner = {
|
|
313
|
+
run: () => autoMigrate({
|
|
314
|
+
currentSchema: ctx.currentSchema,
|
|
315
|
+
snapshotPath: ctx.snapshotPath,
|
|
316
|
+
dialect: ctx.dialect,
|
|
317
|
+
db: ctx.db
|
|
318
|
+
}),
|
|
319
|
+
close: ctx.close
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
} catch {
|
|
323
|
+
return {
|
|
324
|
+
stage: "db-sync",
|
|
325
|
+
success: true,
|
|
326
|
+
durationMs: performance.now() - startTime,
|
|
327
|
+
output: "DB sync skipped (no db config)"
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
try {
|
|
331
|
+
await runner.run();
|
|
332
|
+
return {
|
|
333
|
+
stage: "db-sync",
|
|
334
|
+
success: true,
|
|
335
|
+
durationMs: performance.now() - startTime,
|
|
336
|
+
output: "DB sync complete"
|
|
337
|
+
};
|
|
338
|
+
} catch (error) {
|
|
339
|
+
return {
|
|
340
|
+
stage: "db-sync",
|
|
341
|
+
success: false,
|
|
342
|
+
durationMs: performance.now() - startTime,
|
|
343
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
344
|
+
};
|
|
345
|
+
} finally {
|
|
346
|
+
try {
|
|
347
|
+
await runner.close();
|
|
348
|
+
} catch {}
|
|
349
|
+
}
|
|
290
350
|
}
|
|
291
351
|
getAppIR() {
|
|
292
352
|
return this.appIR;
|
|
@@ -349,7 +409,7 @@ function getAffectedStages(category) {
|
|
|
349
409
|
case "entity":
|
|
350
410
|
return ["analyze", "openapi", "codegen"];
|
|
351
411
|
case "schema":
|
|
352
|
-
return ["codegen", "openapi"];
|
|
412
|
+
return ["db-sync", "codegen", "openapi"];
|
|
353
413
|
case "component":
|
|
354
414
|
return ["build-ui"];
|
|
355
415
|
case "config":
|
|
@@ -359,6 +419,7 @@ function getAffectedStages(category) {
|
|
|
359
419
|
return ["build-ui"];
|
|
360
420
|
}
|
|
361
421
|
}
|
|
422
|
+
var STAGE_ORDER = ["analyze", "db-sync", "codegen", "openapi", "build-ui"];
|
|
362
423
|
function getStagesForChanges(changes) {
|
|
363
424
|
const stages = new Set;
|
|
364
425
|
for (const change of changes) {
|
|
@@ -369,7 +430,7 @@ function getStagesForChanges(changes) {
|
|
|
369
430
|
if (stages.has("codegen") && !stages.has("analyze")) {
|
|
370
431
|
stages.add("analyze");
|
|
371
432
|
}
|
|
372
|
-
return
|
|
433
|
+
return STAGE_ORDER.filter((s) => stages.has(s));
|
|
373
434
|
}
|
|
374
435
|
function createWatcher(config) {
|
|
375
436
|
const {
|
|
@@ -1627,188 +1688,229 @@ function generateAction(options) {
|
|
|
1627
1688
|
}
|
|
1628
1689
|
}
|
|
1629
1690
|
|
|
1630
|
-
// src/commands/
|
|
1631
|
-
import {
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1691
|
+
// src/commands/start.ts
|
|
1692
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync } from "node:fs";
|
|
1693
|
+
import { join as join6, resolve as resolve3 } from "node:path";
|
|
1694
|
+
import { err as err7, ok as ok7 } from "@vertz/errors";
|
|
1695
|
+
function discoverSSRModule(projectRoot) {
|
|
1696
|
+
const serverDir = join6(projectRoot, "dist", "server");
|
|
1697
|
+
if (!existsSync6(serverDir))
|
|
1698
|
+
return;
|
|
1699
|
+
const files = readdirSync2(serverDir).filter((f) => f.endsWith(".js"));
|
|
1700
|
+
if (files.length === 0)
|
|
1701
|
+
return;
|
|
1702
|
+
if (files.includes("app.js")) {
|
|
1703
|
+
return join6(serverDir, "app.js");
|
|
1704
|
+
}
|
|
1705
|
+
const first = files[0];
|
|
1706
|
+
return first ? join6(serverDir, first) : undefined;
|
|
1707
|
+
}
|
|
1708
|
+
function validateBuildOutputs(projectRoot, appType) {
|
|
1709
|
+
const missing = [];
|
|
1710
|
+
if (appType === "api-only" || appType === "full-stack") {
|
|
1711
|
+
const apiBuild = join6(projectRoot, ".vertz", "build", "index.js");
|
|
1712
|
+
if (!existsSync6(apiBuild)) {
|
|
1713
|
+
missing.push(".vertz/build/index.js");
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
if (appType === "ui-only" || appType === "full-stack") {
|
|
1717
|
+
const clientHtml = join6(projectRoot, "dist", "client", "index.html");
|
|
1718
|
+
if (!existsSync6(clientHtml)) {
|
|
1719
|
+
missing.push("dist/client/index.html");
|
|
1720
|
+
}
|
|
1721
|
+
const ssrModule = discoverSSRModule(projectRoot);
|
|
1722
|
+
if (!ssrModule) {
|
|
1723
|
+
missing.push("dist/server/ (no SSR module found)");
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
if (missing.length > 0) {
|
|
1727
|
+
return err7(new Error(`Missing build outputs:
|
|
1728
|
+
- ${missing.join(`
|
|
1729
|
+
- `)}
|
|
1659
1730
|
|
|
1660
|
-
|
|
1661
|
-
` + ` dialect: 'sqlite',
|
|
1662
|
-
` + ` schema: './src/schema.ts',
|
|
1663
|
-
` + ` };
|
|
1664
|
-
`);
|
|
1665
|
-
}
|
|
1666
|
-
throw new Error(`Failed to load vertz.config.ts: the file exists but could not be parsed. Check for syntax errors.`);
|
|
1731
|
+
Run "vertz build" first.`));
|
|
1667
1732
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
` + ` };
|
|
1676
|
-
`);
|
|
1733
|
+
return ok7(undefined);
|
|
1734
|
+
}
|
|
1735
|
+
async function startAction(options = {}) {
|
|
1736
|
+
const { port = Number(process.env.PORT) || 3000, host = "0.0.0.0", verbose = false } = options;
|
|
1737
|
+
const projectRoot = findProjectRoot(process.cwd());
|
|
1738
|
+
if (!projectRoot) {
|
|
1739
|
+
return err7(new Error("Could not find project root. Are you in a Vertz project?"));
|
|
1677
1740
|
}
|
|
1678
|
-
|
|
1679
|
-
|
|
1741
|
+
let detected;
|
|
1742
|
+
try {
|
|
1743
|
+
detected = detectAppType(projectRoot);
|
|
1744
|
+
} catch (error) {
|
|
1745
|
+
return err7(new Error(error instanceof Error ? error.message : String(error)));
|
|
1680
1746
|
}
|
|
1681
|
-
if (
|
|
1682
|
-
|
|
1747
|
+
if (verbose) {
|
|
1748
|
+
console.log(`Detected app type: ${detected.type}`);
|
|
1683
1749
|
}
|
|
1684
|
-
const
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
const schemaPath = resolve3(cwd, dbConfig.schema);
|
|
1688
|
-
let schemaModule;
|
|
1689
|
-
try {
|
|
1690
|
-
schemaModule = await jiti.import(schemaPath);
|
|
1691
|
-
} catch {
|
|
1692
|
-
try {
|
|
1693
|
-
await access(schemaPath);
|
|
1694
|
-
} catch {
|
|
1695
|
-
throw new Error(`Schema file not found: ${schemaPath}. Check the \`schema\` path in your db config.`);
|
|
1696
|
-
}
|
|
1697
|
-
throw new Error(`Failed to load schema file at ${schemaPath}. Check for syntax errors.`);
|
|
1750
|
+
const validation = validateBuildOutputs(projectRoot, detected.type);
|
|
1751
|
+
if (!validation.ok) {
|
|
1752
|
+
return validation;
|
|
1698
1753
|
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1754
|
+
switch (detected.type) {
|
|
1755
|
+
case "api-only":
|
|
1756
|
+
return startApiOnly(projectRoot, port, host, verbose);
|
|
1757
|
+
case "ui-only":
|
|
1758
|
+
return startUIOnly(projectRoot, port, host, verbose);
|
|
1759
|
+
case "full-stack":
|
|
1760
|
+
return startFullStack(projectRoot, port, host, verbose);
|
|
1705
1761
|
}
|
|
1706
|
-
const currentSnapshot = createSnapshot(tables);
|
|
1707
|
-
const storage = new NodeSnapshotStorage;
|
|
1708
|
-
const savedSnapshot = await storage.load(snapshotPath);
|
|
1709
|
-
const previousSnapshot = savedSnapshot ?? { version: 1, tables: {}, enums: {} };
|
|
1710
|
-
const dialect = dbConfig.dialect === "sqlite" ? defaultSqliteDialect : defaultPostgresDialect;
|
|
1711
|
-
const connection = await createConnection(dbConfig);
|
|
1712
|
-
const migrationFiles = await loadMigrationFiles(migrationsDir);
|
|
1713
|
-
const existingFiles = migrationFiles.map((f) => f.name);
|
|
1714
|
-
const writeFile = async (path, content) => {
|
|
1715
|
-
await mkdir(dirname2(path), { recursive: true });
|
|
1716
|
-
await fsWriteFile(path, content, "utf-8");
|
|
1717
|
-
};
|
|
1718
|
-
const readFile = (path) => fsReadFile(path, "utf-8");
|
|
1719
|
-
return {
|
|
1720
|
-
queryFn: connection.queryFn,
|
|
1721
|
-
currentSnapshot,
|
|
1722
|
-
previousSnapshot,
|
|
1723
|
-
savedSnapshot: savedSnapshot ?? undefined,
|
|
1724
|
-
migrationFiles,
|
|
1725
|
-
migrationsDir,
|
|
1726
|
-
existingFiles,
|
|
1727
|
-
dialect,
|
|
1728
|
-
writeFile,
|
|
1729
|
-
readFile,
|
|
1730
|
-
close: connection.close
|
|
1731
|
-
};
|
|
1732
1762
|
}
|
|
1733
|
-
function
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
if (
|
|
1743
|
-
return
|
|
1744
|
-
const stripped = url.slice("sqlite:".length);
|
|
1745
|
-
if (stripped.startsWith("///"))
|
|
1746
|
-
return stripped.slice(2);
|
|
1747
|
-
if (stripped.startsWith("//"))
|
|
1748
|
-
return stripped.slice(2) || DEFAULT_SQLITE_PATH;
|
|
1749
|
-
return stripped || DEFAULT_SQLITE_PATH;
|
|
1750
|
-
}
|
|
1751
|
-
async function createConnection(config) {
|
|
1752
|
-
if (config.dialect === "sqlite") {
|
|
1753
|
-
const dbPath = parseSqliteUrl(config.url);
|
|
1754
|
-
let db;
|
|
1755
|
-
try {
|
|
1756
|
-
const { Database } = await import("bun:sqlite");
|
|
1757
|
-
db = new Database(dbPath);
|
|
1758
|
-
} catch (err7) {
|
|
1759
|
-
throw new Error(`Failed to load bun:sqlite. The vertz CLI requires the Bun runtime for SQLite support.
|
|
1760
|
-
Run your command with: bun vertz db <command>`, { cause: err7 });
|
|
1761
|
-
}
|
|
1762
|
-
const queryFn2 = async (sql, params) => {
|
|
1763
|
-
const stmt = db.prepare(sql);
|
|
1764
|
-
const rows = stmt.all(...params);
|
|
1765
|
-
return { rows, rowCount: rows.length };
|
|
1766
|
-
};
|
|
1767
|
-
const close2 = async () => {
|
|
1768
|
-
db.close();
|
|
1769
|
-
};
|
|
1770
|
-
return { queryFn: queryFn2, close: close2 };
|
|
1763
|
+
async function startApiOnly(projectRoot, port, host, _verbose) {
|
|
1764
|
+
const entryPath = resolve3(projectRoot, ".vertz", "build", "index.js");
|
|
1765
|
+
let mod;
|
|
1766
|
+
try {
|
|
1767
|
+
mod = await import(entryPath);
|
|
1768
|
+
} catch (error) {
|
|
1769
|
+
return err7(new Error(`Failed to import API module: ${error instanceof Error ? error.message : String(error)}`));
|
|
1770
|
+
}
|
|
1771
|
+
const handler = mod.default?.handler;
|
|
1772
|
+
if (typeof handler !== "function") {
|
|
1773
|
+
return err7(new Error("API module must export default with a .handler function."));
|
|
1771
1774
|
}
|
|
1772
|
-
|
|
1775
|
+
const server = Bun.serve({
|
|
1776
|
+
port,
|
|
1777
|
+
hostname: host,
|
|
1778
|
+
fetch: handler
|
|
1779
|
+
});
|
|
1780
|
+
console.log(`Vertz API server running at http://${host === "0.0.0.0" ? "localhost" : host}:${server.port}`);
|
|
1781
|
+
setupGracefulShutdown(server);
|
|
1782
|
+
return ok7(undefined);
|
|
1783
|
+
}
|
|
1784
|
+
async function startUIOnly(projectRoot, port, host, _verbose) {
|
|
1785
|
+
const ssrModulePath = discoverSSRModule(projectRoot);
|
|
1786
|
+
if (!ssrModulePath) {
|
|
1787
|
+
return err7(new Error('No SSR module found in dist/server/. Run "vertz build" first.'));
|
|
1788
|
+
}
|
|
1789
|
+
const templatePath = resolve3(projectRoot, "dist", "client", "index.html");
|
|
1790
|
+
const template = readFileSync(templatePath, "utf-8");
|
|
1791
|
+
let ssrModule;
|
|
1773
1792
|
try {
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
const
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1793
|
+
ssrModule = await import(ssrModulePath);
|
|
1794
|
+
} catch (error) {
|
|
1795
|
+
return err7(new Error(`Failed to import SSR module: ${error instanceof Error ? error.message : String(error)}`));
|
|
1796
|
+
}
|
|
1797
|
+
const inlineCSS = discoverInlineCSS(projectRoot);
|
|
1798
|
+
const { createSSRHandler } = await import("@vertz/ui-server/ssr");
|
|
1799
|
+
const ssrHandler = createSSRHandler({
|
|
1800
|
+
module: ssrModule,
|
|
1801
|
+
template,
|
|
1802
|
+
inlineCSS
|
|
1803
|
+
});
|
|
1804
|
+
const clientDir = resolve3(projectRoot, "dist", "client");
|
|
1805
|
+
const server = Bun.serve({
|
|
1806
|
+
port,
|
|
1807
|
+
hostname: host,
|
|
1808
|
+
async fetch(req) {
|
|
1809
|
+
const url = new URL(req.url);
|
|
1810
|
+
const pathname = url.pathname;
|
|
1811
|
+
const staticResponse = serveStaticFile(clientDir, pathname);
|
|
1812
|
+
if (staticResponse)
|
|
1813
|
+
return staticResponse;
|
|
1814
|
+
return ssrHandler(req);
|
|
1815
|
+
}
|
|
1816
|
+
});
|
|
1817
|
+
console.log(`Vertz server running at http://${host === "0.0.0.0" ? "localhost" : host}:${server.port}`);
|
|
1818
|
+
setupGracefulShutdown(server);
|
|
1819
|
+
return ok7(undefined);
|
|
1788
1820
|
}
|
|
1789
|
-
async function
|
|
1790
|
-
|
|
1821
|
+
async function startFullStack(projectRoot, port, host, _verbose) {
|
|
1822
|
+
const apiEntryPath = resolve3(projectRoot, ".vertz", "build", "index.js");
|
|
1823
|
+
let apiMod;
|
|
1791
1824
|
try {
|
|
1792
|
-
|
|
1825
|
+
apiMod = await import(apiEntryPath);
|
|
1793
1826
|
} catch (error) {
|
|
1794
|
-
|
|
1795
|
-
return [];
|
|
1796
|
-
}
|
|
1797
|
-
throw error;
|
|
1798
|
-
}
|
|
1799
|
-
const files = [];
|
|
1800
|
-
for (const filename of entries.filter((f) => f.endsWith(".sql"))) {
|
|
1801
|
-
const parsed = parseMigrationName(filename);
|
|
1802
|
-
if (!parsed)
|
|
1803
|
-
continue;
|
|
1804
|
-
const content = await fsReadFile(join6(dir, filename), "utf-8");
|
|
1805
|
-
files.push({
|
|
1806
|
-
name: parsed.name,
|
|
1807
|
-
sql: content,
|
|
1808
|
-
timestamp: parsed.timestamp
|
|
1809
|
-
});
|
|
1827
|
+
return err7(new Error(`Failed to import API module: ${error instanceof Error ? error.message : String(error)}`));
|
|
1810
1828
|
}
|
|
1811
|
-
|
|
1829
|
+
const apiHandler = apiMod.default?.handler;
|
|
1830
|
+
if (typeof apiHandler !== "function") {
|
|
1831
|
+
return err7(new Error("API module must export default with a .handler function."));
|
|
1832
|
+
}
|
|
1833
|
+
const ssrModulePath = discoverSSRModule(projectRoot);
|
|
1834
|
+
if (!ssrModulePath) {
|
|
1835
|
+
return err7(new Error('No SSR module found in dist/server/. Run "vertz build" first.'));
|
|
1836
|
+
}
|
|
1837
|
+
const templatePath = resolve3(projectRoot, "dist", "client", "index.html");
|
|
1838
|
+
const template = readFileSync(templatePath, "utf-8");
|
|
1839
|
+
let ssrModule;
|
|
1840
|
+
try {
|
|
1841
|
+
ssrModule = await import(ssrModulePath);
|
|
1842
|
+
} catch (error) {
|
|
1843
|
+
return err7(new Error(`Failed to import SSR module: ${error instanceof Error ? error.message : String(error)}`));
|
|
1844
|
+
}
|
|
1845
|
+
const inlineCSS = discoverInlineCSS(projectRoot);
|
|
1846
|
+
const { createSSRHandler } = await import("@vertz/ui-server/ssr");
|
|
1847
|
+
const ssrHandler = createSSRHandler({
|
|
1848
|
+
module: ssrModule,
|
|
1849
|
+
template,
|
|
1850
|
+
inlineCSS
|
|
1851
|
+
});
|
|
1852
|
+
const clientDir = resolve3(projectRoot, "dist", "client");
|
|
1853
|
+
const server = Bun.serve({
|
|
1854
|
+
port,
|
|
1855
|
+
hostname: host,
|
|
1856
|
+
async fetch(req) {
|
|
1857
|
+
const url = new URL(req.url);
|
|
1858
|
+
const pathname = url.pathname;
|
|
1859
|
+
if (pathname.startsWith("/api")) {
|
|
1860
|
+
return apiHandler(req);
|
|
1861
|
+
}
|
|
1862
|
+
const staticResponse = serveStaticFile(clientDir, pathname);
|
|
1863
|
+
if (staticResponse)
|
|
1864
|
+
return staticResponse;
|
|
1865
|
+
return ssrHandler(req);
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
console.log(`Vertz full-stack server running at http://${host === "0.0.0.0" ? "localhost" : host}:${server.port}`);
|
|
1869
|
+
setupGracefulShutdown(server);
|
|
1870
|
+
return ok7(undefined);
|
|
1871
|
+
}
|
|
1872
|
+
function discoverInlineCSS(projectRoot) {
|
|
1873
|
+
const cssDir = resolve3(projectRoot, "dist", "client", "assets");
|
|
1874
|
+
if (!existsSync6(cssDir))
|
|
1875
|
+
return;
|
|
1876
|
+
const cssFiles = readdirSync2(cssDir).filter((f) => f.endsWith(".css"));
|
|
1877
|
+
if (cssFiles.length === 0)
|
|
1878
|
+
return;
|
|
1879
|
+
const result = {};
|
|
1880
|
+
for (const file of cssFiles) {
|
|
1881
|
+
const content = readFileSync(join6(cssDir, file), "utf-8");
|
|
1882
|
+
result[`/assets/${file}`] = content;
|
|
1883
|
+
}
|
|
1884
|
+
return result;
|
|
1885
|
+
}
|
|
1886
|
+
function serveStaticFile(clientDir, pathname) {
|
|
1887
|
+
if (pathname === "/" || pathname === "/index.html")
|
|
1888
|
+
return null;
|
|
1889
|
+
const filePath = resolve3(clientDir, `.${pathname}`);
|
|
1890
|
+
if (!filePath.startsWith(clientDir))
|
|
1891
|
+
return null;
|
|
1892
|
+
const file = Bun.file(filePath);
|
|
1893
|
+
if (!file.size)
|
|
1894
|
+
return null;
|
|
1895
|
+
const isHashedAsset = pathname.startsWith("/assets/");
|
|
1896
|
+
const cacheControl = isHashedAsset ? "public, max-age=31536000, immutable" : "public, max-age=3600";
|
|
1897
|
+
return new Response(file, {
|
|
1898
|
+
headers: {
|
|
1899
|
+
"Cache-Control": cacheControl,
|
|
1900
|
+
"Content-Type": file.type
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
function setupGracefulShutdown(server) {
|
|
1905
|
+
const shutdown = () => {
|
|
1906
|
+
console.log(`
|
|
1907
|
+
Shutting down...`);
|
|
1908
|
+
server.stop();
|
|
1909
|
+
process.exit(0);
|
|
1910
|
+
};
|
|
1911
|
+
process.on("SIGINT", shutdown);
|
|
1912
|
+
process.on("SIGTERM", shutdown);
|
|
1913
|
+
process.on("SIGHUP", shutdown);
|
|
1812
1914
|
}
|
|
1813
1915
|
|
|
1814
1916
|
// src/cli.ts
|
|
@@ -1851,6 +1953,17 @@ function createCLI() {
|
|
|
1851
1953
|
process.exit(1);
|
|
1852
1954
|
}
|
|
1853
1955
|
});
|
|
1956
|
+
program.command("start").description('Start the production server (run "vertz build" first)').option("-p, --port <port>", "Server port (default: PORT env or 3000)").option("--host <host>", "Server host", "0.0.0.0").option("-v, --verbose", "Verbose output").action(async (opts) => {
|
|
1957
|
+
const result = await startAction({
|
|
1958
|
+
port: opts.port ? parseInt(opts.port, 10) : undefined,
|
|
1959
|
+
host: opts.host,
|
|
1960
|
+
verbose: opts.verbose
|
|
1961
|
+
});
|
|
1962
|
+
if (!result.ok) {
|
|
1963
|
+
console.error(result.error.message);
|
|
1964
|
+
process.exit(1);
|
|
1965
|
+
}
|
|
1966
|
+
});
|
|
1854
1967
|
program.command("generate [type] [name]").description("Generate a module, service, router, or schema").option("--dry-run", "Preview generated files without writing").option("--source-dir <dir>", "Source directory", "src").allowUnknownOption().action(async (type, name, options) => {
|
|
1855
1968
|
const validTypes = ["module", "service", "router", "schema"];
|
|
1856
1969
|
if (!type || !validTypes.includes(type)) {
|
|
@@ -1870,13 +1983,13 @@ function createCLI() {
|
|
|
1870
1983
|
}
|
|
1871
1984
|
});
|
|
1872
1985
|
program.command("codegen").description("Generate SDK and CLI clients from the compiled API").option("--dry-run", "Preview generated files without writing").option("--output <dir>", "Output directory").action(async (opts) => {
|
|
1873
|
-
const { resolve: resolve4, dirname:
|
|
1874
|
-
const { mkdir
|
|
1986
|
+
const { resolve: resolve4, dirname: dirname2 } = await import("node:path");
|
|
1987
|
+
const { mkdir, writeFile: fsWriteFile } = await import("node:fs/promises");
|
|
1875
1988
|
let config;
|
|
1876
1989
|
let compilerConfig;
|
|
1877
1990
|
try {
|
|
1878
1991
|
const configPath = resolve4(process.cwd(), "vertz.config.ts");
|
|
1879
|
-
const jiti =
|
|
1992
|
+
const jiti = createJiti(import.meta.url);
|
|
1880
1993
|
const configModule = await jiti.import(configPath);
|
|
1881
1994
|
config = configModule.codegen ?? configModule.default?.codegen;
|
|
1882
1995
|
compilerConfig = configModule.default;
|
|
@@ -1900,8 +2013,8 @@ function createCLI() {
|
|
|
1900
2013
|
const { createCodegenPipeline: createCodegenPipeline2 } = await import("@vertz/codegen");
|
|
1901
2014
|
const pipeline = createCodegenPipeline2();
|
|
1902
2015
|
const writeFile = async (path, content) => {
|
|
1903
|
-
await
|
|
1904
|
-
await
|
|
2016
|
+
await mkdir(dirname2(path), { recursive: true });
|
|
2017
|
+
await fsWriteFile(path, content, "utf-8");
|
|
1905
2018
|
};
|
|
1906
2019
|
const result = await codegenAction({
|
|
1907
2020
|
config,
|
|
@@ -2025,7 +2138,7 @@ Schema is in sync.`);
|
|
|
2025
2138
|
return program;
|
|
2026
2139
|
}
|
|
2027
2140
|
// src/commands/check.ts
|
|
2028
|
-
import { ok as
|
|
2141
|
+
import { ok as ok8 } from "@vertz/errors";
|
|
2029
2142
|
|
|
2030
2143
|
// src/ui/diagnostic-formatter.ts
|
|
2031
2144
|
import { symbols } from "@vertz/tui";
|
|
@@ -2120,10 +2233,10 @@ async function checkAction(options) {
|
|
|
2120
2233
|
break;
|
|
2121
2234
|
}
|
|
2122
2235
|
}
|
|
2123
|
-
return
|
|
2236
|
+
return ok8({ diagnostics, output, hasErrors });
|
|
2124
2237
|
}
|
|
2125
2238
|
// src/commands/deploy.ts
|
|
2126
|
-
import { err as
|
|
2239
|
+
import { err as err8, ok as ok9 } from "@vertz/errors";
|
|
2127
2240
|
|
|
2128
2241
|
// src/deploy/dockerfile.ts
|
|
2129
2242
|
function generateDockerConfig(runtime, port) {
|
|
@@ -2227,19 +2340,19 @@ var VALID_TARGETS = new Set(["fly", "railway", "docker"]);
|
|
|
2227
2340
|
function deployAction(options) {
|
|
2228
2341
|
const { target, runtime, port } = options;
|
|
2229
2342
|
if (!VALID_TARGETS.has(target)) {
|
|
2230
|
-
return
|
|
2343
|
+
return err8(new Error(`Unknown deploy target: "${target}". Valid targets: fly, railway, docker`));
|
|
2231
2344
|
}
|
|
2232
2345
|
switch (target) {
|
|
2233
2346
|
case "railway":
|
|
2234
|
-
return
|
|
2347
|
+
return ok9({ files: generateRailwayConfig(runtime) });
|
|
2235
2348
|
case "fly":
|
|
2236
|
-
return
|
|
2349
|
+
return ok9({ files: generateFlyConfig(runtime, port) });
|
|
2237
2350
|
case "docker":
|
|
2238
|
-
return
|
|
2351
|
+
return ok9({ files: generateDockerConfig(runtime, port) });
|
|
2239
2352
|
}
|
|
2240
2353
|
}
|
|
2241
2354
|
// src/commands/routes.ts
|
|
2242
|
-
import { ok as
|
|
2355
|
+
import { ok as ok10 } from "@vertz/errors";
|
|
2243
2356
|
function extractRoutes(ir) {
|
|
2244
2357
|
const routes = [];
|
|
2245
2358
|
for (const mod of ir.modules) {
|
|
@@ -2295,7 +2408,7 @@ async function routesAction(options) {
|
|
|
2295
2408
|
} else {
|
|
2296
2409
|
output = formatTable(routes);
|
|
2297
2410
|
}
|
|
2298
|
-
return
|
|
2411
|
+
return ok10({ routes, output });
|
|
2299
2412
|
}
|
|
2300
2413
|
// src/config/defaults.ts
|
|
2301
2414
|
var defaultCLIConfig = {
|
|
@@ -2315,14 +2428,14 @@ var defaultCLIConfig = {
|
|
|
2315
2428
|
generators: {}
|
|
2316
2429
|
};
|
|
2317
2430
|
// src/config/loader.ts
|
|
2318
|
-
import { existsSync as
|
|
2431
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
2319
2432
|
import { join as join7, resolve as resolve4 } from "node:path";
|
|
2320
2433
|
var CONFIG_FILES = ["vertz.config.ts", "vertz.config.js", "vertz.config.mjs"];
|
|
2321
2434
|
function findConfigFile(startDir) {
|
|
2322
2435
|
const dir = resolve4(startDir ?? process.cwd());
|
|
2323
2436
|
for (const filename of CONFIG_FILES) {
|
|
2324
2437
|
const filepath = join7(dir, filename);
|
|
2325
|
-
if (
|
|
2438
|
+
if (existsSync7(filepath)) {
|
|
2326
2439
|
return filepath;
|
|
2327
2440
|
}
|
|
2328
2441
|
}
|
|
@@ -2354,8 +2467,8 @@ async function loadConfig(configPath) {
|
|
|
2354
2467
|
if (!configPath) {
|
|
2355
2468
|
return { ...defaultConfig };
|
|
2356
2469
|
}
|
|
2357
|
-
const { createJiti:
|
|
2358
|
-
const jiti =
|
|
2470
|
+
const { createJiti: createJiti2 } = await import("jiti");
|
|
2471
|
+
const jiti = createJiti2(import.meta.url, {
|
|
2359
2472
|
interopDefault: true
|
|
2360
2473
|
});
|
|
2361
2474
|
const loaded = await jiti.import(configPath);
|
|
@@ -2463,6 +2576,7 @@ function detectRuntime() {
|
|
|
2463
2576
|
}
|
|
2464
2577
|
export {
|
|
2465
2578
|
symbols2 as symbols,
|
|
2579
|
+
startAction,
|
|
2466
2580
|
routesAction,
|
|
2467
2581
|
requireParam,
|
|
2468
2582
|
registerDevCommand,
|