@absolutejs/absolute 0.19.0-beta.169 → 0.19.0-beta.170

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/cli/index.js CHANGED
@@ -17,6 +17,293 @@ var __export = (target, all) => {
17
17
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
18
  var __require = import.meta.require;
19
19
 
20
+ // src/constants.ts
21
+ var ANSI_ESCAPE_LENGTH = 3, ASCII_SPACE = 32, BASE_36_RADIX = 36, BYTES_PER_KILOBYTE = 1024, CLI_ARGS_OFFSET = 3, DEFAULT_PORT = 3000, HOURS_IN_DAY = 24, HOURS_IN_HALF_DAY = 12, MAX_ERROR_LENGTH = 200, MILLISECONDS_IN_A_SECOND = 1000, MINUTES_IN_AN_HOUR = 60, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_MINUTE, MILLISECONDS_IN_A_DAY, SIGINT_EXIT_CODE = 130, SIGTERM_EXIT_CODE = 143, TIME_PRECISION = 2, TWO_THIRDS, UNFOUND_INDEX = -1;
22
+ var init_constants = __esm(() => {
23
+ MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
24
+ MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
25
+ TWO_THIRDS = 2 / 3;
26
+ });
27
+
28
+ // src/utils/getDurationString.ts
29
+ var getDurationString = (duration) => {
30
+ let durationString;
31
+ if (duration < MILLISECONDS_IN_A_SECOND) {
32
+ durationString = `${duration.toFixed(TIME_PRECISION)}ms`;
33
+ } else if (duration < MILLISECONDS_IN_A_MINUTE) {
34
+ durationString = `${(duration / MILLISECONDS_IN_A_SECOND).toFixed(TIME_PRECISION)}s`;
35
+ } else {
36
+ durationString = `${(duration / MILLISECONDS_IN_A_MINUTE).toFixed(TIME_PRECISION)}m`;
37
+ }
38
+ return durationString;
39
+ };
40
+ var init_getDurationString = __esm(() => {
41
+ init_constants();
42
+ });
43
+
44
+ // src/utils/startupBanner.ts
45
+ var MONTHS, formatTimestamp = () => {
46
+ const now = new Date;
47
+ const month = MONTHS[now.getMonth()];
48
+ const day = now.getDate().toString().padStart(2, "0");
49
+ let hours = now.getHours();
50
+ const minutes = now.getMinutes().toString().padStart(2, "0");
51
+ const seconds = now.getSeconds().toString().padStart(2, "0");
52
+ const ampm = hours >= HOURS_IN_HALF_DAY ? "PM" : "AM";
53
+ hours = hours % HOURS_IN_HALF_DAY || HOURS_IN_HALF_DAY;
54
+ return `${month} ${day} ${hours}:${minutes}:${seconds} ${ampm}`;
55
+ };
56
+ var init_startupBanner = __esm(() => {
57
+ init_constants();
58
+ init_getDurationString();
59
+ MONTHS = [
60
+ "Jan",
61
+ "Feb",
62
+ "Mar",
63
+ "Apr",
64
+ "May",
65
+ "Jun",
66
+ "Jul",
67
+ "Aug",
68
+ "Sep",
69
+ "Oct",
70
+ "Nov",
71
+ "Dec"
72
+ ];
73
+ });
74
+
75
+ // src/cli/scripts/telemetry.ts
76
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
77
+ import { homedir } from "os";
78
+ import { join } from "path";
79
+ var configDir, configPath, getTelemetryConfig = () => {
80
+ try {
81
+ if (!existsSync(configPath))
82
+ return null;
83
+ const raw = readFileSync(configPath, "utf-8");
84
+ const config = JSON.parse(raw);
85
+ return config;
86
+ } catch {
87
+ return null;
88
+ }
89
+ }, saveTelemetryConfig = (config) => {
90
+ mkdirSync(configDir, { recursive: true });
91
+ writeFileSync(configPath, `${JSON.stringify(config, null, "\t")}
92
+ `);
93
+ }, enable = () => {
94
+ const existing = getTelemetryConfig();
95
+ const config = {
96
+ anonymousId: existing?.anonymousId ?? crypto.randomUUID(),
97
+ createdAt: existing?.createdAt ?? new Date().toISOString(),
98
+ enabled: true
99
+ };
100
+ saveTelemetryConfig(config);
101
+ console.log("Telemetry enabled.");
102
+ console.log(`Anonymous ID: ${config.anonymousId}`);
103
+ }, disable = () => {
104
+ const existing = getTelemetryConfig();
105
+ if (existing) {
106
+ saveTelemetryConfig({ ...existing, enabled: false });
107
+ }
108
+ console.log("Telemetry disabled.");
109
+ }, status = () => {
110
+ const config = getTelemetryConfig();
111
+ if (!config || !config.enabled) {
112
+ console.log("Telemetry is disabled.");
113
+ } else {
114
+ console.log("Telemetry is enabled.");
115
+ console.log(`Anonymous ID: ${config.anonymousId}`);
116
+ }
117
+ }, telemetry = (args) => {
118
+ const [subcommand] = args;
119
+ if (subcommand === "enable") {
120
+ enable();
121
+ return;
122
+ }
123
+ if (subcommand === "disable") {
124
+ disable();
125
+ return;
126
+ }
127
+ if (subcommand === "status") {
128
+ status();
129
+ return;
130
+ }
131
+ if (!subcommand) {
132
+ status();
133
+ console.log("");
134
+ console.log("Usage: absolute telemetry <command>");
135
+ console.log("Commands:");
136
+ console.log(" enable Enable anonymous telemetry");
137
+ console.log(" disable Disable telemetry");
138
+ console.log(" status Show current telemetry status");
139
+ return;
140
+ }
141
+ console.error(`Unknown telemetry command: ${subcommand}`);
142
+ console.error("Usage: absolute telemetry <enable|disable|status>");
143
+ process.exit(1);
144
+ };
145
+ var init_telemetry = __esm(() => {
146
+ configDir = join(homedir(), ".absolutejs");
147
+ configPath = join(configDir, "telemetry.json");
148
+ });
149
+
150
+ // src/cli/telemetryEvent.ts
151
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
152
+ import { arch, platform } from "os";
153
+ import { dirname, join as join2, parse } from "path";
154
+ var checkCandidate = (candidate) => {
155
+ if (!existsSync2(candidate)) {
156
+ return null;
157
+ }
158
+ const pkg = JSON.parse(readFileSync2(candidate, "utf-8"));
159
+ if (pkg.name === "@absolutejs/absolute") {
160
+ const ver = pkg.version;
161
+ return ver;
162
+ }
163
+ return null;
164
+ }, getVersion = () => {
165
+ try {
166
+ return findPackageVersion();
167
+ } catch {
168
+ return "unknown";
169
+ }
170
+ }, findPackageVersion = () => {
171
+ let { dir } = import.meta;
172
+ while (dir !== parse(dir).root) {
173
+ const candidate = join2(dir, "package.json");
174
+ const version = checkCandidate(candidate);
175
+ if (version) {
176
+ return version;
177
+ }
178
+ dir = dirname(dir);
179
+ }
180
+ return "unknown";
181
+ }, sendTelemetryEvent = (event, payload) => {
182
+ try {
183
+ if (process.env.TELEMETRY_OFF === "1")
184
+ return;
185
+ const config = getTelemetryConfig();
186
+ if (!config?.enabled)
187
+ return;
188
+ const body = {
189
+ anonymousId: config.anonymousId,
190
+ arch: arch(),
191
+ bunVersion: Bun.version,
192
+ event,
193
+ os: platform(),
194
+ payload,
195
+ timestamp: new Date().toISOString(),
196
+ version: getVersion()
197
+ };
198
+ fetch("https://absolutejs.com/api/telemetry", {
199
+ body: JSON.stringify(body),
200
+ headers: { "Content-Type": "application/json" },
201
+ method: "POST"
202
+ }).catch(() => {
203
+ return;
204
+ });
205
+ } catch {}
206
+ };
207
+ var init_telemetryEvent = __esm(() => {
208
+ init_telemetry();
209
+ });
210
+
211
+ // src/utils/loadConfig.ts
212
+ import { resolve } from "path";
213
+ var loadConfig = async (configPath2) => {
214
+ const resolved = resolve(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts");
215
+ const mod = await import(resolved);
216
+ const config = mod.default ?? mod.config;
217
+ if (!config) {
218
+ throw new Error(`Config file "${resolved}" does not export a valid configuration.
219
+ Expected: export default defineConfig({ ... })`);
220
+ }
221
+ return config;
222
+ };
223
+ var init_loadConfig = () => {};
224
+
225
+ // src/cli/utils.ts
226
+ var {$ } = globalThis.Bun;
227
+ import { execSync } from "child_process";
228
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
229
+ import { resolve as resolve2 } from "path";
230
+ var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backend/server.ts", isWSLEnvironment = () => {
231
+ try {
232
+ const release = readFileSync3("/proc/version", "utf-8");
233
+ return /microsoft|wsl/i.test(release);
234
+ } catch {
235
+ return false;
236
+ }
237
+ }, safeKill = (pid) => {
238
+ try {
239
+ process.kill(pid, "SIGTERM");
240
+ } catch {}
241
+ }, killStaleProcesses = (port) => {
242
+ let output;
243
+ try {
244
+ output = execSync(`lsof -ti tcp:${port} -sTCP:LISTEN 2>/dev/null`, {
245
+ encoding: "utf-8"
246
+ }).trim();
247
+ } catch {
248
+ return;
249
+ }
250
+ if (!output) {
251
+ return;
252
+ }
253
+ const pids = output.split(`
254
+ `).map(Number).filter((pid) => pid !== process.pid && pid > 0);
255
+ if (pids.length === 0) {
256
+ return;
257
+ }
258
+ pids.forEach(safeKill);
259
+ console.log(`\x1B[2m${formatTimestamp()}\x1B[0m \x1B[33m[cli]\x1B[0m \x1B[33mKilled ${pids.length} stale ${pids.length === 1 ? "process" : "processes"} on port ${port}.\x1B[0m`);
260
+ }, printHelp = () => {
261
+ console.log("");
262
+ console.log("\x1B[1mShortcuts:\x1B[0m");
263
+ console.log(" \x1B[36mr\x1B[0m / restart \u2014 Restart server");
264
+ console.log(" \x1B[36mp\x1B[0m / pause \u2014 Pause/resume server");
265
+ console.log(" \x1B[36mo\x1B[0m / open \u2014 Open in browser");
266
+ console.log(" \x1B[36mc\x1B[0m / clear \u2014 Clear terminal");
267
+ console.log(" \x1B[36mq\x1B[0m / quit \u2014 Graceful shutdown");
268
+ console.log(" \x1B[36mh\x1B[0m / help \u2014 Show this help");
269
+ console.log(" \x1B[36m$\x1B[0m \u2014 Run a shell command");
270
+ console.log(" \x1B[36m\u2191\x1B[0m / \x1B[36m\u2193\x1B[0m \u2014 Command history");
271
+ console.log("");
272
+ }, printHint = () => {
273
+ console.log("\x1B[90mpress h + enter to show shortcuts\x1B[0m");
274
+ }, readDbScripts = async () => {
275
+ const pkgPath = resolve2("package.json");
276
+ if (!existsSync3(pkgPath))
277
+ return null;
278
+ const pkg = await Bun.file(pkgPath).json();
279
+ const upCommand = pkg.scripts?.["db:up"];
280
+ const downCommand = pkg.scripts?.["db:down"];
281
+ if (!upCommand || !downCommand)
282
+ return null;
283
+ return { downCommand, upCommand };
284
+ }, startDatabase = async (scripts) => {
285
+ await timed("Starting database container...", async () => {
286
+ const { exitCode } = await $`${{ raw: scripts.upCommand }}`.quiet().nothrow();
287
+ if (exitCode !== 0)
288
+ process.exit(exitCode);
289
+ });
290
+ }, stopDatabase = async (scripts) => {
291
+ console.log(`
292
+ Stopping database container...`);
293
+ await $`${{ raw: scripts.downCommand }}`.quiet().nothrow();
294
+ }, timed = async (label, task) => {
295
+ process.stdout.write(label);
296
+ const start = performance.now();
297
+ await task();
298
+ const duration = ((performance.now() - start) / MILLISECONDS_IN_A_SECOND).toFixed(2);
299
+ process.stdout.write(` \x1B[90m${duration}s\x1B[0m
300
+ `);
301
+ };
302
+ var init_utils = __esm(() => {
303
+ init_constants();
304
+ init_startupBanner();
305
+ });
306
+
20
307
  // src/dev/devCert.ts
21
308
  var exports_devCert = {};
22
309
  __export(exports_devCert, {
@@ -233,79 +520,414 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
233
520
  devLog("mkcert installed \u2014 HTTPS certificates are now locally trusted");
234
521
  return true;
235
522
  };
236
- var init_devCert = __esm(() => {
237
- CERT_DIR = join3(process.cwd(), ".absolutejs");
238
- CERT_PATH = join3(CERT_DIR, "cert.pem");
239
- KEY_PATH = join3(CERT_DIR, "key.pem");
523
+ var init_devCert = __esm(() => {
524
+ CERT_DIR = join3(process.cwd(), ".absolutejs");
525
+ CERT_PATH = join3(CERT_DIR, "cert.pem");
526
+ KEY_PATH = join3(CERT_DIR, "key.pem");
527
+ });
528
+
529
+ // src/cli/scripts/compile.ts
530
+ var exports_compile = {};
531
+ __export(exports_compile, {
532
+ compile: () => compile
533
+ });
534
+ var {env: env3 } = globalThis.Bun;
535
+ import {
536
+ existsSync as existsSync8,
537
+ mkdirSync as mkdirSync3,
538
+ readdirSync,
539
+ readFileSync as readFileSync7,
540
+ unlinkSync
541
+ } from "fs";
542
+ import { basename as basename2, join as join5, relative, resolve as resolve6 } from "path";
543
+ var cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, collectFiles2 = (dir) => {
544
+ const results = [];
545
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
546
+ const fullPath = join5(dir, entry.name);
547
+ if (entry.isDirectory()) {
548
+ results.push(...collectFiles2(fullPath));
549
+ } else {
550
+ results.push(fullPath);
551
+ }
552
+ }
553
+ return results;
554
+ }, resolvePackageVersion2 = (candidates) => {
555
+ for (const candidate of candidates) {
556
+ try {
557
+ const pkg = JSON.parse(readFileSync7(candidate, "utf-8"));
558
+ if (pkg.name === "@absolutejs/absolute")
559
+ return pkg.version;
560
+ } catch {}
561
+ }
562
+ return "";
563
+ }, resolveBuildModule2 = async (candidates) => {
564
+ for (const candidate of candidates) {
565
+ try {
566
+ const mod = await import(candidate);
567
+ return mod.build;
568
+ } catch {}
569
+ }
570
+ return;
571
+ }, prerender = async (port, outDir) => {
572
+ const prerenderDir = join5(outDir, "_prerendered");
573
+ mkdirSync3(prerenderDir, { recursive: true });
574
+ const baseUrl = `http://localhost:${port}`;
575
+ const visited = new Set;
576
+ const queue = ["/"];
577
+ const savedFiles = [];
578
+ while (queue.length > 0) {
579
+ const path = queue.shift();
580
+ if (visited.has(path))
581
+ continue;
582
+ visited.add(path);
583
+ try {
584
+ const res = await fetch(`${baseUrl}${path}`);
585
+ if (!res.ok)
586
+ continue;
587
+ const contentType = res.headers.get("content-type") ?? "";
588
+ if (!contentType.includes("text/html"))
589
+ continue;
590
+ const html = await res.text();
591
+ const fileName = path === "/" ? "index.html" : `${path.slice(1).replace(/\//g, "-")}.html`;
592
+ const filePath = join5(prerenderDir, fileName);
593
+ await Bun.write(filePath, html);
594
+ savedFiles.push(filePath);
595
+ console.log(cliTag3("\x1B[36m", ` Pre-rendered ${path} \u2192 ${fileName} (${html.length} bytes)`));
596
+ const linkRegex = /href=["'](\/[^"']*?)["']/g;
597
+ let match;
598
+ while ((match = linkRegex.exec(html)) !== null) {
599
+ const href = match[1] ?? "";
600
+ if (!href || href.includes(".") || href.includes("#") || visited.has(href))
601
+ continue;
602
+ queue.push(href);
603
+ }
604
+ } catch {}
605
+ }
606
+ return savedFiles;
607
+ }, generateEntrypoint = (distDir, serverEntry, prerenderMap) => {
608
+ const allFiles = collectFiles2(distDir);
609
+ const serverBundleName = basename2(serverEntry).replace(/\.[^.]+$/, "") + ".js";
610
+ const skip = new Set([
611
+ serverBundleName,
612
+ "manifest.json",
613
+ "_compile_entrypoint.ts"
614
+ ]);
615
+ const clientFiles = allFiles.filter((f) => {
616
+ const rel = relative(distDir, f);
617
+ if (skip.has(rel))
618
+ return false;
619
+ if (rel.includes(".generated"))
620
+ return false;
621
+ if (rel.includes("/server/"))
622
+ return false;
623
+ return true;
624
+ });
625
+ const imports = [];
626
+ const mappings = [];
627
+ clientFiles.forEach((filePath, idx) => {
628
+ const rel = relative(distDir, filePath).replace(/\\/g, "/");
629
+ const varName = `__a${idx}`;
630
+ const urlPath = "/" + rel;
631
+ imports.push(`import ${varName} from "./${rel}" with { type: "file" };`);
632
+ mappings.push(` "${urlPath}": ${varName},`);
633
+ if (rel.startsWith("workers/") && rel.endsWith(".js")) {
634
+ const parts = rel.match(/^(workers\/[^.]+\.worker)\.[a-z0-9]+\.js$/);
635
+ if (parts) {
636
+ mappings.push(` "/${parts[1]}.js": ${varName},`);
637
+ }
638
+ }
639
+ });
640
+ const pageVarMap = new Map;
641
+ for (const [route, filePath] of prerenderMap) {
642
+ const rel = relative(distDir, filePath).replace(/\\/g, "/");
643
+ const idx = clientFiles.findIndex((f) => relative(distDir, f).replace(/\\/g, "/") === rel);
644
+ if (idx >= 0) {
645
+ pageVarMap.set(route, `__a${idx}`);
646
+ }
647
+ }
648
+ const routeEntries = Array.from(pageVarMap.entries()).map(([route, varName]) => ` "${route}": ${varName},`).join(`
649
+ `);
650
+ return `// Auto-generated compile entrypoint
651
+ import { Elysia } from "elysia";
652
+
653
+ // \u2500\u2500 Embedded asset imports \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
654
+ ${imports.join(`
655
+ `)}
656
+
657
+ // \u2500\u2500 Asset URL \u2192 embedded path map \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
658
+ const ASSETS: Record<string, string> = {
659
+ ${mappings.join(`
660
+ `)}
661
+ };
662
+
663
+ // \u2500\u2500 Pre-rendered page routes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
664
+ const PAGES: Record<string, string> = {
665
+ ${routeEntries}
666
+ };
667
+
668
+ // \u2500\u2500 MIME types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
669
+ const MIME: Record<string, string> = {
670
+ ".js": "application/javascript; charset=utf-8",
671
+ ".css": "text/css; charset=utf-8",
672
+ ".html": "text/html; charset=utf-8",
673
+ ".json": "application/json",
674
+ ".png": "image/png",
675
+ ".jpg": "image/jpeg",
676
+ ".svg": "image/svg+xml",
677
+ ".ico": "image/x-icon",
678
+ ".woff": "font/woff",
679
+ ".woff2": "font/woff2",
680
+ ".ttf": "font/ttf",
681
+ ".webp": "image/webp",
682
+ ".avif": "image/avif",
683
+ };
684
+
685
+ const getMime = (p: string) =>
686
+ MIME[p.substring(p.lastIndexOf("."))] ?? "application/octet-stream";
687
+
688
+ // \u2500\u2500 Server \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
689
+ const port = Number(process.env.PORT) || ${DEFAULT_PORT};
690
+
691
+ const servePage = (path: string) =>
692
+ new Response(Bun.file(path), {
693
+ headers: { "content-type": "text/html; charset=utf-8" },
694
+ });
695
+
696
+ const app = new Elysia()
697
+ // Static assets from embedded filesystem
698
+ .onRequest(({ request, set }) => {
699
+ const url = new URL(request.url);
700
+
701
+ // Check for pre-rendered page
702
+ const page = PAGES[url.pathname];
703
+ if (page) return servePage(page);
704
+
705
+ // Check for embedded asset
706
+ const embedded = ASSETS[url.pathname];
707
+ if (!embedded) return;
708
+ set.headers["content-type"] = getMime(url.pathname);
709
+ set.headers["cache-control"] = "public, max-age=31536000, immutable";
710
+ return new Response(Bun.file(embedded));
711
+ })
712
+ .listen(port);
713
+
714
+ const assetCount = Object.keys(ASSETS).length;
715
+ const pageCount = Object.keys(PAGES).length;
716
+ console.log(\`
717
+ \\x1b[36m\\x1b[1mABSOLUTEJS\\x1b[0m \\x1b[2mcompiled executable\\x1b[0m
718
+
719
+ \\x1b[32m\u279C\\x1b[0m \\x1b[1mLocal:\\x1b[0m http://localhost:\${port}/
720
+
721
+ \\x1b[2m\${pageCount} pre-rendered pages, \${assetCount} embedded assets\\x1b[0m
722
+ \\x1b[2mNo external files needed\\x1b[0m
723
+ \`);
724
+ `;
725
+ }, createStubPlugin = () => ({
726
+ name: "stub-framework-sources",
727
+ setup(bld) {
728
+ bld.onLoad({ filter: /\.(svelte|vue)$/ }, () => ({
729
+ contents: "export default {}",
730
+ loader: "js"
731
+ }));
732
+ bld.onLoad({ filter: /devBuild\.ts$/ }, () => ({
733
+ contents: "export const devBuild = () => {}",
734
+ loader: "js"
735
+ }));
736
+ bld.onLoad({ filter: /core\/build\.ts$/ }, () => ({
737
+ contents: "export const build = () => ({})",
738
+ loader: "js"
739
+ }));
740
+ bld.onLoad({ filter: /src\/build\.ts$/ }, () => ({
741
+ contents: "export const build = () => ({}); export const devBuild = () => {};",
742
+ loader: "js"
743
+ }));
744
+ bld.onLoad({ filter: /plugins\/hmr\.ts$/ }, () => ({
745
+ contents: "export const hmr = () => (app) => app;",
746
+ loader: "js"
747
+ }));
748
+ bld.onLoad({
749
+ filter: /dev\/(assetStore|clientManager|webSocket|moduleVersionTracker|buildHMRClient)\.ts$/
750
+ }, () => ({ contents: "export {};", loader: "js" }));
751
+ bld.onLoad({ filter: /cli\/(telemetryEvent|scripts\/telemetry)\.ts$/ }, () => ({
752
+ contents: "export const sendTelemetryEvent = () => {}; export const getTelemetryConfig = () => null; export const telemetry = () => {};",
753
+ loader: "js"
754
+ }));
755
+ bld.onLoad({
756
+ filter: /react-dom-server-legacy\.browser\.(production|development)\.js$/
757
+ }, () => ({
758
+ contents: "exports.renderToString = undefined; exports.renderToStaticMarkup = undefined;",
759
+ loader: "js"
760
+ }));
761
+ bld.onLoad({ filter: /node_modules\/debug/ }, () => ({
762
+ contents: "module.exports = () => { const noop = () => {}; noop.enabled = false; return noop; }; module.exports.enable = () => {}; module.exports.disable = () => {}; module.exports.enabled = () => false;",
763
+ loader: "js"
764
+ }));
765
+ bld.onLoad({ filter: /\.ts$/ }, async (args) => {
766
+ if (args.path.includes("node_modules"))
767
+ return;
768
+ const text = await Bun.file(args.path).text();
769
+ const stripped = text.replace(/`(?:[^`\\]|\\.)*`/gs, "").replace(/'(?:[^'\\]|\\.)*'/g, "").replace(/"(?:[^"\\]|\\.)*"/g, "");
770
+ if (stripped.includes("@Component")) {
771
+ return { contents: "export default {}", loader: "js" };
772
+ }
773
+ return;
774
+ });
775
+ }
776
+ }), FRAMEWORK_EXTERNALS, compile = async (serverEntry, outdir, outfile, configPath2) => {
777
+ const prerenderPort = Number(env3.COMPILE_PORT) || Number(env3.PORT) || DEFAULT_PORT + 1;
778
+ killStaleProcesses(prerenderPort);
779
+ const entryName = basename2(serverEntry).replace(/\.[^.]+$/, "");
780
+ const resolvedOutdir = resolve6(outdir ?? "dist");
781
+ const resolvedOutfile = resolve6(outfile ?? "compiled-server");
782
+ const absoluteVersion = resolvePackageVersion2([
783
+ resolve6(import.meta.dir, "..", "..", "..", "package.json"),
784
+ resolve6(import.meta.dir, "..", "..", "package.json")
785
+ ]);
786
+ const totalStart = performance.now();
787
+ const buildStart = performance.now();
788
+ process.stdout.write(cliTag3("\x1B[36m", "Building assets"));
789
+ const buildConfig = await loadConfig(configPath2);
790
+ buildConfig.buildDirectory = resolvedOutdir;
791
+ buildConfig.mode = "production";
792
+ try {
793
+ const build = await resolveBuildModule2([
794
+ resolve6(import.meta.dir, "..", "..", "core", "build"),
795
+ resolve6(import.meta.dir, "..", "build")
796
+ ]);
797
+ if (!build)
798
+ throw new Error("Could not locate build module");
799
+ await build(buildConfig);
800
+ } catch (err) {
801
+ console.error(cliTag3("\x1B[31m", "Build step failed."));
802
+ console.error(err);
803
+ process.exit(1);
804
+ }
805
+ console.log(` \x1B[2m(${getDurationString(performance.now() - buildStart)})\x1B[0m`);
806
+ const bundleStart = performance.now();
807
+ process.stdout.write(cliTag3("\x1B[36m", "Bundling production server"));
808
+ const serverBundle = await Bun.build({
809
+ define: { "process.env.NODE_ENV": '"production"' },
810
+ entrypoints: [resolve6(serverEntry)],
811
+ external: FRAMEWORK_EXTERNALS,
812
+ outdir: resolvedOutdir,
813
+ plugins: [createStubPlugin()],
814
+ target: "bun"
815
+ });
816
+ if (!serverBundle.success) {
817
+ serverBundle.logs.forEach((log) => console.error(log));
818
+ console.error(cliTag3("\x1B[31m", "Server bundle failed."));
819
+ process.exit(1);
820
+ }
821
+ const outputPath = resolve6(resolvedOutdir, `${entryName}.js`);
822
+ if (!existsSync8(outputPath)) {
823
+ console.error(cliTag3("\x1B[31m", `Expected output not found: ${outputPath}`));
824
+ process.exit(1);
825
+ }
826
+ console.log(` \x1B[2m(${getDurationString(performance.now() - bundleStart)})\x1B[0m`);
827
+ const prerenderStart = performance.now();
828
+ console.log(cliTag3("\x1B[36m", "Pre-rendering pages..."));
829
+ const serverProcess = Bun.spawn(["bun", "run", outputPath], {
830
+ cwd: process.cwd(),
831
+ env: {
832
+ ...process.env,
833
+ ABSOLUTE_BUILD_DIR: resolvedOutdir,
834
+ ABSOLUTE_VERSION: absoluteVersion,
835
+ FORCE_COLOR: "0",
836
+ NODE_ENV: "production",
837
+ PORT: String(prerenderPort),
838
+ ...configPath2 ? { ABSOLUTE_CONFIG: configPath2 } : {}
839
+ },
840
+ stdout: "pipe",
841
+ stderr: "pipe"
842
+ });
843
+ let ready = false;
844
+ for (let i = 0;i < 50; i++) {
845
+ try {
846
+ const res = await fetch(`http://localhost:${prerenderPort}/`);
847
+ if (res.ok) {
848
+ ready = true;
849
+ break;
850
+ }
851
+ } catch {}
852
+ await Bun.sleep(100);
853
+ }
854
+ if (!ready) {
855
+ serverProcess.kill();
856
+ console.error(cliTag3("\x1B[31m", "Server failed to start for pre-rendering."));
857
+ process.exit(1);
858
+ }
859
+ const prerenderFiles = await prerender(prerenderPort, resolvedOutdir);
860
+ serverProcess.kill();
861
+ await serverProcess.exited;
862
+ const prerenderMap = new Map;
863
+ for (const filePath of prerenderFiles) {
864
+ const fileName = basename2(filePath, ".html");
865
+ const route = fileName === "index" ? "/" : `/${fileName}`;
866
+ prerenderMap.set(route, filePath);
867
+ }
868
+ console.log(cliTag3("\x1B[36m", `Pre-rendered ${prerenderMap.size} pages (${getDurationString(performance.now() - prerenderStart)})`));
869
+ const compileStart = performance.now();
870
+ process.stdout.write(cliTag3("\x1B[36m", "Compiling standalone executable"));
871
+ const entrypointCode = generateEntrypoint(resolvedOutdir, serverEntry, prerenderMap);
872
+ const entrypointPath = join5(resolvedOutdir, "_compile_entrypoint.ts");
873
+ await Bun.write(entrypointPath, entrypointCode);
874
+ const result = await Bun.build({
875
+ entrypoints: [entrypointPath],
876
+ compile: { outfile: resolvedOutfile },
877
+ define: { "process.env.NODE_ENV": '"production"' },
878
+ target: "bun"
879
+ });
880
+ if (!result.success) {
881
+ result.logs.forEach((log) => console.error(log));
882
+ console.error(cliTag3("\x1B[31m", "Compilation failed."));
883
+ process.exit(1);
884
+ }
885
+ console.log(` \x1B[2m(${getDurationString(performance.now() - compileStart)})\x1B[0m`);
886
+ try {
887
+ unlinkSync(entrypointPath);
888
+ } catch {}
889
+ const size = (Bun.file(resolvedOutfile).size / 1048576).toFixed(0);
890
+ const totalDuration = getDurationString(performance.now() - totalStart);
891
+ console.log(cliTag3("\x1B[32m", `Compiled to ${resolvedOutfile} (${size}MB) in ${totalDuration}`));
892
+ console.log(cliTag3("\x1B[2m", `Run with: ./${basename2(resolvedOutfile)}`));
893
+ sendTelemetryEvent("compile:complete", {
894
+ durationMs: Math.round(performance.now() - totalStart),
895
+ entry: serverEntry,
896
+ pages: prerenderMap.size
897
+ });
898
+ };
899
+ var init_compile = __esm(() => {
900
+ init_constants();
901
+ init_getDurationString();
902
+ init_loadConfig();
903
+ init_startupBanner();
904
+ init_telemetryEvent();
905
+ init_utils();
906
+ FRAMEWORK_EXTERNALS = [
907
+ "vue",
908
+ "vue/*",
909
+ "@vue/compiler-sfc",
910
+ "@vue/server-renderer",
911
+ "svelte",
912
+ "svelte/*",
913
+ "@angular/compiler",
914
+ "@angular/compiler-cli",
915
+ "@angular/core",
916
+ "@angular/common",
917
+ "@angular/platform-browser",
918
+ "@angular/platform-server"
919
+ ];
240
920
  });
241
921
 
242
922
  // src/cli/scripts/dev.ts
923
+ init_constants();
924
+ init_startupBanner();
243
925
  var {$: $2, env } = globalThis.Bun;
244
926
  import { existsSync as existsSync5 } from "fs";
245
927
  import { resolve as resolve3 } from "path";
246
928
 
247
- // src/constants.ts
248
- var ANSI_ESCAPE_LENGTH = 3;
249
- var ASCII_SPACE = 32;
250
- var BASE_36_RADIX = 36;
251
- var BYTES_PER_KILOBYTE = 1024;
252
- var CLI_ARGS_OFFSET = 3;
253
- var DEFAULT_PORT = 3000;
254
- var HOURS_IN_DAY = 24;
255
- var HOURS_IN_HALF_DAY = 12;
256
- var MAX_ERROR_LENGTH = 200;
257
- var MILLISECONDS_IN_A_SECOND = 1000;
258
- var MINUTES_IN_AN_HOUR = 60;
259
- var SECONDS_IN_A_MINUTE = 60;
260
- var MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
261
- var MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
262
- var SIGINT_EXIT_CODE = 130;
263
- var SIGTERM_EXIT_CODE = 143;
264
- var TIME_PRECISION = 2;
265
- var TWO_THIRDS = 2 / 3;
266
- var UNFOUND_INDEX = -1;
267
-
268
- // src/utils/getDurationString.ts
269
- var getDurationString = (duration) => {
270
- let durationString;
271
- if (duration < MILLISECONDS_IN_A_SECOND) {
272
- durationString = `${duration.toFixed(TIME_PRECISION)}ms`;
273
- } else if (duration < MILLISECONDS_IN_A_MINUTE) {
274
- durationString = `${(duration / MILLISECONDS_IN_A_SECOND).toFixed(TIME_PRECISION)}s`;
275
- } else {
276
- durationString = `${(duration / MILLISECONDS_IN_A_MINUTE).toFixed(TIME_PRECISION)}m`;
277
- }
278
- return durationString;
279
- };
280
-
281
- // src/utils/startupBanner.ts
282
- var MONTHS = [
283
- "Jan",
284
- "Feb",
285
- "Mar",
286
- "Apr",
287
- "May",
288
- "Jun",
289
- "Jul",
290
- "Aug",
291
- "Sep",
292
- "Oct",
293
- "Nov",
294
- "Dec"
295
- ];
296
- var formatTimestamp = () => {
297
- const now = new Date;
298
- const month = MONTHS[now.getMonth()];
299
- const day = now.getDate().toString().padStart(2, "0");
300
- let hours = now.getHours();
301
- const minutes = now.getMinutes().toString().padStart(2, "0");
302
- const seconds = now.getSeconds().toString().padStart(2, "0");
303
- const ampm = hours >= HOURS_IN_HALF_DAY ? "PM" : "AM";
304
- hours = hours % HOURS_IN_HALF_DAY || HOURS_IN_HALF_DAY;
305
- return `${month} ${day} ${hours}:${minutes}:${seconds} ${ampm}`;
306
- };
307
-
308
929
  // src/cli/interactive.ts
930
+ init_constants();
309
931
  import { openSync } from "fs";
310
932
  import { ReadStream } from "tty";
311
933
  var SHORTCUTS = {
@@ -565,249 +1187,10 @@ var createInteractiveHandler = (actions) => {
565
1187
  return { clearPrompt, dispose, showPrompt };
566
1188
  };
567
1189
 
568
- // src/cli/telemetryEvent.ts
569
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
570
- import { arch, platform } from "os";
571
- import { dirname, join as join2, parse } from "path";
572
-
573
- // src/cli/scripts/telemetry.ts
574
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
575
- import { homedir } from "os";
576
- import { join } from "path";
577
- var configDir = join(homedir(), ".absolutejs");
578
- var configPath = join(configDir, "telemetry.json");
579
- var getTelemetryConfig = () => {
580
- try {
581
- if (!existsSync(configPath))
582
- return null;
583
- const raw = readFileSync(configPath, "utf-8");
584
- const config = JSON.parse(raw);
585
- return config;
586
- } catch {
587
- return null;
588
- }
589
- };
590
- var saveTelemetryConfig = (config) => {
591
- mkdirSync(configDir, { recursive: true });
592
- writeFileSync(configPath, `${JSON.stringify(config, null, "\t")}
593
- `);
594
- };
595
- var enable = () => {
596
- const existing = getTelemetryConfig();
597
- const config = {
598
- anonymousId: existing?.anonymousId ?? crypto.randomUUID(),
599
- createdAt: existing?.createdAt ?? new Date().toISOString(),
600
- enabled: true
601
- };
602
- saveTelemetryConfig(config);
603
- console.log("Telemetry enabled.");
604
- console.log(`Anonymous ID: ${config.anonymousId}`);
605
- };
606
- var disable = () => {
607
- const existing = getTelemetryConfig();
608
- if (existing) {
609
- saveTelemetryConfig({ ...existing, enabled: false });
610
- }
611
- console.log("Telemetry disabled.");
612
- };
613
- var status = () => {
614
- const config = getTelemetryConfig();
615
- if (!config || !config.enabled) {
616
- console.log("Telemetry is disabled.");
617
- } else {
618
- console.log("Telemetry is enabled.");
619
- console.log(`Anonymous ID: ${config.anonymousId}`);
620
- }
621
- };
622
- var telemetry = (args) => {
623
- const [subcommand] = args;
624
- if (subcommand === "enable") {
625
- enable();
626
- return;
627
- }
628
- if (subcommand === "disable") {
629
- disable();
630
- return;
631
- }
632
- if (subcommand === "status") {
633
- status();
634
- return;
635
- }
636
- if (!subcommand) {
637
- status();
638
- console.log("");
639
- console.log("Usage: absolute telemetry <command>");
640
- console.log("Commands:");
641
- console.log(" enable Enable anonymous telemetry");
642
- console.log(" disable Disable telemetry");
643
- console.log(" status Show current telemetry status");
644
- return;
645
- }
646
- console.error(`Unknown telemetry command: ${subcommand}`);
647
- console.error("Usage: absolute telemetry <enable|disable|status>");
648
- process.exit(1);
649
- };
650
-
651
- // src/cli/telemetryEvent.ts
652
- var checkCandidate = (candidate) => {
653
- if (!existsSync2(candidate)) {
654
- return null;
655
- }
656
- const pkg = JSON.parse(readFileSync2(candidate, "utf-8"));
657
- if (pkg.name === "@absolutejs/absolute") {
658
- const ver = pkg.version;
659
- return ver;
660
- }
661
- return null;
662
- };
663
- var getVersion = () => {
664
- try {
665
- return findPackageVersion();
666
- } catch {
667
- return "unknown";
668
- }
669
- };
670
- var findPackageVersion = () => {
671
- let { dir } = import.meta;
672
- while (dir !== parse(dir).root) {
673
- const candidate = join2(dir, "package.json");
674
- const version = checkCandidate(candidate);
675
- if (version) {
676
- return version;
677
- }
678
- dir = dirname(dir);
679
- }
680
- return "unknown";
681
- };
682
- var sendTelemetryEvent = (event, payload) => {
683
- try {
684
- if (process.env.TELEMETRY_OFF === "1")
685
- return;
686
- const config = getTelemetryConfig();
687
- if (!config?.enabled)
688
- return;
689
- const body = {
690
- anonymousId: config.anonymousId,
691
- arch: arch(),
692
- bunVersion: Bun.version,
693
- event,
694
- os: platform(),
695
- payload,
696
- timestamp: new Date().toISOString(),
697
- version: getVersion()
698
- };
699
- fetch("https://absolutejs.com/api/telemetry", {
700
- body: JSON.stringify(body),
701
- headers: { "Content-Type": "application/json" },
702
- method: "POST"
703
- }).catch(() => {
704
- return;
705
- });
706
- } catch {}
707
- };
708
-
709
- // src/utils/loadConfig.ts
710
- import { resolve } from "path";
711
- var loadConfig = async (configPath2) => {
712
- const resolved = resolve(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts");
713
- const mod = await import(resolved);
714
- const config = mod.default ?? mod.config;
715
- if (!config) {
716
- throw new Error(`Config file "${resolved}" does not export a valid configuration.
717
- Expected: export default defineConfig({ ... })`);
718
- }
719
- return config;
720
- };
721
-
722
- // src/cli/utils.ts
723
- var {$ } = globalThis.Bun;
724
- import { execSync } from "child_process";
725
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
726
- import { resolve as resolve2 } from "path";
727
- var COMPOSE_PATH = "db/docker-compose.db.yml";
728
- var DEFAULT_SERVER_ENTRY = "src/backend/server.ts";
729
- var isWSLEnvironment = () => {
730
- try {
731
- const release = readFileSync3("/proc/version", "utf-8");
732
- return /microsoft|wsl/i.test(release);
733
- } catch {
734
- return false;
735
- }
736
- };
737
- var safeKill = (pid) => {
738
- try {
739
- process.kill(pid, "SIGTERM");
740
- } catch {}
741
- };
742
- var killStaleProcesses = (port) => {
743
- let output;
744
- try {
745
- output = execSync(`lsof -ti tcp:${port} -sTCP:LISTEN 2>/dev/null`, {
746
- encoding: "utf-8"
747
- }).trim();
748
- } catch {
749
- return;
750
- }
751
- if (!output) {
752
- return;
753
- }
754
- const pids = output.split(`
755
- `).map(Number).filter((pid) => pid !== process.pid && pid > 0);
756
- if (pids.length === 0) {
757
- return;
758
- }
759
- pids.forEach(safeKill);
760
- console.log(`\x1B[2m${formatTimestamp()}\x1B[0m \x1B[33m[cli]\x1B[0m \x1B[33mKilled ${pids.length} stale ${pids.length === 1 ? "process" : "processes"} on port ${port}.\x1B[0m`);
761
- };
762
- var printHelp = () => {
763
- console.log("");
764
- console.log("\x1B[1mShortcuts:\x1B[0m");
765
- console.log(" \x1B[36mr\x1B[0m / restart \u2014 Restart server");
766
- console.log(" \x1B[36mp\x1B[0m / pause \u2014 Pause/resume server");
767
- console.log(" \x1B[36mo\x1B[0m / open \u2014 Open in browser");
768
- console.log(" \x1B[36mc\x1B[0m / clear \u2014 Clear terminal");
769
- console.log(" \x1B[36mq\x1B[0m / quit \u2014 Graceful shutdown");
770
- console.log(" \x1B[36mh\x1B[0m / help \u2014 Show this help");
771
- console.log(" \x1B[36m$\x1B[0m \u2014 Run a shell command");
772
- console.log(" \x1B[36m\u2191\x1B[0m / \x1B[36m\u2193\x1B[0m \u2014 Command history");
773
- console.log("");
774
- };
775
- var printHint = () => {
776
- console.log("\x1B[90mpress h + enter to show shortcuts\x1B[0m");
777
- };
778
- var readDbScripts = async () => {
779
- const pkgPath = resolve2("package.json");
780
- if (!existsSync3(pkgPath))
781
- return null;
782
- const pkg = await Bun.file(pkgPath).json();
783
- const upCommand = pkg.scripts?.["db:up"];
784
- const downCommand = pkg.scripts?.["db:down"];
785
- if (!upCommand || !downCommand)
786
- return null;
787
- return { downCommand, upCommand };
788
- };
789
- var startDatabase = async (scripts) => {
790
- await timed("Starting database container...", async () => {
791
- const { exitCode } = await $`${{ raw: scripts.upCommand }}`.quiet().nothrow();
792
- if (exitCode !== 0)
793
- process.exit(exitCode);
794
- });
795
- };
796
- var stopDatabase = async (scripts) => {
797
- console.log(`
798
- Stopping database container...`);
799
- await $`${{ raw: scripts.downCommand }}`.quiet().nothrow();
800
- };
801
- var timed = async (label, task) => {
802
- process.stdout.write(label);
803
- const start = performance.now();
804
- await task();
805
- const duration = ((performance.now() - start) / MILLISECONDS_IN_A_SECOND).toFixed(2);
806
- process.stdout.write(` \x1B[90m${duration}s\x1B[0m
807
- `);
808
- };
809
-
810
1190
  // src/cli/scripts/dev.ts
1191
+ init_telemetryEvent();
1192
+ init_loadConfig();
1193
+ init_utils();
811
1194
  var cliTag = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
812
1195
  var confirmPrompt = (message, defaultYes = true) => new Promise((_resolve) => {
813
1196
  let selected = defaultYes;
@@ -1104,6 +1487,8 @@ var eslint = async (args) => {
1104
1487
  };
1105
1488
 
1106
1489
  // src/cli/scripts/info.ts
1490
+ init_constants();
1491
+ init_utils();
1107
1492
  import { execSync as execSync2 } from "child_process";
1108
1493
  import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1109
1494
  import { arch as arch2, cpus, platform as platform3, totalmem, version } from "os";
@@ -1242,6 +1627,7 @@ var info = () => {
1242
1627
  };
1243
1628
 
1244
1629
  // src/cli/cache.ts
1630
+ init_constants();
1245
1631
  import { mkdir } from "fs/promises";
1246
1632
  import { join as join4 } from "path";
1247
1633
  var {Glob } = globalThis.Bun;
@@ -1377,6 +1763,12 @@ var prettier = async (args) => {
1377
1763
  };
1378
1764
 
1379
1765
  // src/cli/scripts/start.ts
1766
+ init_constants();
1767
+ init_getDurationString();
1768
+ init_loadConfig();
1769
+ init_startupBanner();
1770
+ init_telemetryEvent();
1771
+ init_utils();
1380
1772
  var {env: env2 } = globalThis.Bun;
1381
1773
  import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
1382
1774
  import { basename, resolve as resolve5 } from "path";
@@ -1625,6 +2017,10 @@ var start = async (serverEntry, outdir, configPath2) => {
1625
2017
  };
1626
2018
 
1627
2019
  // src/cli/index.ts
2020
+ init_telemetry();
2021
+ init_telemetryEvent();
2022
+ init_constants();
2023
+ init_utils();
1628
2024
  var [command] = process.argv.slice(2);
1629
2025
  var args = process.argv.slice(CLI_ARGS_OFFSET);
1630
2026
  var parseNamedArg = (flag) => {
@@ -1664,6 +2060,15 @@ if (command === "dev") {
1664
2060
  } else if (command === "telemetry") {
1665
2061
  sendTelemetryEvent("cli:command", { command });
1666
2062
  telemetry(args);
2063
+ } else if (command === "compile") {
2064
+ sendTelemetryEvent("cli:command", { command });
2065
+ const outdir = parseNamedArg("--outdir");
2066
+ const outfile = parseNamedArg("--outfile");
2067
+ const configPath2 = parseNamedArg("--config");
2068
+ const positionalArgs = stripNamedArgs("--outdir", "--outfile", "--config");
2069
+ const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
2070
+ const { compile: compile2 } = await Promise.resolve().then(() => (init_compile(), exports_compile));
2071
+ await compile2(serverEntry, outdir, outfile, configPath2);
1667
2072
  } else if (command === "mkcert") {
1668
2073
  sendTelemetryEvent("cli:command", { command });
1669
2074
  const { setupMkcert: setupMkcert2 } = await Promise.resolve().then(() => (init_devCert(), exports_devCert));
@@ -1675,6 +2080,7 @@ if (command === "dev") {
1675
2080
  console.error("Commands:");
1676
2081
  console.error(" dev [entry] Start development server");
1677
2082
  console.error(" start [entry] [--outdir dir] Start production server");
2083
+ console.error(" compile [entry] [--outdir dir] [--outfile path] Compile standalone executable");
1678
2084
  console.error(" eslint Run ESLint (cached)");
1679
2085
  console.error(" info Print system info for bug reports");
1680
2086
  console.error(" prettier Run Prettier check (cached)");