swift-rust 0.2.0 → 1.0.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/bin/build.mjs +372 -0
- package/bin/swift-rust.js +14 -0
- package/package.json +6 -6
package/bin/build.mjs
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import {
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
readdirSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
cpSync,
|
|
11
|
+
openSync,
|
|
12
|
+
unlinkSync,
|
|
13
|
+
} from "node:fs";
|
|
14
|
+
import { join, resolve, dirname, sep } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
const APP_DIR_CANDIDATES = [resolve(cwd, "app", "src"), resolve(cwd, "app")];
|
|
19
|
+
const APP_DIR = APP_DIR_CANDIDATES.find((p) => existsSync(p)) ?? resolve(cwd, "app");
|
|
20
|
+
const PUBLIC_DIR = resolve(cwd, "public");
|
|
21
|
+
const OUT_DIR = resolve(cwd, ".vercel", "output");
|
|
22
|
+
const STATIC_DIR = join(OUT_DIR, "static");
|
|
23
|
+
const RUNTIME_DIR = resolve(fileURLToPath(import.meta.url), "..", "runtime");
|
|
24
|
+
|
|
25
|
+
const PORT_START = parseInt(process.env.SWIFT_RUST_BUILD_PORT || "47321", 10);
|
|
26
|
+
const HOST = "127.0.0.1";
|
|
27
|
+
let PORT = PORT_START;
|
|
28
|
+
const ROUTE_TIMEOUT_MS = 30_000;
|
|
29
|
+
const HEALTH_TIMEOUT_MS = 30_000;
|
|
30
|
+
|
|
31
|
+
const CATCH_PARAM = /^\[\.{3}([^\]]+)\]$/;
|
|
32
|
+
const NAMED_PARAM = /^\[([^\]]+)\]$/;
|
|
33
|
+
const PAGE_EXTENSIONS = ["page.tsx", "page.ts", "page.jsx", "page.js"];
|
|
34
|
+
const NOT_FOUND_FILES = ["not-found.tsx", "not-found.ts", "not-found.jsx", "not-found.js"];
|
|
35
|
+
|
|
36
|
+
const c = {
|
|
37
|
+
reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
|
|
38
|
+
red: "\x1b[31m", green: "\x1b[32m", yellow: "\x1b[33m",
|
|
39
|
+
cyan: "\x1b[36m", gray: "\x1b[90m",
|
|
40
|
+
};
|
|
41
|
+
const useColor = process.stdout.isTTY !== false && !process.env.NO_COLOR;
|
|
42
|
+
const paint = (color, s) => (useColor ? `${c[color]}${s}${c.reset}` : s);
|
|
43
|
+
const fmtMs = (ms) => (ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(2)}s`);
|
|
44
|
+
|
|
45
|
+
let activeLogFile = null;
|
|
46
|
+
|
|
47
|
+
function findPageFile(dir) {
|
|
48
|
+
for (const ext of PAGE_EXTENSIONS) {
|
|
49
|
+
const p = join(dir, ext);
|
|
50
|
+
if (existsSync(p)) return p;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function discoverPages(dir, base = "") {
|
|
56
|
+
const pages = [];
|
|
57
|
+
if (!existsSync(dir)) return pages;
|
|
58
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
59
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
60
|
+
const full = join(dir, entry.name);
|
|
61
|
+
if (entry.isDirectory()) {
|
|
62
|
+
const catchAll = entry.name.match(CATCH_PARAM);
|
|
63
|
+
if (catchAll) {
|
|
64
|
+
const pageFile = findPageFile(full);
|
|
65
|
+
if (pageFile) {
|
|
66
|
+
pages.push({ type: "catchall", dir: full, file: pageFile, base, paramName: catchAll[1] });
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const named = entry.name.match(NAMED_PARAM);
|
|
71
|
+
if (named) {
|
|
72
|
+
const pageFile = findPageFile(full);
|
|
73
|
+
if (pageFile) {
|
|
74
|
+
pages.push({ type: "dynamic", dir: full, file: pageFile, base, paramName: named[1] });
|
|
75
|
+
}
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
pages.push(...discoverPages(full, base + "/" + entry.name));
|
|
79
|
+
} else if (PAGE_EXTENSIONS.includes(entry.name)) {
|
|
80
|
+
pages.push({ type: "static", file: full, route: base || "/" });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return pages;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function findNotFoundFile(dir) {
|
|
87
|
+
for (const name of NOT_FOUND_FILES) {
|
|
88
|
+
const p = join(dir, name);
|
|
89
|
+
if (existsSync(p)) return p;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function enumerateParams(page) {
|
|
95
|
+
for (const ext of PAGE_EXTENSIONS) {
|
|
96
|
+
const p = join(page.dir, ext);
|
|
97
|
+
if (!existsSync(p)) continue;
|
|
98
|
+
try {
|
|
99
|
+
const mod = await import(`${p}?t=${Date.now()}`);
|
|
100
|
+
if (typeof mod.generateStaticParams === "function") {
|
|
101
|
+
return await mod.generateStaticParams();
|
|
102
|
+
}
|
|
103
|
+
} catch {}
|
|
104
|
+
}
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function routesFromParams(base, paramName, params) {
|
|
109
|
+
return params
|
|
110
|
+
.map((p) => {
|
|
111
|
+
const v = p[paramName];
|
|
112
|
+
if (v == null) return null;
|
|
113
|
+
return base + "/" + (Array.isArray(v) ? v.join("/") : String(v));
|
|
114
|
+
})
|
|
115
|
+
.filter(Boolean);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function findBun() {
|
|
119
|
+
if (process.env.SWIFT_RUST_RUNTIME) return process.env.SWIFT_RUST_RUNTIME;
|
|
120
|
+
if (process.versions?.bun) return process.execPath;
|
|
121
|
+
const candidates = [
|
|
122
|
+
process.env.BUN_INSTALL ? join(process.env.BUN_INSTALL, "bin", "bun") : null,
|
|
123
|
+
join(process.env.HOME || "", ".bun", "bin", "bun"),
|
|
124
|
+
"/usr/local/bin/bun",
|
|
125
|
+
"/opt/homebrew/bin/bun",
|
|
126
|
+
].filter(Boolean);
|
|
127
|
+
for (const p of candidates) {
|
|
128
|
+
if (existsSync(p)) return p;
|
|
129
|
+
}
|
|
130
|
+
return process.execPath;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function findFreePort(start) {
|
|
134
|
+
const net = await import("node:net");
|
|
135
|
+
for (let p = start; p < start + 50; p++) {
|
|
136
|
+
const ok = await new Promise((resolve) => {
|
|
137
|
+
const sock = net.createServer();
|
|
138
|
+
sock.once("error", () => resolve(false));
|
|
139
|
+
sock.once("listening", () => sock.close(() => resolve(true)));
|
|
140
|
+
sock.listen(p, HOST);
|
|
141
|
+
});
|
|
142
|
+
if (ok) return p;
|
|
143
|
+
}
|
|
144
|
+
throw new Error(`no free port in range ${start}..${start + 50}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function startDevServer(port, logFile) {
|
|
148
|
+
const devServer = resolve(fileURLToPath(import.meta.url), "..", "dev-server.mjs");
|
|
149
|
+
const runtime = findBun();
|
|
150
|
+
const stdio = logFile
|
|
151
|
+
? ["ignore", openSync(logFile, "w"), "inherit"]
|
|
152
|
+
: ["ignore", "inherit", "inherit"];
|
|
153
|
+
const proc = spawn(runtime, [devServer, "--port", String(port), "--hostname", HOST], {
|
|
154
|
+
stdio,
|
|
155
|
+
env: { ...process.env, NO_COLOR: "1", SWIFT_RUST_BUILD: "1" },
|
|
156
|
+
cwd,
|
|
157
|
+
});
|
|
158
|
+
proc.on("error", (e) => process.stderr.write(` ${paint("red", "dev server spawn error:")} ${e.message}\n`));
|
|
159
|
+
return proc;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function waitForServer(timeoutMs = HEALTH_TIMEOUT_MS) {
|
|
163
|
+
const start = Date.now();
|
|
164
|
+
const url = `http://${HOST}:${PORT}/_swift-rust/health`;
|
|
165
|
+
while (Date.now() - start < timeoutMs) {
|
|
166
|
+
try {
|
|
167
|
+
const res = await fetch(url);
|
|
168
|
+
if (res.ok) return;
|
|
169
|
+
} catch {}
|
|
170
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
171
|
+
}
|
|
172
|
+
throw new Error(`dev server did not become ready at ${url} within ${timeoutMs}ms`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function fetchRoute(pathname, timeoutMs = ROUTE_TIMEOUT_MS) {
|
|
176
|
+
const controller = new AbortController();
|
|
177
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
178
|
+
try {
|
|
179
|
+
const res = await fetch(`http://${HOST}:${PORT}${pathname}`, {
|
|
180
|
+
signal: controller.signal,
|
|
181
|
+
redirect: "manual",
|
|
182
|
+
});
|
|
183
|
+
return { status: res.status, body: await res.text() };
|
|
184
|
+
} finally {
|
|
185
|
+
clearTimeout(timer);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function tailDevLog(lines = 40) {
|
|
190
|
+
if (!activeLogFile || !existsSync(activeLogFile)) return [];
|
|
191
|
+
try {
|
|
192
|
+
const all = readFileSync(activeLogFile, "utf8").split("\n");
|
|
193
|
+
return all.slice(-lines);
|
|
194
|
+
} catch {
|
|
195
|
+
return [];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function stripHmrScript(html) {
|
|
200
|
+
return html.replace(/\s*<script src="\/_swift-rust\/hmr-client\.js"[^>]*>\s*<\/script>/g, "");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function writeStaticFile(outDir, pathname, html) {
|
|
204
|
+
const rel = pathname === "/" ? "index.html" : `${pathname.replace(/^\//, "")}/index.html`;
|
|
205
|
+
const outPath = join(outDir, rel);
|
|
206
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
207
|
+
writeFileSync(outPath, html);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Writes a literal file (e.g. 404.html) at static/<name>, NOT static/<name>/index.html.
|
|
211
|
+
function writeRawFile(outDir, name, contents) {
|
|
212
|
+
const outPath = join(outDir, name);
|
|
213
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
214
|
+
writeFileSync(outPath, contents);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function writeConfigJson(outDir, _hasPublic) {
|
|
218
|
+
// Build Output API v3 config. Only schema-valid fields here — unknown
|
|
219
|
+
// top-level fields or route properties are rejected at "Deploying outputs".
|
|
220
|
+
const config = {
|
|
221
|
+
version: 3,
|
|
222
|
+
routes: [
|
|
223
|
+
{ src: "/_swift-rust/static/(.*)", headers: { "Cache-Control": "public, max-age=31536000, immutable" } },
|
|
224
|
+
{ src: "/fonts/(.*)", headers: { "Cache-Control": "public, max-age=31536000, immutable" } },
|
|
225
|
+
{ handle: "filesystem" },
|
|
226
|
+
{ src: "^(.*)$", status: 404, dest: "/404.html" },
|
|
227
|
+
],
|
|
228
|
+
overrides: {
|
|
229
|
+
"404.html": { path: "404", contentType: "text/html; charset=utf-8" },
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
writeFileSync(join(outDir, "config.json"), `${JSON.stringify(config, null, 2)}\n`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function main() {
|
|
236
|
+
const start = Date.now();
|
|
237
|
+
process.stdout.write(`\n ${paint("cyan", "▲")} ${paint("bold", "swift-rust build")} ${paint("dim", "→ .vercel/output (BOA v3)")}\n`);
|
|
238
|
+
|
|
239
|
+
if (!existsSync(APP_DIR)) {
|
|
240
|
+
process.stderr.write(`\n ${paint("red", "✗")} No app/ directory found in ${cwd}\n\n`);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
process.stdout.write(` ${paint("dim", "app: ")} ${paint("cyan", APP_DIR.replace(cwd + sep, ""))}\n`);
|
|
245
|
+
process.stdout.write(` ${paint("dim", "out: ")} ${paint("cyan", ".vercel/output")}\n\n`);
|
|
246
|
+
|
|
247
|
+
rmSync(OUT_DIR, { recursive: true, force: true });
|
|
248
|
+
mkdirSync(STATIC_DIR, { recursive: true });
|
|
249
|
+
|
|
250
|
+
const pages = discoverPages(APP_DIR);
|
|
251
|
+
const staticRoutes = pages.filter((p) => p.type === "static").map((p) => p.route);
|
|
252
|
+
const catchalls = pages.filter((p) => p.type === "catchall");
|
|
253
|
+
const dynamics = pages.filter((p) => p.type === "dynamic");
|
|
254
|
+
process.stdout.write(` ${paint("dim", "•")} static routes: ${paint("bold", String(staticRoutes.length))}\n`);
|
|
255
|
+
|
|
256
|
+
for (const ca of catchalls) {
|
|
257
|
+
const params = await enumerateParams(ca);
|
|
258
|
+
const routes = routesFromParams(ca.base, ca.paramName, params);
|
|
259
|
+
for (const r of routes) staticRoutes.push(r);
|
|
260
|
+
process.stdout.write(` ${paint("dim", "•")} catch-all ${paint("cyan", ca.base + "/[...]")}: ${paint("bold", String(routes.length))}\n`);
|
|
261
|
+
}
|
|
262
|
+
for (const dyn of dynamics) {
|
|
263
|
+
const params = await enumerateParams(dyn);
|
|
264
|
+
if (params.length === 0) {
|
|
265
|
+
process.stdout.write(` ${paint("dim", "•")} dynamic ${paint("cyan", dyn.base + "/[" + dyn.paramName + "]")}: ${paint("yellow", "needs serverless function (skipped for v0.1.0)")}\n`);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const routes = routesFromParams(dyn.base, dyn.paramName, params);
|
|
269
|
+
for (const r of routes) staticRoutes.push(r);
|
|
270
|
+
process.stdout.write(` ${paint("dim", "•")} dynamic ${paint("cyan", dyn.base + "/[" + dyn.paramName + "]")}: ${paint("bold", String(routes.length))}\n`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const allRoutes = [...new Set(staticRoutes)].sort();
|
|
274
|
+
process.stdout.write(` ${paint("dim", "•")} total: ${paint("bold", String(allRoutes.length))}\n\n`);
|
|
275
|
+
|
|
276
|
+
process.stdout.write(` ${paint("dim", "starting dev server on " + HOST + ":" + PORT_START + "…")}\n`);
|
|
277
|
+
PORT = await findFreePort(PORT_START);
|
|
278
|
+
process.stdout.write(` ${paint("dim", "using port " + PORT + "\n")}\n`);
|
|
279
|
+
activeLogFile = process.env.SWIFT_RUST_BUILD_LOG || "/tmp/swift-rust-build-dev.log";
|
|
280
|
+
try { unlinkSync(activeLogFile); } catch {}
|
|
281
|
+
const proc = startDevServer(PORT, activeLogFile);
|
|
282
|
+
let okCount = 0;
|
|
283
|
+
let skipCount = 0;
|
|
284
|
+
let failCount = 0;
|
|
285
|
+
try {
|
|
286
|
+
await waitForServer();
|
|
287
|
+
process.stdout.write(` ${paint("green", "✓")} server ready\n\n`);
|
|
288
|
+
|
|
289
|
+
for (const route of allRoutes) {
|
|
290
|
+
try {
|
|
291
|
+
const { status, body } = await fetchRoute(route);
|
|
292
|
+
if (status === 200) {
|
|
293
|
+
const cleaned = stripHmrScript(body);
|
|
294
|
+
writeStaticFile(STATIC_DIR, route, cleaned);
|
|
295
|
+
okCount++;
|
|
296
|
+
process.stdout.write(` ${paint("green", "✓")} ${route}\n`);
|
|
297
|
+
} else if (status === 404) {
|
|
298
|
+
skipCount++;
|
|
299
|
+
process.stdout.write(` ${paint("dim", "○")} ${route} ${paint("dim", "(404, skipped)")}\n`);
|
|
300
|
+
} else {
|
|
301
|
+
failCount++;
|
|
302
|
+
const snippet = body.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, 160);
|
|
303
|
+
process.stdout.write(` ${paint("yellow", "!")} ${route} ${paint("dim", `(${status})`)}\n`);
|
|
304
|
+
if (snippet) process.stdout.write(` ${paint("dim", snippet)}\n`);
|
|
305
|
+
}
|
|
306
|
+
} catch (e) {
|
|
307
|
+
failCount++;
|
|
308
|
+
process.stdout.write(` ${paint("red", "✗")} ${route} ${paint("dim", e.name === "AbortError" ? "timeout" : e.message)}\n`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (failCount > 0) {
|
|
313
|
+
const tail = tailDevLog(30);
|
|
314
|
+
if (tail.length) {
|
|
315
|
+
process.stdout.write(`\n ${paint("dim", "dev server tail:")}\n`);
|
|
316
|
+
for (const line of tail) process.stdout.write(` ${paint("dim", line)}\n`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const notFoundFile = findNotFoundFile(APP_DIR);
|
|
321
|
+
if (notFoundFile) {
|
|
322
|
+
try {
|
|
323
|
+
const { status, body } = await fetchRoute("/_not_found_");
|
|
324
|
+
if (status === 200 || status === 404) {
|
|
325
|
+
const html = stripHmrScript(body).replace(/<title>[^<]*<\/title>/, "<title>404 · Swift Rust</title>");
|
|
326
|
+
writeRawFile(STATIC_DIR, "404.html", html);
|
|
327
|
+
process.stdout.write(`\n ${paint("green", "✓")} 404.html\n`);
|
|
328
|
+
}
|
|
329
|
+
} catch (e) {
|
|
330
|
+
process.stdout.write(`\n ${paint("yellow", "!")} 404.html ${paint("dim", "fallback to minimal page")}\n`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (!existsSync(join(STATIC_DIR, "404.html"))) {
|
|
334
|
+
writeRawFile(STATIC_DIR, "404.html", `<!DOCTYPE html>
|
|
335
|
+
<html lang="en"><head><meta charset="utf-8" /><title>404 · Swift Rust</title></head>
|
|
336
|
+
<body><main style="font-family:system-ui;padding:4rem;text-align:center">
|
|
337
|
+
<h1>404</h1><p>This page could not be found.</p><a href="/">← Back home</a>
|
|
338
|
+
</main></body></html>`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (existsSync(RUNTIME_DIR)) {
|
|
342
|
+
cpSync(RUNTIME_DIR, join(STATIC_DIR, "_swift-rust"), { recursive: true });
|
|
343
|
+
}
|
|
344
|
+
const hasPublic = existsSync(PUBLIC_DIR);
|
|
345
|
+
if (hasPublic) {
|
|
346
|
+
cpSync(PUBLIC_DIR, STATIC_DIR, { recursive: true });
|
|
347
|
+
process.stdout.write(` ${paint("green", "✓")} copied public/\n`);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
writeConfigJson(OUT_DIR, hasPublic);
|
|
351
|
+
|
|
352
|
+
const total = Date.now() - start;
|
|
353
|
+
const outRel = OUT_DIR.startsWith(cwd + sep) ? OUT_DIR.slice(cwd.length + 1) : OUT_DIR;
|
|
354
|
+
const skippedPart = skipCount > 0 ? paint("dim", `${skipCount} skipped`) : "";
|
|
355
|
+
const failedPart = failCount > 0 ? paint("yellow", `${failCount} failed`) : paint("dim", "0 failed");
|
|
356
|
+
const summary = ` ${paint("green", "✓")} ${okCount} ok ${skippedPart} ${failedPart}\n`;
|
|
357
|
+
process.stdout.write(`\n ${paint("bold", "done")} ${paint("dim", "in " + fmtMs(total))}\n`);
|
|
358
|
+
process.stdout.write(summary);
|
|
359
|
+
process.stdout.write(` ${paint("dim", "output: " + outRel)}\n\n`);
|
|
360
|
+
|
|
361
|
+
const treatFailuresAsWarning = okCount > 0;
|
|
362
|
+
process.exit(treatFailuresAsWarning || failCount === 0 ? 0 : 1);
|
|
363
|
+
} finally {
|
|
364
|
+
try { proc.kill("SIGTERM"); } catch {}
|
|
365
|
+
setTimeout(() => { try { proc.kill("SIGKILL"); } catch {} process.exit(0); }, 2000).unref();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
main().catch((e) => {
|
|
370
|
+
process.stderr.write(`\n ${paint("red", "✗")} ${e?.stack || e?.message || String(e)}\n\n`);
|
|
371
|
+
process.exit(1);
|
|
372
|
+
});
|
package/bin/swift-rust.js
CHANGED
|
@@ -41,6 +41,20 @@ if (cmd === "dev") {
|
|
|
41
41
|
process.exit(code);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
if (cmd === "build") {
|
|
45
|
+
const buildScript = join(here, "build.mjs");
|
|
46
|
+
const runtime = findBun();
|
|
47
|
+
const child = spawn(runtime, [buildScript, ...process.argv.slice(3)], {
|
|
48
|
+
stdio: "inherit",
|
|
49
|
+
env: process.env,
|
|
50
|
+
});
|
|
51
|
+
const code = await new Promise((r) => {
|
|
52
|
+
child.on("exit", (c) => r(c ?? 1));
|
|
53
|
+
child.on("error", () => r(1));
|
|
54
|
+
});
|
|
55
|
+
process.exit(code);
|
|
56
|
+
}
|
|
57
|
+
|
|
44
58
|
function getBinaryName() {
|
|
45
59
|
if (process.platform === "win32") return "swift-rust.exe";
|
|
46
60
|
return "swift-rust";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swift-rust",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "The full-stack React framework powered with Rust + Bun. TSX-first, Rust rendering, 10x faster than Next.js, single binary deploy.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://swift-rust.dev",
|
|
@@ -87,11 +87,11 @@
|
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@dotenvx/dotenvx": "^1.0.0",
|
|
90
|
-
"@swift-rust/env": "
|
|
91
|
-
"@swift-rust/font": "
|
|
92
|
-
"@swift-rust/image": "
|
|
93
|
-
"@swift-rust/pdf": "
|
|
94
|
-
"@swift-rust/video": "
|
|
90
|
+
"@swift-rust/env": "workspace:*",
|
|
91
|
+
"@swift-rust/font": "workspace:*",
|
|
92
|
+
"@swift-rust/image": "workspace:*",
|
|
93
|
+
"@swift-rust/pdf": "workspace:*",
|
|
94
|
+
"@swift-rust/video": "workspace:*",
|
|
95
95
|
"react": "^19.0.0",
|
|
96
96
|
"react-dom": "^19.0.0"
|
|
97
97
|
},
|