Merge pull request #101 from y574444354/fix/some-task
fix: resolve serve command hanging in Node.js runtime
This commit is contained in:
commit
ad7bc194b2
77
build.ts
77
build.ts
|
|
@ -243,7 +243,82 @@ if (typeof globalThis.Bun === "undefined") {
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
globalThis.Bun = { which, $, hash };
|
// Bun.serve polyfill — bridges Hono fetch handler to Node.js http.
|
||||||
|
// Returns a Promise that resolves with the actual port after 'listening' event.
|
||||||
|
const { createServer: _createHttpServer } = await import("http");
|
||||||
|
async function serve(options) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const server = _createHttpServer((req, res) => {
|
||||||
|
const host = req.headers.host || (options.hostname + ":" + (options.port || 0));
|
||||||
|
const url = new URL(req.url || "/", "http://" + host);
|
||||||
|
const headers = new Headers();
|
||||||
|
const rawHeaders = req.headers;
|
||||||
|
for (const key of Object.keys(rawHeaders)) {
|
||||||
|
const val = rawHeaders[key];
|
||||||
|
if (val != null) headers.set(key, Array.isArray(val) ? val.join(", ") : val);
|
||||||
|
}
|
||||||
|
const chunks = [];
|
||||||
|
req.on("data", (c) => chunks.push(c));
|
||||||
|
req.on("end", () => {
|
||||||
|
const hasBody = req.method !== "GET" && req.method !== "HEAD" && chunks.length > 0;
|
||||||
|
const request = new Request(url.toString(), {
|
||||||
|
method: req.method || "GET",
|
||||||
|
headers,
|
||||||
|
body: hasBody ? Buffer.concat(chunks) : undefined,
|
||||||
|
});
|
||||||
|
Promise.resolve(options.fetch(request))
|
||||||
|
.then((response) => {
|
||||||
|
res.statusCode = response.status;
|
||||||
|
response.headers.forEach((v, k) => res.setHeader(k, v));
|
||||||
|
if (response.body) {
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
const pump = () => reader.read().then(({ done, value }) => {
|
||||||
|
if (done) { res.end(); return; }
|
||||||
|
res.write(value);
|
||||||
|
pump();
|
||||||
|
}).catch(() => res.end());
|
||||||
|
pump();
|
||||||
|
} else {
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (!res.headersSent) res.statusCode = 500;
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
server.once("listening", () => {
|
||||||
|
const addr = server.address();
|
||||||
|
const actualPort = typeof addr === "object" && addr ? addr.port : options.port || 0;
|
||||||
|
resolve({
|
||||||
|
port: actualPort,
|
||||||
|
hostname: options.hostname,
|
||||||
|
stop: () => server.close(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
server.listen(options.port || 0, options.hostname || "0.0.0.0");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Bun.semver — delegate to npm semver package
|
||||||
|
const { createRequire: _createRequire } = await import("module");
|
||||||
|
const _nodeRequire = _createRequire(import.meta.url);
|
||||||
|
let _semver = null;
|
||||||
|
function getSemver() {
|
||||||
|
if (!_semver) _semver = _nodeRequire("semver");
|
||||||
|
return _semver;
|
||||||
|
}
|
||||||
|
const semverPolyfill = {
|
||||||
|
order: (a, b) => {
|
||||||
|
const r = getSemver().compare(a, b, { loose: true });
|
||||||
|
return r > 0 ? 1 : r < 0 ? -1 : 0;
|
||||||
|
},
|
||||||
|
satisfies: (version, range) => getSemver().satisfies(version, range, { loose: true }),
|
||||||
|
};
|
||||||
|
// Bun.version & env stubs
|
||||||
|
const version = "1.2.0";
|
||||||
|
const env = process.env;
|
||||||
|
globalThis.Bun = { which, $, hash, serve, semver: semverPolyfill, version, env };
|
||||||
}
|
}
|
||||||
import "./cli.js"
|
import "./cli.js"
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -5996,7 +5996,7 @@ async function run(): Promise<CommanderCommand> {
|
||||||
});
|
});
|
||||||
await sessionManager.init();
|
await sessionManager.init();
|
||||||
|
|
||||||
const server = startServer(config, sessionManager, eventBus);
|
const server = await startServer(config, sessionManager, eventBus);
|
||||||
const actualPort = server.port ?? config.port;
|
const actualPort = server.port ?? config.port;
|
||||||
printBanner(config, undefined, actualPort);
|
printBanner(config, undefined, actualPort);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,13 @@ export async function saveChildSpawnPrefix(): Promise<void> {
|
||||||
const { execPath, scriptArgs } = getChildSpawnArgs()
|
const { execPath, scriptArgs } = getChildSpawnArgs()
|
||||||
let defineArgs: string[] = []
|
let defineArgs: string[] = []
|
||||||
let featureArgs: string[] = []
|
let featureArgs: string[] = []
|
||||||
// Only pass --feature/define flags when running as a script (dev mode).
|
// Only pass --feature/define flags when running TypeScript source files.
|
||||||
// In compiled standalone executable mode scriptArgs is empty, and feature
|
// In compiled builds (dist/cli-node.js, standalone binary) feature flags are
|
||||||
// flags are already baked in at compile time — passing --feature to the
|
// already baked in at compile time — passing -d/--feature to the child process
|
||||||
// child process would cause "unknown option" errors.
|
// would cause "unknown option" errors in Node.js or standalone mode.
|
||||||
const isScriptMode = scriptArgs.length > 0
|
// Dev mode: .ts/.tsx source files need -d flags. Build: .js files don't.
|
||||||
if (isScriptMode) {
|
const isRunningSourceFile = scriptArgs.length > 0 && (scriptArgs[0].endsWith('.tsx') || scriptArgs[0].endsWith('.ts'))
|
||||||
|
if (isRunningSourceFile) {
|
||||||
try {
|
try {
|
||||||
const definesMod = await import('../../scripts/defines.js') as { getMacroDefines: () => Record<string, string>; DEFAULT_BUILD_FEATURES: readonly string[] }
|
const definesMod = await import('../../scripts/defines.js') as { getMacroDefines: () => Record<string, string>; DEFAULT_BUILD_FEATURES: readonly string[] }
|
||||||
const defines = definesMod.getMacroDefines()
|
const defines = definesMod.getMacroDefines()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user