@lark-apaas/fullstack-cli 1.1.62-alpha.20260824160408 → 1.1.62-alpha.20260824233147
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/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
|
-
import http from 'node:http';
|
|
5
4
|
import net from 'node:net';
|
|
6
5
|
import path from 'node:path';
|
|
7
6
|
import { spawn } from 'node:child_process';
|
|
@@ -17,7 +16,6 @@ const clientHost = process.env.CLIENT_DEV_HOST || '0.0.0.0';
|
|
|
17
16
|
const clientPort = Number(process.env.CLIENT_DEV_PORT || 8080);
|
|
18
17
|
const serverHost = process.env.SERVER_HOST || '0.0.0.0';
|
|
19
18
|
const serverPort = Number(process.env.SERVER_PORT || 3000);
|
|
20
|
-
const internalViteHost = process.env.MIAODA_VITE_INTERNAL_HOST || '127.0.0.1';
|
|
21
19
|
const vite8RuntimeEnabled = process.env.MIAODA_VITE8_RUNTIME_ENABLED === 'true';
|
|
22
20
|
const devBundleEnabled = process.env.MIAODA_VITE_DEV_BUNDLE_ENABLED === 'true';
|
|
23
21
|
if (devBundleEnabled && !vite8RuntimeEnabled) {
|
|
@@ -61,7 +59,8 @@ const vite8Bin = path.resolve(
|
|
|
61
59
|
process.env.MIAODA_VITE8_BIN ||
|
|
62
60
|
'/opt/miaoda/preview-runtime/node_modules/vite/bin/vite.js'
|
|
63
61
|
);
|
|
64
|
-
// pair_ready
|
|
62
|
+
// pair_ready 仅作为就绪观测事件,不再阻断 Vite 公共端口。
|
|
63
|
+
// 就绪口径由 MIAODA_PAIR_READY_GATE 控制:
|
|
65
64
|
// 'true'(默认)= 等 Vite + Nest 双就绪('vite-and-nest');
|
|
66
65
|
// 'false' = 只等 Vite 就绪('vite'),对齐 legacy 预览链路的放行语义。
|
|
67
66
|
// 关闭 gate 时 Nest 就绪仍被观测并照常发 nest_listen_ready 事件,
|
|
@@ -74,8 +73,6 @@ const runtimeStartedAtEpochMs = Date.now();
|
|
|
74
73
|
const startedAt = process.hrtime.bigint();
|
|
75
74
|
let stopping = false;
|
|
76
75
|
let child;
|
|
77
|
-
let proxyServer;
|
|
78
|
-
let pairReady = false;
|
|
79
76
|
|
|
80
77
|
function durationMs(since = startedAt) {
|
|
81
78
|
return Number(process.hrtime.bigint() - since) / 1_000_000;
|
|
@@ -202,26 +199,6 @@ function probeHost(host) {
|
|
|
202
199
|
return host.replace(/^\[|\]$/g, '');
|
|
203
200
|
}
|
|
204
201
|
|
|
205
|
-
async function reservePort() {
|
|
206
|
-
const configured = Number(process.env.MIAODA_VITE_INTERNAL_PORT || 0);
|
|
207
|
-
if (
|
|
208
|
-
Number.isSafeInteger(configured) &&
|
|
209
|
-
configured > 0 &&
|
|
210
|
-
configured <= 65_535
|
|
211
|
-
) {
|
|
212
|
-
return configured;
|
|
213
|
-
}
|
|
214
|
-
return await new Promise((resolve, reject) => {
|
|
215
|
-
const server = net.createServer();
|
|
216
|
-
server.once('error', reject);
|
|
217
|
-
server.listen(0, internalViteHost, () => {
|
|
218
|
-
const address = server.address();
|
|
219
|
-
const port = address && typeof address !== 'string' ? address.port : 0;
|
|
220
|
-
server.close(error => (error ? reject(error) : resolve(port)));
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
202
|
async function waitForPort(host, port, phase) {
|
|
226
203
|
const listenStartedAt = process.hrtime.bigint();
|
|
227
204
|
const deadline = Date.now() + 60_000;
|
|
@@ -250,93 +227,6 @@ async function waitForPort(host, port, phase) {
|
|
|
250
227
|
throw new Error(`MIAODA_WORKSPACE_SERVICE_READY_TIMEOUT: ${phase}`);
|
|
251
228
|
}
|
|
252
229
|
|
|
253
|
-
function rejectBeforePair(response) {
|
|
254
|
-
response.writeHead(503, {
|
|
255
|
-
'content-type': 'text/plain; charset=utf-8',
|
|
256
|
-
'cache-control': 'no-store',
|
|
257
|
-
'retry-after': '1',
|
|
258
|
-
connection: 'close',
|
|
259
|
-
});
|
|
260
|
-
response.end('preview services are starting');
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function proxyHttp(request, response, internalVitePort) {
|
|
264
|
-
if (!pairReady) {
|
|
265
|
-
rejectBeforePair(response);
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
const upstream = http.request(
|
|
269
|
-
{
|
|
270
|
-
host: internalViteHost,
|
|
271
|
-
port: internalVitePort,
|
|
272
|
-
method: request.method,
|
|
273
|
-
path: request.url,
|
|
274
|
-
headers: request.headers,
|
|
275
|
-
},
|
|
276
|
-
upstreamResponse => {
|
|
277
|
-
response.writeHead(
|
|
278
|
-
upstreamResponse.statusCode || 502,
|
|
279
|
-
upstreamResponse.statusMessage,
|
|
280
|
-
upstreamResponse.headers
|
|
281
|
-
);
|
|
282
|
-
upstreamResponse.pipe(response);
|
|
283
|
-
}
|
|
284
|
-
);
|
|
285
|
-
upstream.once('error', error => {
|
|
286
|
-
if (!response.headersSent) {
|
|
287
|
-
response.writeHead(502, {
|
|
288
|
-
'content-type': 'text/plain; charset=utf-8',
|
|
289
|
-
'cache-control': 'no-store',
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
response.end(`vite upstream unavailable: ${error.code || 'unknown'}`);
|
|
293
|
-
});
|
|
294
|
-
request.pipe(upstream);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function proxyUpgrade(request, socket, head, internalVitePort) {
|
|
298
|
-
if (!pairReady) {
|
|
299
|
-
socket.destroy();
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
const upstream = net.createConnection(
|
|
303
|
-
{ host: internalViteHost, port: internalVitePort },
|
|
304
|
-
() => {
|
|
305
|
-
const lines = [
|
|
306
|
-
`${request.method} ${request.url} HTTP/${request.httpVersion}`,
|
|
307
|
-
];
|
|
308
|
-
for (let index = 0; index < request.rawHeaders.length; index += 2) {
|
|
309
|
-
lines.push(
|
|
310
|
-
`${request.rawHeaders[index]}: ${request.rawHeaders[index + 1]}`
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
upstream.write(`${lines.join('\r\n')}\r\n\r\n`);
|
|
314
|
-
if (head.length > 0) upstream.write(head);
|
|
315
|
-
socket.pipe(upstream).pipe(socket);
|
|
316
|
-
}
|
|
317
|
-
);
|
|
318
|
-
upstream.once('error', () => socket.destroy());
|
|
319
|
-
socket.once('error', () => upstream.destroy());
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
async function listenPublicProxy(internalVitePort) {
|
|
323
|
-
proxyServer = http.createServer((request, response) =>
|
|
324
|
-
proxyHttp(request, response, internalVitePort)
|
|
325
|
-
);
|
|
326
|
-
proxyServer.on('upgrade', (request, socket, head) =>
|
|
327
|
-
proxyUpgrade(request, socket, head, internalVitePort)
|
|
328
|
-
);
|
|
329
|
-
await new Promise((resolve, reject) => {
|
|
330
|
-
proxyServer.once('error', reject);
|
|
331
|
-
proxyServer.listen(clientPort, clientHost, resolve);
|
|
332
|
-
});
|
|
333
|
-
emit('public_gate_listen', startedAt, {
|
|
334
|
-
host: clientHost,
|
|
335
|
-
port: clientPort,
|
|
336
|
-
readinessScope,
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
230
|
function terminate(signal = 'SIGTERM') {
|
|
341
231
|
if (!child?.pid) return;
|
|
342
232
|
try {
|
|
@@ -351,8 +241,6 @@ function terminate(signal = 'SIGTERM') {
|
|
|
351
241
|
async function close(signal) {
|
|
352
242
|
if (stopping) return;
|
|
353
243
|
stopping = true;
|
|
354
|
-
pairReady = false;
|
|
355
|
-
proxyServer?.close();
|
|
356
244
|
terminate(signal);
|
|
357
245
|
setTimeout(() => terminate('SIGKILL'), 1_000).unref();
|
|
358
246
|
}
|
|
@@ -377,8 +265,6 @@ if (
|
|
|
377
265
|
}
|
|
378
266
|
|
|
379
267
|
await waitForDependencies();
|
|
380
|
-
const internalVitePort = await reservePort();
|
|
381
|
-
await listenPublicProxy(internalVitePort);
|
|
382
268
|
if (nestStartMode === 'bundle-handoff') {
|
|
383
269
|
await waitForPort(serverHost, serverPort, 'nest_precedes_vite');
|
|
384
270
|
}
|
|
@@ -404,9 +290,9 @@ const viteCliArgs = [
|
|
|
404
290
|
'--config',
|
|
405
291
|
viteRuntimeConfig,
|
|
406
292
|
'--host',
|
|
407
|
-
|
|
293
|
+
clientHost,
|
|
408
294
|
'--port',
|
|
409
|
-
String(
|
|
295
|
+
String(clientPort),
|
|
410
296
|
'--strictPort',
|
|
411
297
|
];
|
|
412
298
|
if (devBundleEnabled) {
|
|
@@ -438,8 +324,6 @@ child = spawn(viteCommand, viteArgs, {
|
|
|
438
324
|
MIAODA_VITE_DEV_BUNDLE_ENABLED: String(devBundleEnabled),
|
|
439
325
|
MIAODA_VITE_DEPS_CACHE_ENABLED: viteDepsCacheEnabled,
|
|
440
326
|
MIAODA_VITE_EPHEMERAL_CACHE_DIR: viteEphemeralCacheDir,
|
|
441
|
-
MIAODA_VITE_INTERNAL_HOST: internalViteHost,
|
|
442
|
-
MIAODA_VITE_INTERNAL_PORT: String(internalVitePort),
|
|
443
327
|
},
|
|
444
328
|
});
|
|
445
329
|
emit('process_spawn', spawnStartedAt, {
|
|
@@ -454,59 +338,80 @@ emit('process_spawn', spawnStartedAt, {
|
|
|
454
338
|
viteRuntimeConfig,
|
|
455
339
|
viteEphemeralCacheDir:
|
|
456
340
|
viteDepsCacheEnabled === 'false' ? viteEphemeralCacheDir : undefined,
|
|
457
|
-
|
|
458
|
-
|
|
341
|
+
host: clientHost,
|
|
342
|
+
port: clientPort,
|
|
343
|
+
portMode: 'direct',
|
|
459
344
|
});
|
|
460
345
|
|
|
461
346
|
const exitPromise = new Promise((resolve, reject) => {
|
|
462
347
|
child.once('error', reject);
|
|
463
348
|
child.once('exit', (code, signal) => resolve({ code, signal }));
|
|
464
349
|
});
|
|
465
|
-
const viteListenWait = waitForPort(
|
|
466
|
-
internalViteHost,
|
|
467
|
-
internalVitePort,
|
|
468
|
-
'vite_listen_ready'
|
|
469
|
-
);
|
|
350
|
+
const viteListenWait = waitForPort(clientHost, clientPort, 'vite_listen_ready');
|
|
470
351
|
const viteRuntimeReadiness = [viteListenWait];
|
|
471
352
|
if (devBundleEnabled) {
|
|
472
353
|
viteRuntimeReadiness.push(waitForBundledDevDocument());
|
|
473
354
|
} else {
|
|
474
355
|
viteRuntimeReadiness.push(waitForWarmupReady());
|
|
475
356
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
...viteRuntimeReadiness,
|
|
480
|
-
waitForPort(serverHost, serverPort, 'nest_listen_ready'),
|
|
481
|
-
]);
|
|
482
|
-
} else {
|
|
483
|
-
// Gate 关闭时 pair_ready 只跟随 Vite;Nest 就绪在后台继续观测,
|
|
484
|
-
// nest_listen_ready 事件照常发出,失败不阻断预览放行。
|
|
485
|
-
waitForPort(serverHost, serverPort, 'nest_listen_ready').catch(() => {});
|
|
486
|
-
}
|
|
357
|
+
const nestReadiness = waitForPort(serverHost, serverPort, 'nest_listen_ready')
|
|
358
|
+
.then(() => ({ ready: true }))
|
|
359
|
+
.catch(error => ({ ready: false, error }));
|
|
487
360
|
await Promise.race([
|
|
488
|
-
|
|
361
|
+
Promise.all(viteRuntimeReadiness),
|
|
489
362
|
exitPromise.then(exit => {
|
|
490
363
|
throw new Error(
|
|
491
364
|
`MIAODA_WORKSPACE_VITE_EXITED_BEFORE_READY: code=${exit.code} signal=${exit.signal}`
|
|
492
365
|
);
|
|
493
366
|
}),
|
|
494
367
|
]);
|
|
495
|
-
pairReady = true;
|
|
496
|
-
emit('pair_ready', startedAt, {
|
|
497
|
-
host: clientHost,
|
|
498
|
-
port: clientPort,
|
|
499
|
-
internalViteHost,
|
|
500
|
-
internalVitePort,
|
|
501
|
-
serverHost,
|
|
502
|
-
serverPort,
|
|
503
|
-
readinessScope,
|
|
504
|
-
});
|
|
505
368
|
emit('startup', startedAt, {
|
|
506
369
|
pid: child.pid,
|
|
507
370
|
port: clientPort,
|
|
508
|
-
readinessScope,
|
|
371
|
+
readinessScope: 'vite',
|
|
372
|
+
pairReadinessScope: readinessScope,
|
|
373
|
+
portMode: 'direct',
|
|
509
374
|
});
|
|
375
|
+
const emitPairReady = () =>
|
|
376
|
+
emit('pair_ready', startedAt, {
|
|
377
|
+
host: clientHost,
|
|
378
|
+
port: clientPort,
|
|
379
|
+
portMode: 'direct',
|
|
380
|
+
serverHost,
|
|
381
|
+
serverPort,
|
|
382
|
+
readinessScope,
|
|
383
|
+
});
|
|
384
|
+
if (pairReadyGate) {
|
|
385
|
+
void nestReadiness.then(result => {
|
|
386
|
+
if (result.ready) {
|
|
387
|
+
emitPairReady();
|
|
388
|
+
} else if (!stopping) {
|
|
389
|
+
emit('pair_ready_failed', startedAt, {
|
|
390
|
+
serverHost,
|
|
391
|
+
serverPort,
|
|
392
|
+
readinessScope,
|
|
393
|
+
reason:
|
|
394
|
+
result.error instanceof Error
|
|
395
|
+
? result.error.message
|
|
396
|
+
: String(result.error),
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
} else {
|
|
401
|
+
emitPairReady();
|
|
402
|
+
void nestReadiness.then(result => {
|
|
403
|
+
if (!result.ready && !stopping) {
|
|
404
|
+
emit('nest_readiness_observation_failed', startedAt, {
|
|
405
|
+
serverHost,
|
|
406
|
+
serverPort,
|
|
407
|
+
reason:
|
|
408
|
+
result.error instanceof Error
|
|
409
|
+
? result.error.message
|
|
410
|
+
: String(result.error),
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
510
415
|
|
|
511
416
|
const exit = await exitPromise;
|
|
512
417
|
const wasStopping = stopping;
|