@lark-apaas/fullstack-cli 1.1.64-alpha.20260901065806 → 1.1.64-alpha.20260901212526
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.js +1734 -1122
- package/package.json +1 -1
- package/templates/scripts/dev.js +59 -9
- package/templates/scripts/server-handoff-runtime.mjs +554 -159
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import fs31 from "fs";
|
|
3
|
+
import path27 from "path";
|
|
4
4
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
5
5
|
import { config as dotenvConfig } from "dotenv";
|
|
6
6
|
|
|
@@ -8261,532 +8261,640 @@ async function preUploadStatic(options) {
|
|
|
8261
8261
|
}
|
|
8262
8262
|
|
|
8263
8263
|
// src/commands/build/server-startup-bundle.handler.ts
|
|
8264
|
-
import
|
|
8264
|
+
import fs30 from "fs";
|
|
8265
8265
|
import http from "http";
|
|
8266
8266
|
import net from "net";
|
|
8267
8267
|
import os3 from "os";
|
|
8268
|
-
import
|
|
8268
|
+
import path26 from "path";
|
|
8269
8269
|
import { builtinModules, createRequire as createRequire3 } from "module";
|
|
8270
8270
|
import { spawn as spawn2 } from "child_process";
|
|
8271
8271
|
import { createHash, randomUUID } from "crypto";
|
|
8272
8272
|
import { build } from "esbuild";
|
|
8273
8273
|
import { parse } from "acorn";
|
|
8274
8274
|
import { ancestor as walkAncestor, simple as walkSimple } from "acorn-walk";
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8275
|
+
|
|
8276
|
+
// src/commands/build/server-startup-module-guard.ts
|
|
8277
|
+
import fs29 from "fs";
|
|
8278
|
+
import path25 from "path";
|
|
8279
|
+
var STARTUP_BUNDLE_FILE = "payload/server.bundle.cjs";
|
|
8280
|
+
var STARTUP_ENTRY_FILE = "payload/server.start.cjs";
|
|
8281
|
+
var MODULE_GUARD_FILE = "module-resolution-guard.cjs";
|
|
8282
|
+
var MODULE_GUARD_SOURCE = `'use strict';
|
|
8283
|
+
const fs = require('node:fs');
|
|
8284
|
+
const path = require('node:path');
|
|
8285
|
+
const Module = require('node:module');
|
|
8286
|
+
|
|
8287
|
+
const payloadRoot = fs.realpathSync(__dirname);
|
|
8288
|
+
const payloadRequire = Module.createRequire(path.join(payloadRoot, 'package.json'));
|
|
8289
|
+
const builtins = new Set([
|
|
8290
|
+
...Module.builtinModules,
|
|
8291
|
+
...Module.builtinModules.map(name => 'node:' + name),
|
|
8292
|
+
]);
|
|
8293
|
+
const originalResolveFilename = Module._resolveFilename;
|
|
8294
|
+
|
|
8295
|
+
function isInside(root, candidate) {
|
|
8296
|
+
const relative = path.relative(root, candidate);
|
|
8297
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
8298
|
+
}
|
|
8299
|
+
|
|
8300
|
+
function isBareSpecifier(request) {
|
|
8301
|
+
return typeof request === 'string' &&
|
|
8302
|
+
!request.startsWith('.') &&
|
|
8303
|
+
!path.isAbsolute(request) &&
|
|
8304
|
+
!request.startsWith('file:');
|
|
8305
|
+
}
|
|
8306
|
+
|
|
8307
|
+
function assertPayloadResolution(request, resolved) {
|
|
8308
|
+
if (builtins.has(resolved)) return resolved;
|
|
8309
|
+
const realResolved = typeof resolved === 'string' && fs.existsSync(resolved)
|
|
8310
|
+
? fs.realpathSync(resolved)
|
|
8311
|
+
: resolved;
|
|
8312
|
+
if (typeof realResolved !== 'string' || !isInside(payloadRoot, realResolved)) {
|
|
8313
|
+
const error = new Error('MIAODA_STARTUP_MODULE_OUTSIDE_PAYLOAD:' + request);
|
|
8314
|
+
error.code = 'MIAODA_STARTUP_MODULE_OUTSIDE_PAYLOAD';
|
|
8315
|
+
throw error;
|
|
8316
|
+
}
|
|
8317
|
+
return realResolved;
|
|
8318
|
+
}
|
|
8319
|
+
|
|
8320
|
+
Module._resolveFilename = function miaodaResolveFilename(request, parent, isMain, options) {
|
|
8321
|
+
if (builtins.has(request)) {
|
|
8322
|
+
return originalResolveFilename.call(this, request, parent, isMain, options);
|
|
8323
|
+
}
|
|
8324
|
+
const parentFilename = parent && typeof parent.filename === 'string'
|
|
8325
|
+
? parent.filename
|
|
8326
|
+
: '';
|
|
8327
|
+
if (!isInside(payloadRoot, parentFilename)) {
|
|
8328
|
+
if (typeof request === 'string' && path.isAbsolute(request)) {
|
|
8329
|
+
return assertPayloadResolution(
|
|
8330
|
+
request,
|
|
8331
|
+
originalResolveFilename.call(this, request, parent, isMain, options)
|
|
8332
|
+
);
|
|
8333
|
+
}
|
|
8334
|
+
if (!isBareSpecifier(request)) {
|
|
8335
|
+
return assertPayloadResolution(request, undefined);
|
|
8336
|
+
}
|
|
8337
|
+
return assertPayloadResolution(request, payloadRequire.resolve(request));
|
|
8338
|
+
}
|
|
8339
|
+
return assertPayloadResolution(
|
|
8340
|
+
request,
|
|
8341
|
+
originalResolveFilename.call(this, request, parent, isMain, options)
|
|
8342
|
+
);
|
|
8343
|
+
};
|
|
8344
|
+
`;
|
|
8345
|
+
function writeServerStartupLauncher(payloadRoot) {
|
|
8346
|
+
fs29.writeFileSync(
|
|
8347
|
+
path25.join(payloadRoot, MODULE_GUARD_FILE),
|
|
8348
|
+
MODULE_GUARD_SOURCE,
|
|
8349
|
+
{
|
|
8350
|
+
mode: 420
|
|
8351
|
+
}
|
|
8352
|
+
);
|
|
8353
|
+
fs29.writeFileSync(
|
|
8354
|
+
path25.join(payloadRoot, path25.basename(STARTUP_ENTRY_FILE)),
|
|
8355
|
+
`require('./${MODULE_GUARD_FILE}');
|
|
8356
|
+
require('./${path25.basename(STARTUP_BUNDLE_FILE)}');
|
|
8357
|
+
`,
|
|
8358
|
+
{ mode: 420 }
|
|
8359
|
+
);
|
|
8360
|
+
}
|
|
8361
|
+
|
|
8362
|
+
// src/commands/build/server-startup-bundle.handler.ts
|
|
8363
|
+
var SCHEMA_VERSION = 4;
|
|
8364
|
+
var BUILDER_POLICY_VERSION = 4;
|
|
8365
|
+
var ARTIFACT_FORMAT = "hybrid-bundle-dynamic-islands";
|
|
8366
|
+
var DEPENDENCY_MODE = "dynamic-islands";
|
|
8367
|
+
var MAX_ISLAND_DISCOVERY_PASSES = 128;
|
|
8368
|
+
var MAX_GENERATION_FILES = 5e4;
|
|
8369
|
+
var MAX_GENERATION_BYTES = 256 * 1024 * 1024;
|
|
8370
|
+
var MAX_GENERATION_FILE_BYTES = 64 * 1024 * 1024;
|
|
8371
|
+
var MAX_FILE_INDEX_BYTES = 16 * 1024 * 1024;
|
|
8372
|
+
var MAX_MANIFEST_BYTES = 1024 * 1024;
|
|
8373
|
+
var MAX_PROBE_BYTES = 64 * 1024;
|
|
8374
|
+
var MAX_DEPENDENCY_METADATA_BYTES = 64 * 1024 * 1024;
|
|
8375
|
+
var MAX_PACKAGE_MANIFEST_BYTES = 1024 * 1024;
|
|
8376
|
+
var MAX_READINESS_RESPONSE_BYTES = 64 * 1024;
|
|
8282
8377
|
var BUILTINS = /* @__PURE__ */ new Set([
|
|
8283
8378
|
...builtinModules,
|
|
8284
8379
|
...builtinModules.map((name) => `node:${name}`)
|
|
8285
8380
|
]);
|
|
8286
|
-
var
|
|
8287
|
-
var RUNTIME_ASSET_READ_METHODS = /* @__PURE__ */ new Set([
|
|
8288
|
-
"access",
|
|
8289
|
-
"accessSync",
|
|
8290
|
-
"createReadStream",
|
|
8291
|
-
"open",
|
|
8292
|
-
"openSync",
|
|
8293
|
-
"readFile",
|
|
8294
|
-
"readFileSync",
|
|
8295
|
-
"stat",
|
|
8296
|
-
"statSync"
|
|
8297
|
-
]);
|
|
8298
|
-
var SOURCE_HASH_IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
8381
|
+
var ROOT_SOURCE_HASH_IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
8299
8382
|
".git",
|
|
8300
8383
|
".miaoda-cache",
|
|
8301
8384
|
".turbo",
|
|
8302
8385
|
"coverage",
|
|
8303
8386
|
"dist",
|
|
8304
|
-
"logs"
|
|
8305
|
-
"node_modules"
|
|
8387
|
+
"logs"
|
|
8306
8388
|
]);
|
|
8307
|
-
var AUDITED_FRAMEWORK_DYNAMIC_LOADER_HASHES = {
|
|
8308
|
-
"/@nestjs/common/utils/load-package.util.js": [
|
|
8309
|
-
"8fc26b273fe5499285e25355b4368fe8e1527ae217ede53144219c17cf1aa721"
|
|
8310
|
-
],
|
|
8311
|
-
"/@nestjs/core/helpers/optional-require.js": [
|
|
8312
|
-
"c8a109dab1b2461e866fe04b8be5988ccc199a2239c730abc05fc28c0f85d7f2"
|
|
8313
|
-
],
|
|
8314
|
-
"/@nestjs/core/helpers/load-adapter.js": [
|
|
8315
|
-
"7970867a441f356a2e257a12e43dbb8022b58631b3076f298058abb46270009a"
|
|
8316
|
-
],
|
|
8317
|
-
"/express/lib/view.js": [
|
|
8318
|
-
"ec627880c1b43aee5887164ac2e9c58f01e4ee8086e23a829eddf1af3858c021"
|
|
8319
|
-
],
|
|
8320
|
-
"/require-in-the-middle/index.js": [
|
|
8321
|
-
"721b78e7afebc91a75ecc8b8d9a166775ef03fd8f96e7cbcad1b46f8b4e74a07"
|
|
8322
|
-
],
|
|
8323
|
-
"/@opentelemetry/instrumentation/build/src/platform/node/instrumentation.js": ["098033348a2d1750e5722457fa56ccbe51c7df1aafe58f960ec20566a9a8b310"],
|
|
8324
|
-
"/@lark-apaas/nestjs-capability/dist/index.cjs": [
|
|
8325
|
-
"9a6aea944995f46adf9733daaf13ec6cd0d46decab044e2548e0f0b1ba54cde2"
|
|
8326
|
-
],
|
|
8327
|
-
"/@lark-apaas/fullstack-nestjs-core/dist/index.cjs": [
|
|
8328
|
-
"76fd8e2b4eaf762346e22919b229d81bc6c3848f1e7968e8e63e9493ca6127d9"
|
|
8329
|
-
],
|
|
8330
|
-
"/pino/lib/transport.js": [
|
|
8331
|
-
"c4857be63a0392312c9010fc222e7216fee0c216ef8dbcf133c61158528ab091"
|
|
8332
|
-
],
|
|
8333
|
-
"/hbs/lib/hbs.js": [
|
|
8334
|
-
"fdab192a37993e8643e5ce27698fc7e1138b0033e487270f77fd865fa00feab0"
|
|
8335
|
-
],
|
|
8336
|
-
"/handlebars/lib/index.js": [
|
|
8337
|
-
"76f96bd806c6b48987dd811de149be3d8c296eb440f9c91a3b8cad9fb2f9030a"
|
|
8338
|
-
]
|
|
8339
|
-
};
|
|
8340
|
-
var AUDITED_RUNTIME_FS_READER_HASHES = {
|
|
8341
|
-
"/@grpc/grpc-js/build/src/tls-helpers.js": [
|
|
8342
|
-
"9c3b00e23fca5e7996212778f151301eb202337da931f384fb1b60eb9d13f6c4"
|
|
8343
|
-
],
|
|
8344
|
-
"/@grpc/proto-loader/build/src/util.js": [
|
|
8345
|
-
"72101d764f31ece6d3c22cc6674c32ab3fb1f4975756d9ee4e39f3b155fb6f03"
|
|
8346
|
-
],
|
|
8347
|
-
"/@lark-apaas/fullstack-nestjs-core/dist/index.cjs": [
|
|
8348
|
-
"76fd8e2b4eaf762346e22919b229d81bc6c3848f1e7968e8e63e9493ca6127d9"
|
|
8349
|
-
],
|
|
8350
|
-
"/@lark-apaas/nestjs-capability/dist/index.cjs": [
|
|
8351
|
-
"9a6aea944995f46adf9733daaf13ec6cd0d46decab044e2548e0f0b1ba54cde2"
|
|
8352
|
-
],
|
|
8353
|
-
"/@nestjs/config/dist/config.module.js": [
|
|
8354
|
-
"6d907e32437d1c922d5dcd17e3a0daf052d7d95a56adfc2972965e47cca31ff4"
|
|
8355
|
-
],
|
|
8356
|
-
"/@nestjs/config/dist/config.service.js": [
|
|
8357
|
-
"a6febcebd600bf8468ffa15e736266407404b5c281f2b1ddcec466245e889a72"
|
|
8358
|
-
],
|
|
8359
|
-
"/dotenv/lib/main.js": [
|
|
8360
|
-
"0d55d84f7ae79c6752b9b6ffd6f083c32a72d1d6ca2e3606f9161ffa441c3f52"
|
|
8361
|
-
],
|
|
8362
|
-
"/express/lib/view.js": [
|
|
8363
|
-
"ec627880c1b43aee5887164ac2e9c58f01e4ee8086e23a829eddf1af3858c021"
|
|
8364
|
-
],
|
|
8365
|
-
"/send/index.js": [
|
|
8366
|
-
"614d9bdd1944cc51663785b0e74c245296830f014a6f8c6c48cdc6a26b56c01e"
|
|
8367
|
-
],
|
|
8368
|
-
"/@opentelemetry/otlp-exporter-base/build/esm/configuration/otlp-node-http-env-configuration.js": ["d4397f98b3cea799130dd26fee05ce2f27811e5643244e9d59264d218ac9f364"],
|
|
8369
|
-
"/@opentelemetry/otlp-grpc-exporter-base/build/src/configuration/otlp-grpc-env-configuration.js": ["901d2348bf46babe99c7b13cf1aea5bf76f44e5ab45c6f5f1aefbed525938696"],
|
|
8370
|
-
"/@opentelemetry/resources/build/src/detectors/platform/node/machine-id/getMachineId-bsd.js": [
|
|
8371
|
-
"e4cef35e2b61c3471154414de9b9b3dc21b0778e8e728c56ae0f1cdf2558b8ed",
|
|
8372
|
-
"e56af724ce673fe33e83aec425822f5211cd368afcba0d04be41f47da728115f"
|
|
8373
|
-
],
|
|
8374
|
-
"/@opentelemetry/resources/build/src/detectors/platform/node/machine-id/getMachineId-linux.js": [
|
|
8375
|
-
"d62c5a539558002a63a05093f4f3a0820a35ebf95d51966725fb92110beefc95",
|
|
8376
|
-
"631b352f8994ff3cccf365473127b1dfa97f95bb0d0c70e3ce1137c744b92830"
|
|
8377
|
-
],
|
|
8378
|
-
"/@protobufjs/fetch/index.js": [
|
|
8379
|
-
"5e8c1d65ee1857327528c5b3fc807c3647324f3097a6cb9358f9e2c328c143fe"
|
|
8380
|
-
],
|
|
8381
|
-
"/axios/dist/node/axios.cjs": [
|
|
8382
|
-
"241146620c67551291fef242d9ab9fd9b28f1e0e14ae311e7db759d36942b574"
|
|
8383
|
-
],
|
|
8384
|
-
"/chokidar/index.js": [
|
|
8385
|
-
"18ce2effe87d6379aa1d3756e5694c57c72cf97804056d688499a2bffcec66fd"
|
|
8386
|
-
],
|
|
8387
|
-
"/chokidar/lib/fsevents-handler.js": [
|
|
8388
|
-
"c2e15baebf066bf8531cbf82a324631a40b218d073274429edb50b4bdbbb0265"
|
|
8389
|
-
],
|
|
8390
|
-
"/chokidar/lib/nodefs-handler.js": [
|
|
8391
|
-
"60be035e7ea64858a0144230d5073b18a69f3b0eefba62a9b032c6d2f179d807"
|
|
8392
|
-
],
|
|
8393
|
-
"/form-data/lib/form_data.js": [
|
|
8394
|
-
"c63c99e10e2c3f46fa990787d7dc4a4f65ea90211c422e19626fecb3d767c41d"
|
|
8395
|
-
],
|
|
8396
|
-
"/handlebars/lib/index.js": [
|
|
8397
|
-
"76f96bd806c6b48987dd811de149be3d8c296eb440f9c91a3b8cad9fb2f9030a"
|
|
8398
|
-
],
|
|
8399
|
-
"/hbs/lib/hbs.js": [
|
|
8400
|
-
"fdab192a37993e8643e5ce27698fc7e1138b0033e487270f77fd865fa00feab0"
|
|
8401
|
-
],
|
|
8402
|
-
"/mime/mime.js": [
|
|
8403
|
-
"a121a0b9e780e9ae349a26227a0d25c33ebac2d52a85aae5affa84ba0f53f16c"
|
|
8404
|
-
],
|
|
8405
|
-
"/mkdirp/index.js": [
|
|
8406
|
-
"df33312136061eee26701a34ca4f9be043b9675d359a115503dc2df909106432"
|
|
8407
|
-
],
|
|
8408
|
-
"/postgres/cjs/src/index.js": [
|
|
8409
|
-
"d8fea1a5311c47e65004646bc81f57305ac64d48f99004a5b3ca27bcfc6babf8"
|
|
8410
|
-
],
|
|
8411
|
-
"/protobufjs/src/root.js": [
|
|
8412
|
-
"1f610f79137dff45ce2ec4e0f742ae43f26b296f2518f4ba41e0a497af5ad624"
|
|
8413
|
-
],
|
|
8414
|
-
"/sonic-boom/index.js": [
|
|
8415
|
-
"cd3f77b5b75366df3f0a9c27dc18c4f8c47478a7cc982a2bbdc70bfded3c1221"
|
|
8416
|
-
],
|
|
8417
|
-
"/undici/lib/mock/snapshot-recorder.js": [
|
|
8418
|
-
"9bf63c8b207b6f6e7fe4400b32d8322cfc185735d6ecfbd87a2691a8fba82922"
|
|
8419
|
-
]
|
|
8420
|
-
};
|
|
8421
8389
|
var probeIdentities = /* @__PURE__ */ new WeakMap();
|
|
8422
8390
|
function sha256(contents) {
|
|
8423
8391
|
return createHash("sha256").update(contents).digest("hex");
|
|
8424
8392
|
}
|
|
8393
|
+
function stableJson(value) {
|
|
8394
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
8395
|
+
if (value && typeof value === "object") {
|
|
8396
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
8397
|
+
}
|
|
8398
|
+
return JSON.stringify(value);
|
|
8399
|
+
}
|
|
8400
|
+
function isCapabilityReadinessPayload(contents) {
|
|
8401
|
+
if (contents.length > MAX_READINESS_RESPONSE_BYTES) return false;
|
|
8402
|
+
try {
|
|
8403
|
+
const payload = JSON.parse(contents.toString("utf8"));
|
|
8404
|
+
return Boolean(
|
|
8405
|
+
payload && typeof payload === "object" && payload.status_code === "0" && payload.data && typeof payload.data === "object" && !Array.isArray(payload.data) && Array.isArray(payload.data.capabilities)
|
|
8406
|
+
);
|
|
8407
|
+
} catch {
|
|
8408
|
+
return false;
|
|
8409
|
+
}
|
|
8410
|
+
}
|
|
8425
8411
|
function isInside(root, candidate) {
|
|
8426
|
-
const relative =
|
|
8427
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
8412
|
+
const relative = path26.relative(root, candidate);
|
|
8413
|
+
return relative === "" || !relative.startsWith("..") && !path26.isAbsolute(relative);
|
|
8414
|
+
}
|
|
8415
|
+
function toPosixRelative(root, file) {
|
|
8416
|
+
return path26.relative(root, file).split(path26.sep).join("/");
|
|
8428
8417
|
}
|
|
8429
8418
|
function assertNoSymlinkComponents(root, candidate, message) {
|
|
8430
|
-
|
|
8431
|
-
if (!isInside(root, candidate))
|
|
8432
|
-
throw new Error(`${message}: path escaped root`);
|
|
8419
|
+
if (!isInside(root, candidate)) throw new Error(`${message}: escaped root`);
|
|
8433
8420
|
let current = root;
|
|
8434
|
-
for (const segment of relative.split(
|
|
8435
|
-
|
|
8436
|
-
|
|
8421
|
+
for (const segment of path26.relative(root, candidate).split(path26.sep)) {
|
|
8422
|
+
if (!segment) continue;
|
|
8423
|
+
current = path26.join(current, segment);
|
|
8424
|
+
if (fs30.existsSync(current) && fs30.lstatSync(current).isSymbolicLink()) {
|
|
8437
8425
|
throw new Error(message);
|
|
8438
8426
|
}
|
|
8439
8427
|
}
|
|
8440
8428
|
}
|
|
8441
|
-
function
|
|
8442
|
-
if (!
|
|
8443
|
-
for (const entry of
|
|
8444
|
-
if (
|
|
8445
|
-
|
|
8429
|
+
function walkSourceFiles(root, directory, output) {
|
|
8430
|
+
if (!fs30.existsSync(directory)) return;
|
|
8431
|
+
for (const entry of fs30.readdirSync(directory, { withFileTypes: true })) {
|
|
8432
|
+
if (entry.name === "node_modules" || directory === root && ROOT_SOURCE_HASH_IGNORED_DIRECTORIES.has(entry.name)) {
|
|
8433
|
+
continue;
|
|
8434
|
+
}
|
|
8435
|
+
const candidate = path26.join(directory, entry.name);
|
|
8446
8436
|
if (entry.isSymbolicLink()) {
|
|
8447
8437
|
throw new Error(
|
|
8448
|
-
`source symlink is unsupported: ${
|
|
8438
|
+
`source symlink is unsupported: ${toPosixRelative(root, candidate)}`
|
|
8449
8439
|
);
|
|
8450
8440
|
}
|
|
8451
|
-
if (entry.isDirectory())
|
|
8441
|
+
if (entry.isDirectory()) walkSourceFiles(root, candidate, output);
|
|
8452
8442
|
else if (entry.isFile()) output.push(candidate);
|
|
8443
|
+
else {
|
|
8444
|
+
throw new Error(
|
|
8445
|
+
`source special file is unsupported: ${toPosixRelative(root, candidate)}`
|
|
8446
|
+
);
|
|
8447
|
+
}
|
|
8453
8448
|
}
|
|
8454
8449
|
}
|
|
8455
8450
|
function workspaceSourceSha256(projectRoot) {
|
|
8456
8451
|
const files = [];
|
|
8457
|
-
|
|
8452
|
+
walkSourceFiles(projectRoot, projectRoot, files);
|
|
8458
8453
|
const hash = createHash("sha256");
|
|
8459
8454
|
for (const file of files.sort()) {
|
|
8460
|
-
hash.update(
|
|
8455
|
+
hash.update(toPosixRelative(projectRoot, file));
|
|
8461
8456
|
hash.update("\0");
|
|
8462
|
-
hash
|
|
8457
|
+
updateHashFromFile(hash, file);
|
|
8463
8458
|
hash.update("\0");
|
|
8464
8459
|
}
|
|
8465
8460
|
return hash.digest("hex");
|
|
8466
8461
|
}
|
|
8467
|
-
function
|
|
8468
|
-
const
|
|
8469
|
-
const
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8462
|
+
function updateHashFromFile(hash, file) {
|
|
8463
|
+
const descriptor = fs30.openSync(file, "r");
|
|
8464
|
+
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
8465
|
+
try {
|
|
8466
|
+
const before = fs30.fstatSync(descriptor);
|
|
8467
|
+
let position = 0;
|
|
8468
|
+
while (position < before.size) {
|
|
8469
|
+
const bytesRead = fs30.readSync(
|
|
8470
|
+
descriptor,
|
|
8471
|
+
buffer,
|
|
8472
|
+
0,
|
|
8473
|
+
Math.min(buffer.length, before.size - position),
|
|
8474
|
+
position
|
|
8475
|
+
);
|
|
8476
|
+
if (bytesRead === 0) break;
|
|
8477
|
+
hash.update(buffer.subarray(0, bytesRead));
|
|
8478
|
+
position += bytesRead;
|
|
8479
|
+
}
|
|
8480
|
+
const after = fs30.fstatSync(descriptor);
|
|
8481
|
+
if (position !== before.size || after.size !== before.size || after.mtimeMs !== before.mtimeMs) {
|
|
8482
|
+
throw new Error(`source changed while hashing: ${file}`);
|
|
8483
|
+
}
|
|
8484
|
+
} finally {
|
|
8485
|
+
fs30.closeSync(descriptor);
|
|
8479
8486
|
}
|
|
8480
|
-
|
|
8487
|
+
}
|
|
8488
|
+
function runtimeIdentity() {
|
|
8489
|
+
const report = process.report?.getReport();
|
|
8490
|
+
const header = report?.header;
|
|
8491
|
+
return {
|
|
8492
|
+
nodeVersion: process.versions.node,
|
|
8493
|
+
nodeModulesAbi: process.versions.modules,
|
|
8494
|
+
platform: process.platform,
|
|
8495
|
+
arch: process.arch,
|
|
8496
|
+
libc: typeof header?.glibcVersionRuntime === "string" ? `glibc-${header.glibcVersionRuntime}` : process.platform === "linux" ? "linux-unknown-libc" : "not-applicable"
|
|
8497
|
+
};
|
|
8481
8498
|
}
|
|
8482
8499
|
function resolveEntry(projectRoot, requested) {
|
|
8483
|
-
const entry =
|
|
8500
|
+
const entry = path26.resolve(projectRoot, requested);
|
|
8484
8501
|
if (!isInside(projectRoot, entry))
|
|
8485
8502
|
throw new Error("compiled entry escaped project root");
|
|
8486
|
-
if (!
|
|
8503
|
+
if (!fs30.existsSync(entry))
|
|
8487
8504
|
throw new Error(`compiled entry is not a file: ${entry}`);
|
|
8488
|
-
if (
|
|
8505
|
+
if (fs30.lstatSync(entry).isSymbolicLink()) {
|
|
8489
8506
|
throw new Error("compiled entry symlink is unsupported");
|
|
8490
8507
|
}
|
|
8491
|
-
const realEntry =
|
|
8508
|
+
const realEntry = fs30.realpathSync(entry);
|
|
8492
8509
|
if (!isInside(projectRoot, realEntry))
|
|
8493
8510
|
throw new Error("compiled entry escaped project root");
|
|
8494
|
-
if (!
|
|
8511
|
+
if (!fs30.statSync(realEntry).isFile())
|
|
8495
8512
|
throw new Error(`compiled entry is not a file: ${entry}`);
|
|
8496
8513
|
return realEntry;
|
|
8497
8514
|
}
|
|
8498
|
-
function
|
|
8499
|
-
const
|
|
8500
|
-
|
|
8501
|
-
)
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8515
|
+
function resolveNestTsconfig(projectRoot) {
|
|
8516
|
+
const nestConfigFile = path26.join(projectRoot, "nest-cli.json");
|
|
8517
|
+
let configured;
|
|
8518
|
+
if (fs30.existsSync(nestConfigFile)) {
|
|
8519
|
+
const nestConfig = JSON.parse(fs30.readFileSync(nestConfigFile, "utf8"));
|
|
8520
|
+
configured = nestConfig.compilerOptions?.tsConfigPath;
|
|
8521
|
+
if (configured !== void 0 && typeof configured !== "string") {
|
|
8522
|
+
throw new Error("nest-cli.json compilerOptions.tsConfigPath is invalid");
|
|
8523
|
+
}
|
|
8524
|
+
}
|
|
8525
|
+
const candidates = typeof configured === "string" ? [configured] : ["tsconfig.build.json", "tsconfig.node.json", "tsconfig.json"];
|
|
8526
|
+
const selected = candidates.map((candidate) => path26.resolve(projectRoot, candidate)).find((candidate) => fs30.existsSync(candidate));
|
|
8527
|
+
if (!selected) {
|
|
8528
|
+
throw new Error(`Nest TypeScript config missing: ${candidates.join(", ")}`);
|
|
8529
|
+
}
|
|
8530
|
+
if (!isInside(projectRoot, selected))
|
|
8531
|
+
throw new Error("Nest TypeScript config escaped project root");
|
|
8532
|
+
if (fs30.lstatSync(selected).isSymbolicLink())
|
|
8533
|
+
throw new Error("Nest TypeScript config symlink is unsupported");
|
|
8534
|
+
const realConfig = fs30.realpathSync(selected);
|
|
8535
|
+
if (!isInside(projectRoot, realConfig) || !fs30.statSync(realConfig).isFile()) {
|
|
8536
|
+
throw new Error("Nest TypeScript config escaped project root");
|
|
8537
|
+
}
|
|
8538
|
+
return realConfig;
|
|
8539
|
+
}
|
|
8540
|
+
function resolveNestCli(projectRoot) {
|
|
8541
|
+
const projectRequire = createRequire3(path26.join(projectRoot, "package.json"));
|
|
8542
|
+
try {
|
|
8543
|
+
return projectRequire.resolve("@nestjs/cli/bin/nest.js");
|
|
8544
|
+
} catch (directError) {
|
|
8545
|
+
try {
|
|
8546
|
+
const packageFile = projectRequire.resolve("@nestjs/cli/package.json");
|
|
8547
|
+
const packageJson = JSON.parse(fs30.readFileSync(packageFile, "utf8"));
|
|
8548
|
+
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.nest;
|
|
8549
|
+
if (!relativeBin) throw new Error("@nestjs/cli has no nest binary");
|
|
8550
|
+
const cliFile = path26.resolve(path26.dirname(packageFile), relativeBin);
|
|
8551
|
+
if (!fs30.statSync(cliFile).isFile())
|
|
8552
|
+
throw new Error("@nestjs/cli nest binary is not a file");
|
|
8553
|
+
return cliFile;
|
|
8554
|
+
} catch (packageError) {
|
|
8555
|
+
throw new Error(
|
|
8556
|
+
`project @nestjs/cli is unavailable: ${packageError instanceof Error ? packageError.message : String(packageError)}; direct=${directError instanceof Error ? directError.message : String(directError)}`
|
|
8518
8557
|
);
|
|
8519
8558
|
}
|
|
8520
|
-
}
|
|
8559
|
+
}
|
|
8521
8560
|
}
|
|
8522
|
-
function
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
8561
|
+
function readLinuxProcessIdentity(pid) {
|
|
8562
|
+
if (process.platform !== "linux") return void 0;
|
|
8563
|
+
try {
|
|
8564
|
+
const stat = fs30.readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
8565
|
+
const commandEnd = stat.lastIndexOf(")");
|
|
8566
|
+
if (commandEnd < 0) return void 0;
|
|
8567
|
+
const fields = stat.slice(commandEnd + 1).trim().split(/\s+/);
|
|
8568
|
+
return /^\d+$/.test(fields[19] || "") && /^\d+$/.test(fields[2] || "") ? { processStartTicks: fields[19], processGroupId: Number(fields[2]) } : void 0;
|
|
8569
|
+
} catch {
|
|
8570
|
+
return void 0;
|
|
8571
|
+
}
|
|
8572
|
+
}
|
|
8573
|
+
function registerProbe(child) {
|
|
8574
|
+
if (!child.pid) throw new Error("isolated process pid unavailable");
|
|
8575
|
+
const identity = readLinuxProcessIdentity(child.pid);
|
|
8576
|
+
if (process.platform === "linux" && !identity) {
|
|
8577
|
+
child.kill("SIGKILL");
|
|
8578
|
+
throw new Error("isolated process birth identity unavailable");
|
|
8579
|
+
}
|
|
8580
|
+
probeIdentities.set(child, {
|
|
8581
|
+
pid: child.pid,
|
|
8582
|
+
processStartTicks: identity?.processStartTicks
|
|
8529
8583
|
});
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
return candidate.expressions?.some(isCreateRequireReference) ?? false;
|
|
8540
|
-
}
|
|
8541
|
-
return false;
|
|
8542
|
-
};
|
|
8543
|
-
walkSimple(ast, {
|
|
8544
|
-
CallExpression(node) {
|
|
8545
|
-
const isCreateRequire = isCreateRequireReference(node.callee);
|
|
8546
|
-
const isRequire = node.callee.type === "Identifier" && (node.callee.name === "require" || node.callee.name === "__require") || node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && node.callee.object.name === "module" && (node.callee.property.type === "Identifier" && node.callee.property.name === "require" || node.callee.property.type === "Literal" && node.callee.property.value === "require");
|
|
8547
|
-
const isRequireResolve = node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && (node.callee.object.name === "require" || node.callee.object.name === "__require") && node.callee.property.type === "Identifier" && node.callee.property.name === "resolve";
|
|
8548
|
-
if (isCreateRequire) {
|
|
8549
|
-
replacements.push({
|
|
8550
|
-
start: node.start,
|
|
8551
|
-
end: node.end,
|
|
8552
|
-
kind: "create-require"
|
|
8553
|
-
});
|
|
8554
|
-
} else if ((isRequire || isRequireResolve) && (node.arguments[0]?.type !== "Literal" || typeof node.arguments[0].value !== "string")) {
|
|
8555
|
-
replacements.push({
|
|
8556
|
-
start: node.start,
|
|
8557
|
-
end: node.end,
|
|
8558
|
-
kind: "dynamic-load"
|
|
8559
|
-
});
|
|
8560
|
-
}
|
|
8561
|
-
},
|
|
8562
|
-
ImportExpression(node) {
|
|
8563
|
-
if (node.source.type !== "Literal" || typeof node.source.value !== "string") {
|
|
8564
|
-
replacements.push({
|
|
8565
|
-
start: node.start,
|
|
8566
|
-
end: node.end,
|
|
8567
|
-
kind: "dynamic-load"
|
|
8568
|
-
});
|
|
8569
|
-
}
|
|
8570
|
-
},
|
|
8571
|
-
MemberExpression(node) {
|
|
8572
|
-
if (node.object.type !== "Identifier" || node.object.name !== "require" && node.object.name !== "__require") {
|
|
8573
|
-
return;
|
|
8584
|
+
}
|
|
8585
|
+
function probeGroupRunning(child) {
|
|
8586
|
+
const registered = probeIdentities.get(child);
|
|
8587
|
+
if (!registered) return false;
|
|
8588
|
+
if (process.platform === "linux") {
|
|
8589
|
+
const current = readLinuxProcessIdentity(registered.pid);
|
|
8590
|
+
if (current) {
|
|
8591
|
+
if (current.processStartTicks !== registered.processStartTicks || current.processGroupId !== registered.pid) {
|
|
8592
|
+
return false;
|
|
8574
8593
|
}
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
});
|
|
8582
|
-
} else if (property === "main") {
|
|
8583
|
-
replacements.push({
|
|
8584
|
-
start: node.start,
|
|
8585
|
-
end: node.end,
|
|
8586
|
-
kind: "require-main"
|
|
8587
|
-
});
|
|
8588
|
-
} else if (property === "extensions") {
|
|
8589
|
-
replacements.push({
|
|
8590
|
-
start: node.start,
|
|
8591
|
-
end: node.end,
|
|
8592
|
-
kind: "require-extensions"
|
|
8593
|
-
});
|
|
8594
|
+
} else {
|
|
8595
|
+
try {
|
|
8596
|
+
process.kill(registered.pid, 0);
|
|
8597
|
+
return false;
|
|
8598
|
+
} catch (error) {
|
|
8599
|
+
if (error.code !== "ESRCH") return false;
|
|
8594
8600
|
}
|
|
8595
8601
|
}
|
|
8596
|
-
}
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
const value = replacement.kind === "create-require" ? disabledCreateRequire : replacement.kind === "dynamic-load" ? unavailable : replacement.kind === "require-main" ? "undefined" : "Object.create(null)";
|
|
8604
|
-
output = `${output.slice(0, replacement.start)}${value}${output.slice(
|
|
8605
|
-
replacement.end
|
|
8606
|
-
)}`;
|
|
8607
|
-
}
|
|
8608
|
-
return output.replace(
|
|
8609
|
-
/\bcreateRequire\b/g,
|
|
8610
|
-
"__miaoda_disabled_create_require"
|
|
8611
|
-
);
|
|
8602
|
+
}
|
|
8603
|
+
try {
|
|
8604
|
+
process.kill(-registered.pid, 0);
|
|
8605
|
+
return true;
|
|
8606
|
+
} catch (error) {
|
|
8607
|
+
return error.code === "EPERM";
|
|
8608
|
+
}
|
|
8612
8609
|
}
|
|
8613
|
-
function
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
const source = fs29.readFileSync(args.path, "utf8");
|
|
8620
|
-
if (!normalized.includes("/node_modules/") || !Object.entries(AUDITED_FRAMEWORK_DYNAMIC_LOADER_HASHES).some(
|
|
8621
|
-
([suffix, hashes]) => normalized.endsWith(suffix) && hashes.includes(sha256(source))
|
|
8622
|
-
)) {
|
|
8623
|
-
return void 0;
|
|
8624
|
-
}
|
|
8625
|
-
return {
|
|
8626
|
-
contents: neutralizeDynamicLoads(source),
|
|
8627
|
-
loader: "js",
|
|
8628
|
-
resolveDir: path25.dirname(args.path)
|
|
8629
|
-
};
|
|
8630
|
-
});
|
|
8631
|
-
}
|
|
8632
|
-
};
|
|
8610
|
+
async function waitForProbeGroup(child, timeoutMs) {
|
|
8611
|
+
const deadline = Date.now() + timeoutMs;
|
|
8612
|
+
while (probeGroupRunning(child) && Date.now() < deadline) {
|
|
8613
|
+
await new Promise((resolve2) => setTimeout(resolve2, 25));
|
|
8614
|
+
}
|
|
8615
|
+
return !probeGroupRunning(child);
|
|
8633
8616
|
}
|
|
8634
|
-
function
|
|
8635
|
-
const
|
|
8636
|
-
return
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
return {
|
|
8642
|
-
path: projectRequire.resolve("class-transformer/cjs/storage.js")
|
|
8643
|
-
};
|
|
8644
|
-
} catch {
|
|
8645
|
-
return void 0;
|
|
8646
|
-
}
|
|
8647
|
-
});
|
|
8617
|
+
async function stopProbe(child) {
|
|
8618
|
+
const registered = probeIdentities.get(child);
|
|
8619
|
+
if (!registered) return;
|
|
8620
|
+
if (probeGroupRunning(child)) {
|
|
8621
|
+
try {
|
|
8622
|
+
process.kill(-registered.pid, "SIGTERM");
|
|
8623
|
+
} catch {
|
|
8648
8624
|
}
|
|
8649
|
-
}
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8655
|
-
}
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
esbuild.onResolve(
|
|
8661
|
-
{ filter: /^@lark-apaas\/fullstack-nestjs-core$/ },
|
|
8662
|
-
() => {
|
|
8663
|
-
try {
|
|
8664
|
-
return {
|
|
8665
|
-
path: resolveProjectPackage(
|
|
8666
|
-
projectRoot,
|
|
8667
|
-
"@lark-apaas/fullstack-nestjs-core/runtime"
|
|
8668
|
-
)
|
|
8669
|
-
};
|
|
8670
|
-
} catch {
|
|
8671
|
-
try {
|
|
8672
|
-
return {
|
|
8673
|
-
path: resolveProjectPackage(
|
|
8674
|
-
projectRoot,
|
|
8675
|
-
"@lark-apaas/fullstack-nestjs-core"
|
|
8676
|
-
)
|
|
8677
|
-
};
|
|
8678
|
-
} catch (error) {
|
|
8679
|
-
return {
|
|
8680
|
-
errors: [
|
|
8681
|
-
{
|
|
8682
|
-
text: `@lark-apaas/fullstack-nestjs-core cannot be resolved from project: ${error instanceof Error ? error.message : String(error)}`
|
|
8683
|
-
}
|
|
8684
|
-
]
|
|
8685
|
-
};
|
|
8686
|
-
}
|
|
8687
|
-
}
|
|
8688
|
-
}
|
|
8625
|
+
}
|
|
8626
|
+
if (!await waitForProbeGroup(child, 500)) {
|
|
8627
|
+
if (probeGroupRunning(child)) {
|
|
8628
|
+
try {
|
|
8629
|
+
process.kill(-registered.pid, "SIGKILL");
|
|
8630
|
+
} catch {
|
|
8631
|
+
}
|
|
8632
|
+
}
|
|
8633
|
+
if (!await waitForProbeGroup(child, 500)) {
|
|
8634
|
+
throw new Error(
|
|
8635
|
+
`isolated probe process group did not exit: ${registered.pid}`
|
|
8689
8636
|
);
|
|
8690
8637
|
}
|
|
8691
|
-
};
|
|
8692
|
-
}
|
|
8693
|
-
function legacyFullstackNestOpenApiStub(projectRoot) {
|
|
8694
|
-
let runtimeOnlyEntryAvailable = false;
|
|
8695
|
-
try {
|
|
8696
|
-
resolveProjectPackage(
|
|
8697
|
-
projectRoot,
|
|
8698
|
-
"@lark-apaas/fullstack-nestjs-core/runtime"
|
|
8699
|
-
);
|
|
8700
|
-
runtimeOnlyEntryAvailable = true;
|
|
8701
|
-
} catch {
|
|
8702
8638
|
}
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8639
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
8640
|
+
const exited = await new Promise((resolve2) => {
|
|
8641
|
+
let settled = false;
|
|
8642
|
+
let timer;
|
|
8643
|
+
const finish = (result) => {
|
|
8644
|
+
if (settled) return;
|
|
8645
|
+
settled = true;
|
|
8646
|
+
if (timer) clearTimeout(timer);
|
|
8647
|
+
child.off("exit", onExit);
|
|
8648
|
+
child.off("error", onError);
|
|
8649
|
+
resolve2(result);
|
|
8650
|
+
};
|
|
8651
|
+
const onExit = () => finish(true);
|
|
8652
|
+
const onError = () => finish(false);
|
|
8653
|
+
child.once("exit", onExit);
|
|
8654
|
+
child.once("error", onError);
|
|
8655
|
+
timer = setTimeout(() => finish(false), 5e3);
|
|
8656
|
+
if (child.exitCode !== null || child.signalCode !== null) finish(true);
|
|
8657
|
+
});
|
|
8658
|
+
if (!exited) {
|
|
8659
|
+
throw new Error(
|
|
8660
|
+
`isolated probe child did not publish exit after group cleanup: ${registered.pid}`
|
|
8720
8661
|
);
|
|
8721
8662
|
}
|
|
8722
|
-
}
|
|
8663
|
+
}
|
|
8723
8664
|
}
|
|
8724
|
-
function
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
if (node.name === "createRequire") {
|
|
8730
|
-
warnings.push("node createRequire remains in bundle");
|
|
8731
|
-
}
|
|
8732
|
-
},
|
|
8733
|
-
MemberExpression(node) {
|
|
8734
|
-
if (node.computed && node.property.type === "Literal" && node.property.value === "createRequire") {
|
|
8735
|
-
warnings.push("node createRequire remains in bundle");
|
|
8736
|
-
}
|
|
8737
|
-
},
|
|
8738
|
-
CallExpression(node) {
|
|
8739
|
-
const args = node.arguments;
|
|
8740
|
-
const isRequire = node.callee.type === "Identifier" && (node.callee.name === "require" || node.callee.name === "__require") || node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && node.callee.object.name === "module" && (node.callee.property.type === "Identifier" && node.callee.property.name === "require" || node.callee.property.type === "Literal" && node.callee.property.value === "require");
|
|
8741
|
-
const isRequireResolve = node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && (node.callee.object.name === "require" || node.callee.object.name === "__require") && node.callee.property.type === "Identifier" && node.callee.property.name === "resolve";
|
|
8742
|
-
if (isRequire && args[0]?.type !== "Literal") {
|
|
8743
|
-
warnings.push("dynamic require remains in bundle");
|
|
8744
|
-
} else if (isRequireResolve && args[0]?.type === "Literal" && typeof args[0].value === "string" && !BUILTINS.has(args[0].value)) {
|
|
8745
|
-
warnings.push(`require.resolve remains in bundle: ${args[0].value}`);
|
|
8746
|
-
} else if (isRequireResolve && (args[0]?.type !== "Literal" || typeof args[0].value !== "string")) {
|
|
8747
|
-
warnings.push("dynamic require.resolve remains in bundle");
|
|
8748
|
-
}
|
|
8749
|
-
},
|
|
8750
|
-
ImportExpression(node) {
|
|
8751
|
-
if (node.source.type !== "Literal" || typeof node.source.value !== "string") {
|
|
8752
|
-
warnings.push("dynamic import remains in bundle");
|
|
8753
|
-
}
|
|
8754
|
-
}
|
|
8665
|
+
function collectChildOutput(child, stream) {
|
|
8666
|
+
let output = "";
|
|
8667
|
+
child[stream]?.setEncoding("utf8");
|
|
8668
|
+
child[stream]?.on("data", (chunk) => {
|
|
8669
|
+
output = `${output}${String(chunk)}`.slice(-64 * 1024);
|
|
8755
8670
|
});
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
`${node.name} value escapes static call${member ? ` via ${member}` : ""}`
|
|
8671
|
+
return () => output;
|
|
8672
|
+
}
|
|
8673
|
+
async function waitForCommand(child, timeoutMs, description) {
|
|
8674
|
+
let timer;
|
|
8675
|
+
try {
|
|
8676
|
+
return await new Promise((resolve2, reject) => {
|
|
8677
|
+
let settled = false;
|
|
8678
|
+
const finish = (callback) => {
|
|
8679
|
+
if (settled) return;
|
|
8680
|
+
settled = true;
|
|
8681
|
+
if (timer) clearTimeout(timer);
|
|
8682
|
+
callback();
|
|
8683
|
+
};
|
|
8684
|
+
child.once("error", (error) => finish(() => reject(error)));
|
|
8685
|
+
child.once(
|
|
8686
|
+
"exit",
|
|
8687
|
+
(code, signal) => finish(
|
|
8688
|
+
() => signal ? reject(new Error(`${description} exited by ${signal}`)) : resolve2(code ?? 1)
|
|
8689
|
+
)
|
|
8776
8690
|
);
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8691
|
+
timer = setTimeout(
|
|
8692
|
+
() => finish(() => reject(new Error(`${description} timeout`))),
|
|
8693
|
+
timeoutMs
|
|
8694
|
+
);
|
|
8695
|
+
});
|
|
8696
|
+
} finally {
|
|
8697
|
+
if (timer) clearTimeout(timer);
|
|
8698
|
+
}
|
|
8699
|
+
}
|
|
8700
|
+
async function compileNestSource(projectRoot, stagingRoot, timeoutMs, sourceConfig) {
|
|
8701
|
+
const cliFile = resolveNestCli(projectRoot);
|
|
8702
|
+
const compileRoot = path26.join(stagingRoot, ".compiled");
|
|
8703
|
+
const outputRoot = path26.join(compileRoot, "output");
|
|
8704
|
+
fs30.mkdirSync(outputRoot, { recursive: true });
|
|
8705
|
+
const isolatedConfig = path26.join(compileRoot, "tsconfig.json");
|
|
8706
|
+
fs30.writeFileSync(
|
|
8707
|
+
isolatedConfig,
|
|
8708
|
+
`${JSON.stringify(
|
|
8709
|
+
{
|
|
8710
|
+
extends: sourceConfig,
|
|
8711
|
+
compilerOptions: {
|
|
8712
|
+
outDir: outputRoot,
|
|
8713
|
+
incremental: false,
|
|
8714
|
+
composite: false,
|
|
8715
|
+
declaration: false,
|
|
8716
|
+
declarationMap: false,
|
|
8717
|
+
sourceMap: false,
|
|
8718
|
+
inlineSourceMap: false
|
|
8719
|
+
}
|
|
8720
|
+
},
|
|
8721
|
+
null,
|
|
8722
|
+
2
|
|
8723
|
+
)}
|
|
8724
|
+
`,
|
|
8725
|
+
{ mode: 384 }
|
|
8726
|
+
);
|
|
8727
|
+
const child = spawn2(
|
|
8728
|
+
process.execPath,
|
|
8729
|
+
[cliFile, "build", "--path", path26.relative(projectRoot, isolatedConfig)],
|
|
8730
|
+
{
|
|
8731
|
+
cwd: projectRoot,
|
|
8732
|
+
detached: true,
|
|
8733
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
8734
|
+
env: { ...process.env, NODE_ENV: "production" }
|
|
8735
|
+
}
|
|
8736
|
+
);
|
|
8737
|
+
registerProbe(child);
|
|
8738
|
+
const stdout = collectChildOutput(child, "stdout");
|
|
8739
|
+
const stderr = collectChildOutput(child, "stderr");
|
|
8740
|
+
try {
|
|
8741
|
+
const code = await waitForCommand(
|
|
8742
|
+
child,
|
|
8743
|
+
timeoutMs,
|
|
8744
|
+
"isolated Nest compilation"
|
|
8745
|
+
);
|
|
8746
|
+
if (code !== 0) {
|
|
8747
|
+
throw new Error(
|
|
8748
|
+
`isolated Nest compilation failed with exit ${code}: ${stderr().trim() || stdout().trim()}`
|
|
8749
|
+
);
|
|
8750
|
+
}
|
|
8751
|
+
} finally {
|
|
8752
|
+
await stopProbe(child);
|
|
8753
|
+
}
|
|
8754
|
+
const candidates = [
|
|
8755
|
+
path26.join(outputRoot, "server", "main.js"),
|
|
8756
|
+
path26.join(outputRoot, "main.js")
|
|
8757
|
+
].filter((candidate) => fs30.existsSync(candidate));
|
|
8758
|
+
if (candidates.length !== 1) {
|
|
8759
|
+
throw new Error(
|
|
8760
|
+
candidates.length === 0 ? "isolated Nest compiled entry missing; checked server/main.js and main.js" : "isolated Nest compiled entry is ambiguous"
|
|
8761
|
+
);
|
|
8762
|
+
}
|
|
8763
|
+
const entry = fs30.realpathSync(candidates[0]);
|
|
8764
|
+
if (!isInside(fs30.realpathSync(outputRoot), entry) || !fs30.statSync(entry).isFile()) {
|
|
8765
|
+
throw new Error("isolated Nest compiled entry escaped output root");
|
|
8766
|
+
}
|
|
8767
|
+
return { entry, applicationRoot: outputRoot };
|
|
8768
|
+
}
|
|
8769
|
+
function copyRegularFile(source, target) {
|
|
8770
|
+
const stats = fs30.lstatSync(source);
|
|
8771
|
+
if (stats.isSymbolicLink()) {
|
|
8772
|
+
throw new Error(`runtime tree symlink is unsupported: ${source}`);
|
|
8773
|
+
}
|
|
8774
|
+
if (!stats.isFile()) {
|
|
8775
|
+
throw new Error(`runtime tree special file is unsupported: ${source}`);
|
|
8776
|
+
}
|
|
8777
|
+
fs30.mkdirSync(path26.dirname(target), { recursive: true });
|
|
8778
|
+
fs30.copyFileSync(source, target, fs30.constants.COPYFILE_FICLONE);
|
|
8779
|
+
fs30.chmodSync(target, stats.mode & 73 ? 493 : 420);
|
|
8780
|
+
}
|
|
8781
|
+
function copyDirectoryContents(sourceRoot, targetRoot, skipNestedNodeModules, budget, inspectFile) {
|
|
8782
|
+
const visit = (source, target) => {
|
|
8783
|
+
const stats = fs30.lstatSync(source);
|
|
8784
|
+
if (stats.isSymbolicLink()) {
|
|
8785
|
+
throw new Error(`runtime tree symlink is unsupported: ${source}`);
|
|
8786
|
+
}
|
|
8787
|
+
if (stats.isFile()) {
|
|
8788
|
+
if (budget) {
|
|
8789
|
+
reserveGenerationBudget(source, stats.size, budget);
|
|
8781
8790
|
}
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
|
|
8791
|
+
inspectFile?.(source, stats);
|
|
8792
|
+
copyRegularFile(source, target);
|
|
8793
|
+
return;
|
|
8794
|
+
}
|
|
8795
|
+
if (!stats.isDirectory()) {
|
|
8796
|
+
throw new Error(`runtime tree special file is unsupported: ${source}`);
|
|
8797
|
+
}
|
|
8798
|
+
fs30.mkdirSync(target, { recursive: true, mode: 493 });
|
|
8799
|
+
for (const entry of fs30.readdirSync(source, { withFileTypes: true })) {
|
|
8800
|
+
if (skipNestedNodeModules && entry.name === "node_modules") continue;
|
|
8801
|
+
visit(path26.join(source, entry.name), path26.join(target, entry.name));
|
|
8802
|
+
}
|
|
8803
|
+
};
|
|
8804
|
+
visit(sourceRoot, targetRoot);
|
|
8805
|
+
}
|
|
8806
|
+
function reserveGenerationBudget(file, size, budget) {
|
|
8807
|
+
if (size > MAX_GENERATION_FILE_BYTES) {
|
|
8808
|
+
throw new Error(`generation file exceeds 64 MiB: ${file}`);
|
|
8809
|
+
}
|
|
8810
|
+
if (budget.fileCount + 1 > MAX_GENERATION_FILES) {
|
|
8811
|
+
throw new Error(`generation exceeds ${MAX_GENERATION_FILES} files`);
|
|
8812
|
+
}
|
|
8813
|
+
if (budget.totalBytes + size > MAX_GENERATION_BYTES) {
|
|
8814
|
+
throw new Error("generation exceeds 256 MiB");
|
|
8815
|
+
}
|
|
8816
|
+
budget.fileCount += 1;
|
|
8817
|
+
budget.totalBytes += size;
|
|
8818
|
+
}
|
|
8819
|
+
function measurePayload(payloadRoot) {
|
|
8820
|
+
const budget = { fileCount: 0, totalBytes: 0 };
|
|
8821
|
+
const visit = (directory) => {
|
|
8822
|
+
for (const entry of fs30.readdirSync(directory, { withFileTypes: true })) {
|
|
8823
|
+
const candidate = path26.join(directory, entry.name);
|
|
8824
|
+
const stats = fs30.lstatSync(candidate);
|
|
8825
|
+
if (stats.isSymbolicLink()) {
|
|
8826
|
+
throw new Error(`generation symlink is unsupported: ${candidate}`);
|
|
8827
|
+
}
|
|
8828
|
+
if (stats.isDirectory()) visit(candidate);
|
|
8829
|
+
else if (stats.isFile()) {
|
|
8830
|
+
reserveGenerationBudget(candidate, stats.size, budget);
|
|
8831
|
+
} else {
|
|
8832
|
+
throw new Error(`generation special file is unsupported: ${candidate}`);
|
|
8785
8833
|
}
|
|
8786
|
-
warnings.push("module.require value escapes static call");
|
|
8787
8834
|
}
|
|
8788
|
-
}
|
|
8789
|
-
|
|
8835
|
+
};
|
|
8836
|
+
visit(payloadRoot);
|
|
8837
|
+
return budget;
|
|
8838
|
+
}
|
|
8839
|
+
function copyProbeWorkspace(projectRoot, probeProjectRoot) {
|
|
8840
|
+
const files = [];
|
|
8841
|
+
walkSourceFiles(projectRoot, projectRoot, files);
|
|
8842
|
+
const budget = { fileCount: 0, totalBytes: 0 };
|
|
8843
|
+
for (const file of files) {
|
|
8844
|
+
reserveGenerationBudget(file, fs30.lstatSync(file).size, budget);
|
|
8845
|
+
copyRegularFile(
|
|
8846
|
+
file,
|
|
8847
|
+
path26.join(
|
|
8848
|
+
probeProjectRoot,
|
|
8849
|
+
...toPosixRelative(projectRoot, file).split("/")
|
|
8850
|
+
)
|
|
8851
|
+
);
|
|
8852
|
+
}
|
|
8853
|
+
}
|
|
8854
|
+
function readJsonObject(file, description) {
|
|
8855
|
+
const parsed = JSON.parse(
|
|
8856
|
+
readBoundedFile(file, MAX_PACKAGE_MANIFEST_BYTES, description).toString(
|
|
8857
|
+
"utf8"
|
|
8858
|
+
)
|
|
8859
|
+
);
|
|
8860
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
8861
|
+
throw new Error(`${description} must be a JSON object`);
|
|
8862
|
+
}
|
|
8863
|
+
return parsed;
|
|
8864
|
+
}
|
|
8865
|
+
function readBoundedFile(file, maxBytes, description) {
|
|
8866
|
+
const stats = fs30.lstatSync(file);
|
|
8867
|
+
if (stats.isSymbolicLink() || !stats.isFile() || stats.size > maxBytes) {
|
|
8868
|
+
throw new Error(`${description} exceeds the supported metadata size`);
|
|
8869
|
+
}
|
|
8870
|
+
const contents = fs30.readFileSync(file);
|
|
8871
|
+
if (contents.length !== stats.size) {
|
|
8872
|
+
throw new Error(`${description} changed while reading`);
|
|
8873
|
+
}
|
|
8874
|
+
return contents;
|
|
8875
|
+
}
|
|
8876
|
+
function lockPackages(lock, description) {
|
|
8877
|
+
if (typeof lock.lockfileVersion !== "number" || lock.lockfileVersion < 2 || !lock.packages || typeof lock.packages !== "object" || Array.isArray(lock.packages)) {
|
|
8878
|
+
throw new Error(`${description} must be an npm lockfile v2 or v3`);
|
|
8879
|
+
}
|
|
8880
|
+
return lock.packages;
|
|
8881
|
+
}
|
|
8882
|
+
function comparableLockRecord(record) {
|
|
8883
|
+
return {
|
|
8884
|
+
integrity: record.integrity,
|
|
8885
|
+
link: record.link,
|
|
8886
|
+
resolved: record.resolved,
|
|
8887
|
+
version: record.version
|
|
8888
|
+
};
|
|
8889
|
+
}
|
|
8890
|
+
function isSafePackageLockPath(relative) {
|
|
8891
|
+
if (!relative.startsWith("node_modules/") || relative.includes("\\") || path26.posix.isAbsolute(relative)) {
|
|
8892
|
+
return false;
|
|
8893
|
+
}
|
|
8894
|
+
const segments = relative.split("/");
|
|
8895
|
+
return segments.every(
|
|
8896
|
+
(segment) => segment && segment !== "." && segment !== ".."
|
|
8897
|
+
);
|
|
8790
8898
|
}
|
|
8791
8899
|
function memberPropertyName(node) {
|
|
8792
8900
|
if (!node || typeof node !== "object") return void 0;
|
|
@@ -8795,520 +8903,1039 @@ function memberPropertyName(node) {
|
|
|
8795
8903
|
if (candidate.type === "Literal" && typeof candidate.value === "string") {
|
|
8796
8904
|
return candidate.value;
|
|
8797
8905
|
}
|
|
8798
|
-
if (candidate.type === "MemberExpression") {
|
|
8799
|
-
return memberPropertyName(candidate.property);
|
|
8800
|
-
}
|
|
8801
8906
|
return void 0;
|
|
8802
8907
|
}
|
|
8803
|
-
function
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
|
|
8808
|
-
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
fragments.push(candidate.value);
|
|
8814
|
-
return;
|
|
8815
|
-
}
|
|
8816
|
-
if (candidate.type === "TemplateElement") {
|
|
8817
|
-
const templateValue = candidate.value;
|
|
8818
|
-
const text = templateValue?.cooked ?? templateValue?.raw;
|
|
8819
|
-
if (typeof text === "string") fragments.push(text);
|
|
8820
|
-
return;
|
|
8821
|
-
}
|
|
8822
|
-
for (const [key, child] of Object.entries(candidate)) {
|
|
8823
|
-
if (key === "start" || key === "end" || key === "loc") continue;
|
|
8824
|
-
visit(child);
|
|
8825
|
-
}
|
|
8826
|
-
};
|
|
8827
|
-
visit(node);
|
|
8828
|
-
return /(?:^|[\\/])node_modules(?:[\\/]|$)/.test(
|
|
8829
|
-
fragments.join("/").replace(/\\\\/g, "/")
|
|
8908
|
+
function isLiteralString(node) {
|
|
8909
|
+
return Boolean(
|
|
8910
|
+
node && typeof node === "object" && node.type === "Literal" && typeof node.value === "string"
|
|
8911
|
+
);
|
|
8912
|
+
}
|
|
8913
|
+
function isRuntimeTypeScriptSpecifier(node) {
|
|
8914
|
+
return Boolean(
|
|
8915
|
+
isLiteralString(node) && /\.(?:cts|mts|ts|tsx)(?:$|[?#])/.test(
|
|
8916
|
+
String(node.value)
|
|
8917
|
+
)
|
|
8830
8918
|
);
|
|
8831
8919
|
}
|
|
8832
|
-
function
|
|
8920
|
+
function isPackageRelativeDynamicTarget(node) {
|
|
8833
8921
|
if (!node || typeof node !== "object") return false;
|
|
8834
|
-
if (Array.isArray(node)) {
|
|
8835
|
-
return node.some((item) => expressionContainsIdentifier(item, name));
|
|
8836
|
-
}
|
|
8837
8922
|
const candidate = node;
|
|
8838
|
-
if (candidate.type === "
|
|
8839
|
-
|
|
8840
|
-
|
|
8923
|
+
if (candidate.type === "Literal" && typeof candidate.value === "string") {
|
|
8924
|
+
return candidate.value.startsWith("./");
|
|
8925
|
+
}
|
|
8926
|
+
if (candidate.type === "TemplateLiteral") {
|
|
8927
|
+
const prefix = candidate.quasis?.[0]?.value?.cooked;
|
|
8928
|
+
return typeof prefix === "string" && prefix.startsWith("./");
|
|
8929
|
+
}
|
|
8930
|
+
if (candidate.type === "BinaryExpression" && candidate.operator === "+") {
|
|
8931
|
+
return isPackageRelativeDynamicTarget(candidate.left);
|
|
8932
|
+
}
|
|
8933
|
+
if (candidate.type === "ConditionalExpression") {
|
|
8934
|
+
return isPackageRelativeDynamicTarget(candidate.consequent) && isPackageRelativeDynamicTarget(candidate.alternate);
|
|
8935
|
+
}
|
|
8936
|
+
if (candidate.type === "LogicalExpression" && (candidate.operator === "||" || candidate.operator === "??")) {
|
|
8937
|
+
return isPackageRelativeDynamicTarget(candidate.left) && isPackageRelativeDynamicTarget(candidate.right);
|
|
8938
|
+
}
|
|
8939
|
+
if (candidate.type !== "CallExpression") return false;
|
|
8940
|
+
const callee = candidate.callee;
|
|
8941
|
+
if (callee?.type !== "MemberExpression") return false;
|
|
8942
|
+
const property = memberPropertyName(callee.property);
|
|
8943
|
+
if (property !== "join" && property !== "resolve") return false;
|
|
8944
|
+
const firstArgument = candidate.arguments?.[0];
|
|
8945
|
+
return Boolean(
|
|
8946
|
+
firstArgument && (firstArgument.type === "Identifier" && (firstArgument.name === "__dirname" || firstArgument.name === "__filename") || isPackageRelativeDynamicTarget(firstArgument))
|
|
8841
8947
|
);
|
|
8842
8948
|
}
|
|
8843
|
-
function
|
|
8844
|
-
|
|
8845
|
-
const
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
walkSimple(ast, {
|
|
8852
|
-
CallExpression(node) {
|
|
8853
|
-
const method = memberPropertyName(node.callee);
|
|
8854
|
-
if (method && RUNTIME_ASSET_READ_METHODS.has(method) && rejectEveryRead) {
|
|
8855
|
-
warnings.push(`dependency runtime fs read in input: ${origin}`);
|
|
8856
|
-
} else if (method && RUNTIME_ASSET_READ_METHODS.has(method) && expressionContainsNodeModulesPath(node.arguments[0])) {
|
|
8857
|
-
warnings.push(`node_modules runtime asset read in input: ${origin}`);
|
|
8858
|
-
} else if (method && RUNTIME_ASSET_READ_METHODS.has(method) && expressionContainsIdentifier(node.arguments[0], "__dirname")) {
|
|
8859
|
-
warnings.push(`__dirname runtime asset read in input: ${origin}`);
|
|
8860
|
-
}
|
|
8861
|
-
}
|
|
8862
|
-
});
|
|
8863
|
-
return warnings;
|
|
8864
|
-
}
|
|
8865
|
-
function findUnsafeApplicationModuleLoads(projectRoot, applicationRoot, inputFiles) {
|
|
8866
|
-
const realApplicationRoot = fs29.realpathSync(applicationRoot);
|
|
8867
|
-
const warnings = [];
|
|
8868
|
-
for (const input of inputFiles) {
|
|
8869
|
-
const candidate = path25.isAbsolute(input) ? input : path25.resolve(projectRoot, input);
|
|
8870
|
-
if (!fs29.existsSync(candidate)) continue;
|
|
8871
|
-
const realInput = fs29.realpathSync(candidate);
|
|
8872
|
-
if (!/\.(?:cjs|mjs|js)$/.test(realInput)) continue;
|
|
8873
|
-
const source = fs29.readFileSync(realInput, "utf8");
|
|
8874
|
-
const isDependencyInput = realInput.split(path25.sep).includes("node_modules");
|
|
8875
|
-
const normalizedInput = realInput.split(path25.sep).join("/");
|
|
8876
|
-
const auditedRuntimeFsReader = isDependencyInput && Object.entries(AUDITED_RUNTIME_FS_READER_HASHES).some(
|
|
8877
|
-
([suffix, hashes]) => normalizedInput.endsWith(suffix) && hashes.includes(sha256(source))
|
|
8878
|
-
);
|
|
8879
|
-
const origin = path25.relative(projectRoot, realInput).split(path25.sep).join("/");
|
|
8880
|
-
warnings.push(
|
|
8881
|
-
...findNodeModulesRuntimeAssetReads(
|
|
8882
|
-
source,
|
|
8883
|
-
origin,
|
|
8884
|
-
isDependencyInput && !auditedRuntimeFsReader
|
|
8885
|
-
)
|
|
8949
|
+
function isProvablyPackageEscapingPath(node) {
|
|
8950
|
+
if (!node || typeof node !== "object") return false;
|
|
8951
|
+
const candidate = node;
|
|
8952
|
+
if (candidate.type === "BinaryExpression" && candidate.operator === "+") {
|
|
8953
|
+
const left = candidate.left;
|
|
8954
|
+
const right = candidate.right;
|
|
8955
|
+
return Boolean(
|
|
8956
|
+
left?.type === "Identifier" && left.name === "__dirname" && right?.type === "Literal" && typeof right.value === "string" && path26.posix.normalize(path26.posix.join("/package", right.value)).startsWith("/package/") === false
|
|
8886
8957
|
);
|
|
8887
|
-
|
|
8888
|
-
|
|
8958
|
+
}
|
|
8959
|
+
if (candidate.type !== "CallExpression") return false;
|
|
8960
|
+
const callee = candidate.callee;
|
|
8961
|
+
if (callee?.type !== "MemberExpression" || !["join", "resolve"].includes(memberPropertyName(callee.property) || "")) {
|
|
8962
|
+
return false;
|
|
8963
|
+
}
|
|
8964
|
+
const [base, ...segments] = candidate.arguments || [];
|
|
8965
|
+
if (!base || typeof base !== "object" || base.type !== "Identifier" || base.name !== "__dirname" || segments.some(
|
|
8966
|
+
(segment) => !segment || typeof segment !== "object" || segment.type !== "Literal" || typeof segment.value !== "string"
|
|
8967
|
+
)) {
|
|
8968
|
+
return false;
|
|
8969
|
+
}
|
|
8970
|
+
const normalized = path26.posix.normalize(
|
|
8971
|
+
path26.posix.join(
|
|
8972
|
+
"/package",
|
|
8973
|
+
...segments.map((segment) => String(segment.value))
|
|
8974
|
+
)
|
|
8975
|
+
);
|
|
8976
|
+
return normalized !== "/package" && !normalized.startsWith("/package/");
|
|
8977
|
+
}
|
|
8978
|
+
function dynamicCodeEvaluatorKind(node) {
|
|
8979
|
+
if (!node || typeof node !== "object") return void 0;
|
|
8980
|
+
const candidate = node;
|
|
8981
|
+
if (candidate.type === "Identifier") {
|
|
8982
|
+
if (candidate.name === "eval") return "eval";
|
|
8983
|
+
if (candidate.name === "Function") return "function";
|
|
8984
|
+
return void 0;
|
|
8985
|
+
}
|
|
8986
|
+
if (candidate.type === "SequenceExpression") {
|
|
8987
|
+
for (const expression of candidate.expressions ?? []) {
|
|
8988
|
+
const kind = dynamicCodeEvaluatorKind(expression);
|
|
8989
|
+
if (kind) return kind;
|
|
8889
8990
|
}
|
|
8890
|
-
|
|
8991
|
+
return void 0;
|
|
8992
|
+
}
|
|
8993
|
+
if (candidate.type === "MemberExpression") {
|
|
8994
|
+
const property = memberPropertyName(candidate.property);
|
|
8995
|
+
if (property === "eval") return "eval";
|
|
8996
|
+
if (property === "Function") return "function";
|
|
8997
|
+
}
|
|
8998
|
+
return void 0;
|
|
8999
|
+
}
|
|
9000
|
+
function isLiteralEvalImport(node) {
|
|
9001
|
+
if (node.callee.type !== "Identifier" || node.callee.name !== "eval" || node.arguments.length !== 1 || !isLiteralString(node.arguments[0])) {
|
|
9002
|
+
return false;
|
|
9003
|
+
}
|
|
9004
|
+
const source = String(node.arguments[0].value).trim();
|
|
9005
|
+
const match = source.match(/^import\s*\(\s*(['"])([^'"\\]+)\1\s*\)\s*;?$/);
|
|
9006
|
+
return Boolean(match && isBareSpecifier(match[2]));
|
|
9007
|
+
}
|
|
9008
|
+
function isLiteralEvalWithoutUnboundedModuleLoading(node) {
|
|
9009
|
+
if (node.callee.type !== "Identifier" && node.callee.type !== "SequenceExpression") {
|
|
9010
|
+
return false;
|
|
9011
|
+
}
|
|
9012
|
+
if (dynamicCodeEvaluatorKind(node.callee) !== "eval" || node.arguments.length !== 1 || !isLiteralString(node.arguments[0])) {
|
|
9013
|
+
return false;
|
|
9014
|
+
}
|
|
9015
|
+
const source = String(node.arguments[0].value).trim();
|
|
9016
|
+
return source === "require" || isLiteralEvalImport(node) || !/\b(?:import|require)\b|\b(?:dlopen|_load|_resolveFilename)\b/.test(source);
|
|
9017
|
+
}
|
|
9018
|
+
function isEvalRequireFactory(node) {
|
|
9019
|
+
if (!node || typeof node !== "object") return false;
|
|
9020
|
+
const candidate = node;
|
|
9021
|
+
return Boolean(
|
|
9022
|
+
candidate.type === "CallExpression" && candidate.callee.type === "Identifier" && candidate.callee.name === "eval" && candidate.arguments.length === 1 && isLiteralString(candidate.arguments[0]) && String(candidate.arguments[0].value).trim() === "require"
|
|
9023
|
+
);
|
|
9024
|
+
}
|
|
9025
|
+
function packageLayoutCapabilityReasons(source) {
|
|
9026
|
+
const reasons = /* @__PURE__ */ new Set();
|
|
9027
|
+
if (/\brequire\s*\(\s*['"](?:node:)?fs(?:\/promises)?['"]\s*\)/.test(source) || /\bfrom\s*['"](?:node:)?fs(?:\/promises)?['"]/.test(source) || /\bimport\s*['"](?:node:)?fs(?:\/promises)?['"]/.test(source)) {
|
|
9028
|
+
reasons.add("uses filesystem APIs");
|
|
9029
|
+
}
|
|
9030
|
+
if (/\brequire\s*\(\s*['"](?:node:)?vm['"]\s*\)/.test(source) || /\bfrom\s*['"](?:node:)?vm['"]/.test(source) || /\bimport\s*['"](?:node:)?vm['"]/.test(source)) {
|
|
9031
|
+
reasons.add("uses VM code evaluation");
|
|
9032
|
+
}
|
|
9033
|
+
let ast;
|
|
9034
|
+
try {
|
|
9035
|
+
ast = parse(source, {
|
|
8891
9036
|
ecmaVersion: "latest",
|
|
8892
9037
|
sourceType: "module",
|
|
8893
9038
|
allowHashBang: true,
|
|
8894
9039
|
allowReturnOutsideFunction: true
|
|
8895
9040
|
});
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
9041
|
+
} catch {
|
|
9042
|
+
try {
|
|
9043
|
+
ast = parse(source, {
|
|
9044
|
+
ecmaVersion: "latest",
|
|
9045
|
+
sourceType: "script",
|
|
9046
|
+
allowHashBang: true,
|
|
9047
|
+
allowReturnOutsideFunction: true
|
|
9048
|
+
});
|
|
9049
|
+
} catch {
|
|
9050
|
+
return [...reasons, "requires a package-local JavaScript loader"];
|
|
9051
|
+
}
|
|
9052
|
+
}
|
|
9053
|
+
const requireAliases = /* @__PURE__ */ new Set(["require"]);
|
|
9054
|
+
walkSimple(ast, {
|
|
9055
|
+
VariableDeclarator(node) {
|
|
9056
|
+
if (node.id.type === "Identifier" && node.init?.type === "Identifier" && requireAliases.has(node.init.name)) {
|
|
9057
|
+
requireAliases.add(node.id.name);
|
|
9058
|
+
}
|
|
9059
|
+
}
|
|
9060
|
+
});
|
|
9061
|
+
walkSimple(ast, {
|
|
9062
|
+
CallExpression(node) {
|
|
9063
|
+
const callee = node.callee;
|
|
9064
|
+
const evaluatorKind = dynamicCodeEvaluatorKind(callee);
|
|
9065
|
+
if (evaluatorKind === "eval" && !isLiteralEvalWithoutUnboundedModuleLoading(node)) {
|
|
9066
|
+
reasons.add("uses eval-generated code");
|
|
9067
|
+
} else if (evaluatorKind === "function") {
|
|
9068
|
+
reasons.add("uses Function constructor");
|
|
9069
|
+
}
|
|
9070
|
+
if (callee.type === "MemberExpression") {
|
|
9071
|
+
const property = memberPropertyName(callee.property);
|
|
9072
|
+
if (property === "_load" || property === "_resolveFilename") {
|
|
9073
|
+
reasons.add("uses unbounded Node module loader");
|
|
8902
9074
|
}
|
|
8903
|
-
if (
|
|
8904
|
-
|
|
8905
|
-
`dynamic require.resolve in application input: ${origin}`
|
|
8906
|
-
);
|
|
9075
|
+
if (property === "dlopen" && callee.object.type === "Identifier" && callee.object.name === "process") {
|
|
9076
|
+
reasons.add("uses native dynamic loader");
|
|
8907
9077
|
}
|
|
8908
|
-
}
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
9078
|
+
}
|
|
9079
|
+
if (isEvalRequireFactory(callee)) {
|
|
9080
|
+
reasons.add("uses unbounded dynamic require");
|
|
9081
|
+
}
|
|
9082
|
+
const directRequire = callee.type === "Identifier" && requireAliases.has(callee.name);
|
|
9083
|
+
const moduleRequire = callee.type === "MemberExpression" && callee.object.type === "Identifier" && callee.object.name === "module" && memberPropertyName(callee.property) === "require";
|
|
9084
|
+
const requireResolve = callee.type === "MemberExpression" && callee.object.type === "Identifier" && callee.object.name === "require" && memberPropertyName(callee.property) === "resolve";
|
|
9085
|
+
if ((directRequire || moduleRequire) && !isLiteralString(node.arguments[0])) {
|
|
9086
|
+
reasons.add(
|
|
9087
|
+
isPackageRelativeDynamicTarget(node.arguments[0]) ? "uses package-relative dynamic require" : "uses unbounded dynamic require"
|
|
9088
|
+
);
|
|
9089
|
+
}
|
|
9090
|
+
if ((directRequire || moduleRequire || requireResolve) && isRuntimeTypeScriptSpecifier(node.arguments[0])) {
|
|
9091
|
+
reasons.add("loads runtime TypeScript");
|
|
9092
|
+
}
|
|
9093
|
+
if (requireResolve) {
|
|
9094
|
+
reasons.add(
|
|
9095
|
+
isLiteralString(node.arguments[0]) || isPackageRelativeDynamicTarget(node.arguments[0]) ? "uses package-relative require.resolve" : "uses unbounded dynamic require.resolve"
|
|
9096
|
+
);
|
|
9097
|
+
}
|
|
9098
|
+
},
|
|
9099
|
+
ImportExpression(node) {
|
|
9100
|
+
if (isRuntimeTypeScriptSpecifier(node.source)) {
|
|
9101
|
+
reasons.add("loads runtime TypeScript");
|
|
9102
|
+
} else if (!isLiteralString(node.source)) {
|
|
9103
|
+
reasons.add(
|
|
9104
|
+
isPackageRelativeDynamicTarget(node.source) ? "uses package-relative dynamic import" : "uses unbounded dynamic import"
|
|
9105
|
+
);
|
|
9106
|
+
}
|
|
9107
|
+
},
|
|
9108
|
+
ImportDeclaration(node) {
|
|
9109
|
+
if (isRuntimeTypeScriptSpecifier(node.source)) {
|
|
9110
|
+
reasons.add("loads runtime TypeScript");
|
|
9111
|
+
}
|
|
9112
|
+
},
|
|
9113
|
+
VariableDeclarator(node) {
|
|
9114
|
+
if (node.id.type !== "ObjectPattern") return;
|
|
9115
|
+
const init2 = node.init;
|
|
9116
|
+
const moduleConstructor = Boolean(
|
|
9117
|
+
init2?.type === "MemberExpression" && memberPropertyName(init2.property) === "constructor" && init2.object?.type === "Identifier" && init2.object.name === "module"
|
|
9118
|
+
);
|
|
9119
|
+
const nodeModuleNamespace = Boolean(
|
|
9120
|
+
init2?.type === "Identifier" && init2.name === "Module"
|
|
9121
|
+
);
|
|
9122
|
+
if (!moduleConstructor && !nodeModuleNamespace) return;
|
|
9123
|
+
for (const property of node.id.properties) {
|
|
9124
|
+
if (property.type !== "Property") continue;
|
|
9125
|
+
const name = memberPropertyName(property.key);
|
|
9126
|
+
if (name === "_load" || name === "_resolveFilename") {
|
|
9127
|
+
reasons.add("uses unbounded Node module loader");
|
|
8912
9128
|
}
|
|
9129
|
+
if (name === "dlopen") reasons.add("uses native dynamic loader");
|
|
8913
9130
|
}
|
|
8914
|
-
}
|
|
8915
|
-
|
|
8916
|
-
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
9131
|
+
},
|
|
9132
|
+
NewExpression(node) {
|
|
9133
|
+
if (dynamicCodeEvaluatorKind(node.callee) === "function") {
|
|
9134
|
+
reasons.add("uses Function constructor");
|
|
9135
|
+
}
|
|
9136
|
+
},
|
|
9137
|
+
MetaProperty(node) {
|
|
9138
|
+
if (node.meta.name === "import" && node.property.name === "meta") {
|
|
9139
|
+
reasons.add("uses import.meta package location");
|
|
9140
|
+
}
|
|
9141
|
+
}
|
|
9142
|
+
});
|
|
9143
|
+
const fsNamespaces = /* @__PURE__ */ new Set();
|
|
9144
|
+
const fsPathFunctions = /* @__PURE__ */ new Set();
|
|
9145
|
+
const fsPathMethods = /* @__PURE__ */ new Set([
|
|
9146
|
+
"access",
|
|
9147
|
+
"accessSync",
|
|
9148
|
+
"createReadStream",
|
|
9149
|
+
"existsSync",
|
|
9150
|
+
"lstat",
|
|
9151
|
+
"lstatSync",
|
|
9152
|
+
"open",
|
|
9153
|
+
"openSync",
|
|
9154
|
+
"readFile",
|
|
9155
|
+
"readFileSync",
|
|
9156
|
+
"readdir",
|
|
9157
|
+
"readdirSync",
|
|
9158
|
+
"realpath",
|
|
9159
|
+
"realpathSync",
|
|
9160
|
+
"stat",
|
|
9161
|
+
"statSync"
|
|
9162
|
+
]);
|
|
9163
|
+
walkSimple(ast, {
|
|
9164
|
+
ImportDeclaration(node) {
|
|
9165
|
+
if (typeof node.source.value !== "string" || !["fs", "node:fs", "fs/promises", "node:fs/promises"].includes(
|
|
9166
|
+
node.source.value
|
|
9167
|
+
)) {
|
|
9168
|
+
return;
|
|
9169
|
+
}
|
|
9170
|
+
for (const specifier of node.specifiers) {
|
|
9171
|
+
if (specifier.type === "ImportSpecifier") {
|
|
9172
|
+
if (fsPathMethods.has(specifier.imported.name)) {
|
|
9173
|
+
fsPathFunctions.add(specifier.local.name);
|
|
9174
|
+
}
|
|
9175
|
+
} else {
|
|
9176
|
+
fsNamespaces.add(specifier.local.name);
|
|
9177
|
+
}
|
|
9178
|
+
}
|
|
9179
|
+
},
|
|
9180
|
+
VariableDeclarator(node) {
|
|
9181
|
+
const init2 = node.init;
|
|
9182
|
+
const required = init2?.type === "CallExpression" && init2.callee?.type === "Identifier" && init2.callee.name === "require" && isLiteralString(init2.arguments?.[0]) && ["fs", "node:fs", "fs/promises", "node:fs/promises"].includes(
|
|
9183
|
+
String((init2.arguments?.[0]).value)
|
|
9184
|
+
);
|
|
9185
|
+
if (!required) return;
|
|
9186
|
+
if (node.id.type === "Identifier") fsNamespaces.add(node.id.name);
|
|
9187
|
+
if (node.id.type === "ObjectPattern") {
|
|
9188
|
+
for (const property of node.id.properties) {
|
|
9189
|
+
if (property.type === "Property" && property.value.type === "Identifier" && fsPathMethods.has(memberPropertyName(property.key) || "")) {
|
|
9190
|
+
fsPathFunctions.add(property.value.name);
|
|
9191
|
+
}
|
|
9192
|
+
}
|
|
9193
|
+
}
|
|
9194
|
+
}
|
|
9195
|
+
});
|
|
9196
|
+
walkSimple(ast, {
|
|
9197
|
+
CallExpression(node) {
|
|
9198
|
+
const callee = node.callee;
|
|
9199
|
+
let isFsPathCall = callee.type === "Identifier" && fsPathFunctions.has(callee.name);
|
|
9200
|
+
if (callee.type === "MemberExpression") {
|
|
9201
|
+
const method = memberPropertyName(callee.property);
|
|
9202
|
+
const object = callee.object;
|
|
9203
|
+
const namespace = object.type === "Identifier" ? object.name : object.type === "MemberExpression" && memberPropertyName(object.property) === "promises" && object.object.type === "Identifier" ? object.object.name : void 0;
|
|
9204
|
+
isFsPathCall = Boolean(
|
|
9205
|
+
namespace && fsNamespaces.has(namespace) && fsPathMethods.has(method || "")
|
|
8927
9206
|
);
|
|
9207
|
+
}
|
|
9208
|
+
if (isFsPathCall && isProvablyPackageEscapingPath(node.arguments[0])) {
|
|
9209
|
+
reasons.add("uses filesystem path outside the proven package boundary");
|
|
9210
|
+
}
|
|
9211
|
+
}
|
|
9212
|
+
});
|
|
9213
|
+
walkAncestor(ast, {
|
|
9214
|
+
Identifier(node, _state, ancestors) {
|
|
9215
|
+
const parent = ancestors.at(-2);
|
|
9216
|
+
const grandparent = ancestors.at(-3);
|
|
9217
|
+
if (node.name === "__dirname" || node.name === "__filename") {
|
|
9218
|
+
if (parent?.type === "MemberExpression" && parent.property === node && !parent.computed) {
|
|
9219
|
+
return;
|
|
9220
|
+
}
|
|
9221
|
+
reasons.add("uses package-relative file location");
|
|
8928
9222
|
return;
|
|
8929
9223
|
}
|
|
8930
|
-
|
|
8931
|
-
|
|
9224
|
+
if (node.name === "createRequire") {
|
|
9225
|
+
reasons.add("uses createRequire");
|
|
9226
|
+
return;
|
|
9227
|
+
}
|
|
9228
|
+
if (node.name !== "require") return;
|
|
9229
|
+
if (parent?.type === "CallExpression" && parent.callee === node) return;
|
|
9230
|
+
if (parent?.type === "UnaryExpression" && parent.operator === "typeof") {
|
|
9231
|
+
return;
|
|
9232
|
+
}
|
|
9233
|
+
if (parent?.type === "MemberExpression" && parent.object === node) {
|
|
9234
|
+
const property = memberPropertyName(parent.property);
|
|
9235
|
+
if (property === "resolve" && grandparent?.type === "CallExpression" && grandparent.callee === parent) {
|
|
9236
|
+
return;
|
|
9237
|
+
}
|
|
9238
|
+
reasons.add(`uses require.${property ?? "unknown"} runtime state`);
|
|
9239
|
+
return;
|
|
9240
|
+
}
|
|
9241
|
+
reasons.add("escapes the require function");
|
|
9242
|
+
},
|
|
9243
|
+
MemberExpression(node, _state, ancestors) {
|
|
9244
|
+
const property = memberPropertyName(node.property);
|
|
9245
|
+
const object = node.object;
|
|
9246
|
+
const moduleConstructor = Boolean(
|
|
9247
|
+
object.type === "MemberExpression" && memberPropertyName(object.property) === "constructor" && object.object?.type === "Identifier" && object.object.name === "module"
|
|
9248
|
+
);
|
|
9249
|
+
if ((property === "_load" || property === "_resolveFilename") && (moduleConstructor || object.type === "Identifier" && object.name === "Module")) {
|
|
9250
|
+
reasons.add("uses unbounded Node module loader");
|
|
9251
|
+
}
|
|
9252
|
+
if (property === "dlopen" && object.type === "Identifier" && object.name === "process") {
|
|
9253
|
+
reasons.add("uses native dynamic loader");
|
|
9254
|
+
}
|
|
9255
|
+
if (node.object.type !== "Identifier" || node.object.name !== "module" || property !== "require") {
|
|
9256
|
+
return;
|
|
9257
|
+
}
|
|
9258
|
+
const parent = ancestors.at(-2);
|
|
9259
|
+
if (parent?.type === "CallExpression" && parent.callee === node) return;
|
|
9260
|
+
reasons.add("escapes module.require");
|
|
9261
|
+
}
|
|
8932
9262
|
});
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
9263
|
+
return [...reasons].sort();
|
|
9264
|
+
}
|
|
9265
|
+
function createPackageOwnerResolver(projectRoot) {
|
|
9266
|
+
const nodeModulesRoot = path26.join(projectRoot, "node_modules");
|
|
9267
|
+
const cache = /* @__PURE__ */ new Map();
|
|
9268
|
+
return (file) => {
|
|
9269
|
+
const absolute = path26.resolve(file);
|
|
9270
|
+
const cached = cache.get(absolute);
|
|
9271
|
+
if (cached !== void 0 || cache.has(absolute)) return cached;
|
|
9272
|
+
if (!isInside(nodeModulesRoot, absolute)) {
|
|
9273
|
+
cache.set(absolute, void 0);
|
|
9274
|
+
return void 0;
|
|
9275
|
+
}
|
|
9276
|
+
let current = fs30.existsSync(absolute) && fs30.statSync(absolute).isDirectory() ? absolute : path26.dirname(absolute);
|
|
9277
|
+
while (isInside(nodeModulesRoot, current) && current !== nodeModulesRoot) {
|
|
9278
|
+
const manifest = path26.join(current, "package.json");
|
|
9279
|
+
if (fs30.existsSync(manifest) && fs30.statSync(manifest).isFile()) {
|
|
9280
|
+
cache.set(absolute, current);
|
|
9281
|
+
return current;
|
|
9282
|
+
}
|
|
9283
|
+
current = path26.dirname(current);
|
|
9284
|
+
}
|
|
9285
|
+
cache.set(absolute, void 0);
|
|
8948
9286
|
return void 0;
|
|
9287
|
+
};
|
|
9288
|
+
}
|
|
9289
|
+
function readPackageIdentity(projectRoot, packageRoot) {
|
|
9290
|
+
const packagePath = toPosixRelative(projectRoot, packageRoot);
|
|
9291
|
+
if (!isSafePackageLockPath(packagePath)) {
|
|
9292
|
+
throw new Error(`unsupported dynamic island path: ${packagePath}`);
|
|
9293
|
+
}
|
|
9294
|
+
const manifest = readJsonObject(
|
|
9295
|
+
path26.join(packageRoot, "package.json"),
|
|
9296
|
+
`dynamic island ${packagePath}`
|
|
9297
|
+
);
|
|
9298
|
+
if (typeof manifest.name !== "string" || !manifest.name) {
|
|
9299
|
+
throw new Error(`dynamic island package name is invalid: ${packagePath}`);
|
|
8949
9300
|
}
|
|
9301
|
+
return { packagePath, packageName: manifest.name };
|
|
8950
9302
|
}
|
|
8951
|
-
function
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
|
|
8955
|
-
|
|
8956
|
-
throw new Error("isolated process birth identity unavailable");
|
|
9303
|
+
function addDynamicIsland(projectRoot, islands, packageRoot, reasons) {
|
|
9304
|
+
const existing = islands.get(packageRoot);
|
|
9305
|
+
if (existing) {
|
|
9306
|
+
for (const reason of reasons) existing.reasons.add(reason);
|
|
9307
|
+
return;
|
|
8957
9308
|
}
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
9309
|
+
const identity = readPackageIdentity(projectRoot, packageRoot);
|
|
9310
|
+
islands.set(packageRoot, {
|
|
9311
|
+
packageRoot,
|
|
9312
|
+
...identity,
|
|
9313
|
+
reasons: new Set(reasons)
|
|
8961
9314
|
});
|
|
8962
9315
|
}
|
|
8963
|
-
function
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
return false;
|
|
8976
|
-
} catch (error) {
|
|
8977
|
-
if (error.code !== "ESRCH") return false;
|
|
9316
|
+
function isBareSpecifier(specifier) {
|
|
9317
|
+
return !specifier.startsWith(".") && !specifier.startsWith("/") && !specifier.startsWith("file:");
|
|
9318
|
+
}
|
|
9319
|
+
function isBundleableResolvedFile(file) {
|
|
9320
|
+
const extension = path26.extname(file).toLowerCase();
|
|
9321
|
+
return extension === "" || extension === ".js" || extension === ".cjs" || extension === ".cts" || extension === ".mjs" || extension === ".mts" || extension === ".json" || extension === ".jsx" || extension === ".ts" || extension === ".tsx";
|
|
9322
|
+
}
|
|
9323
|
+
function retryIslandDiscovery(packagePath, reasons) {
|
|
9324
|
+
return {
|
|
9325
|
+
errors: [
|
|
9326
|
+
{
|
|
9327
|
+
text: `retry with dynamic island ${packagePath}: ${reasons.join(", ")}`
|
|
8978
9328
|
}
|
|
8979
|
-
|
|
8980
|
-
}
|
|
8981
|
-
try {
|
|
8982
|
-
process.kill(-registered.pid, 0);
|
|
8983
|
-
return true;
|
|
8984
|
-
} catch (error) {
|
|
8985
|
-
return error.code === "EPERM";
|
|
8986
|
-
}
|
|
9329
|
+
]
|
|
9330
|
+
};
|
|
8987
9331
|
}
|
|
8988
|
-
|
|
8989
|
-
const
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
9332
|
+
function hybridDynamicIslandPlugin(projectRoot, islands) {
|
|
9333
|
+
const packageOwner = createPackageOwnerResolver(projectRoot);
|
|
9334
|
+
const discover = (owner, reasons) => {
|
|
9335
|
+
addDynamicIsland(projectRoot, islands, owner, reasons);
|
|
9336
|
+
return retryIslandDiscovery(toPosixRelative(projectRoot, owner), reasons);
|
|
9337
|
+
};
|
|
9338
|
+
return {
|
|
9339
|
+
name: "miaoda-hybrid-dynamic-islands",
|
|
9340
|
+
setup(esbuild) {
|
|
9341
|
+
esbuild.onResolve({ filter: /.*/ }, async (args) => {
|
|
9342
|
+
const pluginData = args.pluginData;
|
|
9343
|
+
if (pluginData?.miaodaHybridSkip) return void 0;
|
|
9344
|
+
if (BUILTINS.has(args.path)) return { path: args.path, external: true };
|
|
9345
|
+
if (args.kind === "entry-point") return void 0;
|
|
9346
|
+
const importerOwner = args.importer ? packageOwner(args.importer) : void 0;
|
|
9347
|
+
const resolved = await esbuild.resolve(args.path, {
|
|
9348
|
+
importer: args.importer,
|
|
9349
|
+
kind: args.kind,
|
|
9350
|
+
namespace: args.namespace,
|
|
9351
|
+
resolveDir: args.resolveDir,
|
|
9352
|
+
pluginData: { miaodaHybridSkip: true }
|
|
9353
|
+
});
|
|
9354
|
+
if (resolved.errors.length > 0) {
|
|
9355
|
+
return importerOwner ? discover(importerOwner, [`resolves ${args.path} at runtime`]) : { errors: resolved.errors };
|
|
9356
|
+
}
|
|
9357
|
+
if (resolved.external) return resolved;
|
|
9358
|
+
const targetOwner = packageOwner(resolved.path);
|
|
9359
|
+
if (targetOwner && islands.has(targetOwner)) {
|
|
9360
|
+
if (isBareSpecifier(args.path)) {
|
|
9361
|
+
const targetIdentity = readPackageIdentity(
|
|
9362
|
+
projectRoot,
|
|
9363
|
+
targetOwner
|
|
9364
|
+
);
|
|
9365
|
+
if (args.kind === "import-statement" || args.kind === "dynamic-import") {
|
|
9366
|
+
if (importerOwner && importerOwner !== targetOwner) {
|
|
9367
|
+
return discover(importerOwner, [
|
|
9368
|
+
`preserves ESM import conditions for ${targetIdentity.packagePath}`
|
|
9369
|
+
]);
|
|
9370
|
+
}
|
|
9371
|
+
return {
|
|
9372
|
+
errors: [
|
|
9373
|
+
{
|
|
9374
|
+
text: `bundle entry cannot preserve ESM import conditions for dynamic island: ${targetIdentity.packagePath}`
|
|
9375
|
+
}
|
|
9376
|
+
]
|
|
9377
|
+
};
|
|
9378
|
+
}
|
|
9379
|
+
const rootPackagePath = `node_modules/${targetIdentity.packageName}`;
|
|
9380
|
+
if (targetIdentity.packagePath === rootPackagePath) {
|
|
9381
|
+
return { path: args.path, external: true };
|
|
9382
|
+
}
|
|
9383
|
+
if (importerOwner && importerOwner !== targetOwner) {
|
|
9384
|
+
return discover(importerOwner, [
|
|
9385
|
+
`resolves nested dynamic island ${targetIdentity.packagePath}`
|
|
9386
|
+
]);
|
|
9387
|
+
}
|
|
9388
|
+
return {
|
|
9389
|
+
errors: [
|
|
9390
|
+
{
|
|
9391
|
+
text: `bundle entry cannot preserve nested package resolution: ${targetIdentity.packagePath}`
|
|
9392
|
+
}
|
|
9393
|
+
]
|
|
9394
|
+
};
|
|
9395
|
+
}
|
|
9396
|
+
if (importerOwner && importerOwner !== targetOwner) {
|
|
9397
|
+
return discover(importerOwner, [
|
|
9398
|
+
`depends on dynamic island ${toPosixRelative(
|
|
9399
|
+
projectRoot,
|
|
9400
|
+
targetOwner
|
|
9401
|
+
)}`
|
|
9402
|
+
]);
|
|
9403
|
+
}
|
|
9404
|
+
if (!isBareSpecifier(args.path)) {
|
|
9405
|
+
return {
|
|
9406
|
+
errors: [
|
|
9407
|
+
{
|
|
9408
|
+
text: `application relative import crosses into dynamic island: ${args.path}`
|
|
9409
|
+
}
|
|
9410
|
+
]
|
|
9411
|
+
};
|
|
9412
|
+
}
|
|
9413
|
+
return { path: args.path, external: true };
|
|
9414
|
+
}
|
|
9415
|
+
if (targetOwner && resolved.path && !isBundleableResolvedFile(resolved.path)) {
|
|
9416
|
+
return discover(targetOwner, [
|
|
9417
|
+
`loads runtime asset ${path26.extname(resolved.path) || "<no extension>"}`
|
|
9418
|
+
]);
|
|
9419
|
+
}
|
|
9420
|
+
return resolved;
|
|
9421
|
+
});
|
|
9422
|
+
esbuild.onLoad(
|
|
9423
|
+
{ filter: /\.(?:cjs|cts|js|jsx|mjs|mts|ts|tsx)$/ },
|
|
9424
|
+
(args) => {
|
|
9425
|
+
const source = fs30.readFileSync(args.path, "utf8");
|
|
9426
|
+
const reasons = packageLayoutCapabilityReasons(source);
|
|
9427
|
+
if (reasons.length === 0) return void 0;
|
|
9428
|
+
const owner = packageOwner(args.path);
|
|
9429
|
+
if (owner) {
|
|
9430
|
+
if (/\.(?:cts|mts|ts|tsx)$/.test(args.path)) {
|
|
9431
|
+
const identity = readPackageIdentity(projectRoot, owner);
|
|
9432
|
+
return {
|
|
9433
|
+
errors: [
|
|
9434
|
+
{
|
|
9435
|
+
text: `TypeScript dependency requires package layout but is not directly executable: ${identity.packagePath}/${toPosixRelative(owner, args.path)}: ${reasons.join(", ")}`
|
|
9436
|
+
}
|
|
9437
|
+
]
|
|
9438
|
+
};
|
|
9439
|
+
}
|
|
9440
|
+
return discover(owner, reasons);
|
|
9441
|
+
}
|
|
9442
|
+
const applicationReasons = reasons.filter(
|
|
9443
|
+
(reason) => reason !== "uses filesystem APIs" && reason !== "uses filesystem path outside the proven package boundary"
|
|
9444
|
+
);
|
|
9445
|
+
if (applicationReasons.length === 0) return void 0;
|
|
9446
|
+
return {
|
|
9447
|
+
errors: [
|
|
9448
|
+
{
|
|
9449
|
+
text: `application startup code cannot preserve dynamic layout: ${toPosixRelative(
|
|
9450
|
+
projectRoot,
|
|
9451
|
+
args.path
|
|
9452
|
+
)}: ${applicationReasons.join(", ")}`
|
|
9453
|
+
}
|
|
9454
|
+
]
|
|
9455
|
+
};
|
|
9456
|
+
}
|
|
9457
|
+
);
|
|
9458
|
+
}
|
|
9459
|
+
};
|
|
8994
9460
|
}
|
|
8995
|
-
async function
|
|
8996
|
-
const
|
|
8997
|
-
|
|
8998
|
-
|
|
9461
|
+
async function buildHybridBundle(projectRoot, entryFile, outputFile) {
|
|
9462
|
+
const islands = /* @__PURE__ */ new Map();
|
|
9463
|
+
for (let pass = 0; pass < MAX_ISLAND_DISCOVERY_PASSES; pass += 1) {
|
|
9464
|
+
const before = islands.size;
|
|
9465
|
+
fs30.rmSync(outputFile, { force: true });
|
|
8999
9466
|
try {
|
|
9000
|
-
|
|
9001
|
-
|
|
9467
|
+
await build({
|
|
9468
|
+
absWorkingDir: projectRoot,
|
|
9469
|
+
entryPoints: [entryFile],
|
|
9470
|
+
outfile: outputFile,
|
|
9471
|
+
bundle: true,
|
|
9472
|
+
platform: "node",
|
|
9473
|
+
format: "cjs",
|
|
9474
|
+
target: `node${process.versions.node.split(".")[0]}`,
|
|
9475
|
+
keepNames: true,
|
|
9476
|
+
legalComments: "none",
|
|
9477
|
+
logLevel: "silent",
|
|
9478
|
+
preserveSymlinks: true,
|
|
9479
|
+
sourcemap: false,
|
|
9480
|
+
plugins: [hybridDynamicIslandPlugin(projectRoot, islands)]
|
|
9481
|
+
});
|
|
9482
|
+
return islands;
|
|
9483
|
+
} catch (error) {
|
|
9484
|
+
if (islands.size > before) continue;
|
|
9485
|
+
throw error;
|
|
9002
9486
|
}
|
|
9003
9487
|
}
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
9488
|
+
throw new Error(
|
|
9489
|
+
`dynamic island discovery exceeded ${MAX_ISLAND_DISCOVERY_PASSES} passes`
|
|
9490
|
+
);
|
|
9491
|
+
}
|
|
9492
|
+
function readDependencyState(projectRoot) {
|
|
9493
|
+
const packageFile = path26.join(projectRoot, "package.json");
|
|
9494
|
+
const lockFile = path26.join(projectRoot, "package-lock.json");
|
|
9495
|
+
const installedLockFile = path26.join(
|
|
9496
|
+
projectRoot,
|
|
9497
|
+
"node_modules",
|
|
9498
|
+
".package-lock.json"
|
|
9499
|
+
);
|
|
9500
|
+
for (const [file, description] of [
|
|
9501
|
+
[packageFile, "package.json"],
|
|
9502
|
+
[lockFile, "package-lock.json"],
|
|
9503
|
+
[installedLockFile, "installed node_modules lockfile"]
|
|
9504
|
+
]) {
|
|
9505
|
+
if (!fs30.existsSync(file) || fs30.lstatSync(file).isSymbolicLink()) {
|
|
9506
|
+
throw new Error(`${description} is unavailable`);
|
|
9507
|
+
}
|
|
9508
|
+
}
|
|
9509
|
+
const packageContents = readBoundedFile(
|
|
9510
|
+
packageFile,
|
|
9511
|
+
MAX_PACKAGE_MANIFEST_BYTES,
|
|
9512
|
+
"package.json"
|
|
9513
|
+
);
|
|
9514
|
+
const lockContents = readBoundedFile(
|
|
9515
|
+
lockFile,
|
|
9516
|
+
MAX_DEPENDENCY_METADATA_BYTES,
|
|
9517
|
+
"package-lock.json"
|
|
9518
|
+
);
|
|
9519
|
+
const installedLockContents = readBoundedFile(
|
|
9520
|
+
installedLockFile,
|
|
9521
|
+
MAX_DEPENDENCY_METADATA_BYTES,
|
|
9522
|
+
"installed node_modules lockfile"
|
|
9523
|
+
);
|
|
9524
|
+
const packageJson = readJsonObject(packageFile, "package.json");
|
|
9525
|
+
const rootLock = JSON.parse(lockContents.toString("utf8"));
|
|
9526
|
+
const installedLock = JSON.parse(
|
|
9527
|
+
installedLockContents.toString("utf8")
|
|
9528
|
+
);
|
|
9529
|
+
const rootPackages = lockPackages(rootLock, "package-lock.json");
|
|
9530
|
+
const installedPackages = lockPackages(
|
|
9531
|
+
installedLock,
|
|
9532
|
+
"installed node_modules lockfile"
|
|
9533
|
+
);
|
|
9534
|
+
const rootRecord = rootPackages[""];
|
|
9535
|
+
if (!rootRecord) throw new Error("package-lock.json root package is missing");
|
|
9536
|
+
for (const field of ["dependencies", "optionalDependencies"]) {
|
|
9537
|
+
const declared = packageJson[field] ?? {};
|
|
9538
|
+
const locked = rootRecord[field] ?? {};
|
|
9539
|
+
if (stableJson(declared) !== stableJson(locked)) {
|
|
9540
|
+
throw new Error(`package.json and package-lock.json ${field} disagree`);
|
|
9541
|
+
}
|
|
9542
|
+
}
|
|
9543
|
+
let declaredDynamicDependencies;
|
|
9544
|
+
const startupConfig = packageJson.miaodaStartupBundle;
|
|
9545
|
+
if (startupConfig !== void 0) {
|
|
9546
|
+
if (!startupConfig || typeof startupConfig !== "object" || Array.isArray(startupConfig)) {
|
|
9547
|
+
throw new Error("package.json miaodaStartupBundle must be an object");
|
|
9548
|
+
}
|
|
9549
|
+
const configured = startupConfig.dynamicDependencies;
|
|
9550
|
+
if (!Array.isArray(configured) || configured.some((item) => typeof item !== "string")) {
|
|
9551
|
+
throw new Error(
|
|
9552
|
+
"package.json miaodaStartupBundle.dynamicDependencies must be a string array"
|
|
9553
|
+
);
|
|
9010
9554
|
}
|
|
9011
|
-
|
|
9555
|
+
declaredDynamicDependencies = [...new Set(configured)].sort();
|
|
9556
|
+
if (declaredDynamicDependencies.length !== configured.length) {
|
|
9012
9557
|
throw new Error(
|
|
9013
|
-
|
|
9558
|
+
"package.json miaodaStartupBundle.dynamicDependencies contains duplicates"
|
|
9014
9559
|
);
|
|
9015
9560
|
}
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9561
|
+
const rootRuntimeDependencies = /* @__PURE__ */ new Set([
|
|
9562
|
+
...Object.keys(stringRecord(packageJson.dependencies)),
|
|
9563
|
+
...Object.keys(stringRecord(packageJson.optionalDependencies))
|
|
9564
|
+
]);
|
|
9565
|
+
for (const dependencyName of declaredDynamicDependencies) {
|
|
9566
|
+
packageNameSegments(dependencyName);
|
|
9567
|
+
if (!rootRuntimeDependencies.has(dependencyName)) {
|
|
9568
|
+
throw new Error(
|
|
9569
|
+
`declared startup dynamic dependency is not a root runtime dependency: ${dependencyName}`
|
|
9570
|
+
);
|
|
9571
|
+
}
|
|
9027
9572
|
}
|
|
9028
9573
|
}
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9574
|
+
return {
|
|
9575
|
+
packageJson,
|
|
9576
|
+
packageContents,
|
|
9577
|
+
lockContents,
|
|
9578
|
+
rootPackages,
|
|
9579
|
+
installedPackages,
|
|
9580
|
+
declaredDynamicDependencies
|
|
9581
|
+
};
|
|
9582
|
+
}
|
|
9583
|
+
function manifestContainsRuntimeTypeScript(value) {
|
|
9584
|
+
if (typeof value === "string") {
|
|
9585
|
+
return /\.(?:cts|mts|ts|tsx)(?:$|[?#])/.test(value);
|
|
9033
9586
|
}
|
|
9034
|
-
if (
|
|
9035
|
-
|
|
9036
|
-
if (
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
throw new Error("Nest TypeScript config escaped project root");
|
|
9587
|
+
if (Array.isArray(value))
|
|
9588
|
+
return value.some(manifestContainsRuntimeTypeScript);
|
|
9589
|
+
if (value && typeof value === "object") {
|
|
9590
|
+
return Object.entries(value).some(
|
|
9591
|
+
([condition, target]) => condition !== "types" && !condition.startsWith("types@") && manifestContainsRuntimeTypeScript(target)
|
|
9592
|
+
);
|
|
9041
9593
|
}
|
|
9042
|
-
return
|
|
9594
|
+
return false;
|
|
9043
9595
|
}
|
|
9044
|
-
function
|
|
9045
|
-
|
|
9046
|
-
|
|
9596
|
+
function isPackageDevelopmentFile(relativeFile) {
|
|
9597
|
+
const segments = relativeFile.split("/");
|
|
9598
|
+
return segments.some(
|
|
9599
|
+
(segment) => /^(?:__tests__|bench(?:mark)?s?|fixtures?|tests?)$/i.test(segment)
|
|
9600
|
+
) || /(?:^|\.)\b(?:spec|test)\.[cm]?[jt]sx?$/.test(path26.basename(relativeFile));
|
|
9601
|
+
}
|
|
9602
|
+
function createMaterializedPackageAuditor(packageRoot, identity) {
|
|
9603
|
+
if (manifestContainsRuntimeTypeScript(identity.manifest.main) || manifestContainsRuntimeTypeScript(identity.manifest.exports) || manifestContainsRuntimeTypeScript(identity.manifest.bin)) {
|
|
9604
|
+
throw new Error(
|
|
9605
|
+
`TypeScript dependency is not directly executable in the startup runtime: ${identity.packagePath}`
|
|
9606
|
+
);
|
|
9047
9607
|
}
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
const records = /* @__PURE__ */ new Map();
|
|
9063
|
-
for (const inputFile of inputFiles) {
|
|
9064
|
-
if (!fs29.existsSync(inputFile)) continue;
|
|
9065
|
-
if (fs29.lstatSync(inputFile).isSymbolicLink()) {
|
|
9066
|
-
throw new Error(
|
|
9067
|
-
`source input symlink is unsupported: ${path25.relative(projectRoot, inputFile)}`
|
|
9608
|
+
let runtimeTypeScriptFile;
|
|
9609
|
+
let packageRelativeDynamicLoader;
|
|
9610
|
+
return {
|
|
9611
|
+
inspect(candidate) {
|
|
9612
|
+
const name = path26.basename(candidate);
|
|
9613
|
+
const relativeFile = toPosixRelative(packageRoot, candidate);
|
|
9614
|
+
if (isPackageDevelopmentFile(relativeFile)) return;
|
|
9615
|
+
if (/\.(?:cts|mts|ts|tsx)$/.test(name) && !/\.d\.(?:cts|mts|ts)$/.test(name)) {
|
|
9616
|
+
runtimeTypeScriptFile ?? (runtimeTypeScriptFile = relativeFile);
|
|
9617
|
+
return;
|
|
9618
|
+
}
|
|
9619
|
+
if (!/\.(?:cjs|js|jsx|mjs)$/.test(name)) return;
|
|
9620
|
+
const reasons = packageLayoutCapabilityReasons(
|
|
9621
|
+
fs30.readFileSync(candidate, "utf8")
|
|
9068
9622
|
);
|
|
9623
|
+
for (const reason of reasons) {
|
|
9624
|
+
if (reason === "loads runtime TypeScript") {
|
|
9625
|
+
throw new Error(
|
|
9626
|
+
`TypeScript dependency is not directly executable in the startup runtime: ${identity.packagePath}/${toPosixRelative(packageRoot, candidate)}`
|
|
9627
|
+
);
|
|
9628
|
+
}
|
|
9629
|
+
if (reason.startsWith("uses package-relative dynamic")) {
|
|
9630
|
+
packageRelativeDynamicLoader ?? (packageRelativeDynamicLoader = relativeFile);
|
|
9631
|
+
}
|
|
9632
|
+
if (reason === "uses filesystem path outside the proven package boundary") {
|
|
9633
|
+
throw new Error(
|
|
9634
|
+
`filesystem access escapes the startup island boundary: ${identity.packagePath}/${toPosixRelative(packageRoot, candidate)}`
|
|
9635
|
+
);
|
|
9636
|
+
}
|
|
9637
|
+
if (reason === "uses unbounded dynamic import" || reason === "uses eval-generated code" || reason === "uses VM code evaluation" || reason === "uses native dynamic loader") {
|
|
9638
|
+
throw new Error(
|
|
9639
|
+
`startup island uses an unsupported executable loader: ${identity.packagePath}/${toPosixRelative(packageRoot, candidate)}: ${reason}`
|
|
9640
|
+
);
|
|
9641
|
+
}
|
|
9642
|
+
}
|
|
9643
|
+
},
|
|
9644
|
+
assertComplete() {
|
|
9645
|
+
if (runtimeTypeScriptFile && packageRelativeDynamicLoader) {
|
|
9646
|
+
throw new Error(
|
|
9647
|
+
`package-relative dynamic loader may select non-executable TypeScript: ${identity.packagePath}/${packageRelativeDynamicLoader} -> ${runtimeTypeScriptFile}`
|
|
9648
|
+
);
|
|
9649
|
+
}
|
|
9069
9650
|
}
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9651
|
+
};
|
|
9652
|
+
}
|
|
9653
|
+
function packageNameSegments(name) {
|
|
9654
|
+
const segments = name.split("/");
|
|
9655
|
+
if (name.startsWith("@") && segments.length !== 2 || !name.startsWith("@") && segments.length !== 1 || segments.some((segment) => !segment || segment === "." || segment === "..")) {
|
|
9656
|
+
throw new Error(`unsupported dependency package name: ${name}`);
|
|
9657
|
+
}
|
|
9658
|
+
return segments;
|
|
9659
|
+
}
|
|
9660
|
+
function resolveInstalledDependencyRoot(projectRoot, packageRoot, dependencyName) {
|
|
9661
|
+
const segments = packageNameSegments(dependencyName);
|
|
9662
|
+
let current = packageRoot;
|
|
9663
|
+
while (isInside(projectRoot, current)) {
|
|
9664
|
+
const candidate = path26.join(current, "node_modules", ...segments);
|
|
9665
|
+
if (fs30.existsSync(candidate)) {
|
|
9666
|
+
if (fs30.lstatSync(candidate).isSymbolicLink()) {
|
|
9667
|
+
throw new Error(
|
|
9668
|
+
`linked runtime dependency is unsupported: ${toPosixRelative(
|
|
9669
|
+
projectRoot,
|
|
9670
|
+
candidate
|
|
9671
|
+
)}`
|
|
9672
|
+
);
|
|
9673
|
+
}
|
|
9674
|
+
if (fs30.statSync(candidate).isDirectory() && fs30.existsSync(path26.join(candidate, "package.json"))) {
|
|
9675
|
+
return candidate;
|
|
9676
|
+
}
|
|
9073
9677
|
}
|
|
9074
|
-
const
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
path: relative,
|
|
9078
|
-
sha256: sha256(contents),
|
|
9079
|
-
size: contents.length
|
|
9080
|
-
});
|
|
9678
|
+
const parent = path26.dirname(current);
|
|
9679
|
+
if (parent === current) break;
|
|
9680
|
+
current = parent;
|
|
9081
9681
|
}
|
|
9082
|
-
return
|
|
9083
|
-
|
|
9682
|
+
return void 0;
|
|
9683
|
+
}
|
|
9684
|
+
function stringRecord(value) {
|
|
9685
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
9686
|
+
return Object.fromEntries(
|
|
9687
|
+
Object.entries(value).filter(
|
|
9688
|
+
(entry) => typeof entry[1] === "string"
|
|
9689
|
+
)
|
|
9084
9690
|
);
|
|
9085
9691
|
}
|
|
9086
|
-
function
|
|
9087
|
-
const
|
|
9088
|
-
|
|
9089
|
-
|
|
9692
|
+
function validateInstalledPackage(projectRoot, packageRoot, state) {
|
|
9693
|
+
const { packagePath, packageName } = readPackageIdentity(
|
|
9694
|
+
projectRoot,
|
|
9695
|
+
packageRoot
|
|
9090
9696
|
);
|
|
9091
|
-
const
|
|
9092
|
-
const
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
|
|
9697
|
+
const locked = state.rootPackages[packagePath];
|
|
9698
|
+
const installed = state.installedPackages[packagePath];
|
|
9699
|
+
if (!locked)
|
|
9700
|
+
throw new Error(`package is absent from lockfile: ${packagePath}`);
|
|
9701
|
+
if (locked.link === true) {
|
|
9702
|
+
throw new Error(`linked runtime package is unsupported: ${packagePath}`);
|
|
9703
|
+
}
|
|
9704
|
+
if (!installed || stableJson(comparableLockRecord(installed)) !== stableJson(comparableLockRecord(locked))) {
|
|
9705
|
+
throw new Error(
|
|
9706
|
+
`installed package does not match lockfile: ${packagePath}`
|
|
9100
9707
|
);
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
for (const requested of extended) {
|
|
9106
|
-
if (typeof requested !== "string") continue;
|
|
9107
|
-
const local = resolveLocalTsconfigReference(
|
|
9108
|
-
projectRoot,
|
|
9109
|
-
realConfig,
|
|
9110
|
-
requested
|
|
9111
|
-
);
|
|
9112
|
-
if (local) visitConfig(local);
|
|
9113
|
-
}
|
|
9114
|
-
for (const reference of loaded2.config?.references ?? []) {
|
|
9115
|
-
if (typeof reference?.path !== "string") continue;
|
|
9116
|
-
const local = resolveLocalTsconfigReference(
|
|
9117
|
-
projectRoot,
|
|
9118
|
-
realConfig,
|
|
9119
|
-
reference.path
|
|
9120
|
-
);
|
|
9121
|
-
if (local) visitConfig(local);
|
|
9122
|
-
}
|
|
9123
|
-
};
|
|
9124
|
-
visitConfig(sourceConfig);
|
|
9125
|
-
const loaded = typescript.readConfigFile(
|
|
9126
|
-
sourceConfig,
|
|
9127
|
-
typescript.sys.readFile
|
|
9128
|
-
);
|
|
9129
|
-
if (loaded.error) {
|
|
9130
|
-
throw new Error(`TypeScript config cannot be read: ${sourceConfig}`);
|
|
9131
|
-
}
|
|
9132
|
-
const parsed = typescript.parseJsonConfigFileContent(
|
|
9133
|
-
loaded.config,
|
|
9134
|
-
typescript.sys,
|
|
9135
|
-
path25.dirname(sourceConfig),
|
|
9136
|
-
{ noEmit: true, incremental: false, composite: false },
|
|
9137
|
-
sourceConfig
|
|
9708
|
+
}
|
|
9709
|
+
const manifest = readJsonObject(
|
|
9710
|
+
path26.join(packageRoot, "package.json"),
|
|
9711
|
+
`installed package ${packagePath}`
|
|
9138
9712
|
);
|
|
9139
|
-
if (
|
|
9140
|
-
throw new Error(
|
|
9713
|
+
if (manifest.name !== packageName) {
|
|
9714
|
+
throw new Error(
|
|
9715
|
+
`installed package name does not match path: ${packagePath}`
|
|
9716
|
+
);
|
|
9141
9717
|
}
|
|
9142
|
-
const
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
projectReferences: parsed.projectReferences
|
|
9146
|
-
});
|
|
9147
|
-
const inputs = new Set(configFiles);
|
|
9148
|
-
for (const sourceFile of program.getSourceFiles()) {
|
|
9149
|
-
if (!fs29.existsSync(sourceFile.fileName)) continue;
|
|
9150
|
-
const realFile = fs29.realpathSync(sourceFile.fileName);
|
|
9151
|
-
const relative = path25.relative(projectRoot, realFile);
|
|
9152
|
-
if (isInside(projectRoot, realFile) && !relative.split(path25.sep).includes("node_modules")) {
|
|
9153
|
-
inputs.add(realFile);
|
|
9154
|
-
}
|
|
9718
|
+
const version = manifest.version;
|
|
9719
|
+
if (typeof version !== "string" || !version) {
|
|
9720
|
+
throw new Error(`installed package version is invalid: ${packagePath}`);
|
|
9155
9721
|
}
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9722
|
+
if (typeof locked.version === "string" && locked.version !== version) {
|
|
9723
|
+
throw new Error(
|
|
9724
|
+
`installed package version does not match lockfile: ${packagePath}`
|
|
9725
|
+
);
|
|
9159
9726
|
}
|
|
9160
|
-
return
|
|
9161
|
-
}
|
|
9162
|
-
function sourceIdentitySha256(workspaceTreeSha256, sourceInputs) {
|
|
9163
|
-
return sha256(JSON.stringify({ sourceInputs, workspaceTreeSha256 }));
|
|
9727
|
+
return { packagePath, packageName, version, manifest };
|
|
9164
9728
|
}
|
|
9165
|
-
function
|
|
9166
|
-
const
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
|
|
9729
|
+
function materializeDynamicIslands(projectRoot, payloadRoot, islands) {
|
|
9730
|
+
const state = readDependencyState(projectRoot);
|
|
9731
|
+
if (islands.size > 0 && state.declaredDynamicDependencies === void 0) {
|
|
9732
|
+
throw new Error(
|
|
9733
|
+
"startup bundle with dynamic islands requires package.json miaodaStartupBundle.dynamicDependencies (use [] when no non-relative dynamic package is allowed)"
|
|
9734
|
+
);
|
|
9735
|
+
}
|
|
9736
|
+
const queue = [...islands.values()].sort((left, right) => left.packagePath.localeCompare(right.packagePath)).map((island) => island.packageRoot);
|
|
9737
|
+
const dynamicDependencies = [];
|
|
9738
|
+
for (const dependencyName of state.declaredDynamicDependencies ?? []) {
|
|
9739
|
+
const dependencyRoot = resolveInstalledDependencyRoot(
|
|
9740
|
+
projectRoot,
|
|
9741
|
+
projectRoot,
|
|
9742
|
+
dependencyName
|
|
9743
|
+
);
|
|
9744
|
+
if (!dependencyRoot) {
|
|
9180
9745
|
throw new Error(
|
|
9181
|
-
`
|
|
9746
|
+
`declared startup dynamic dependency is not installed: ${dependencyName}`
|
|
9182
9747
|
);
|
|
9183
9748
|
}
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
let output = "";
|
|
9188
|
-
child[stream]?.setEncoding("utf8");
|
|
9189
|
-
child[stream]?.on("data", (chunk) => {
|
|
9190
|
-
output = `${output}${String(chunk)}`.slice(-64 * 1024);
|
|
9191
|
-
});
|
|
9192
|
-
return () => output;
|
|
9193
|
-
}
|
|
9194
|
-
async function waitForCommand(child, timeoutMs, description) {
|
|
9195
|
-
let timer;
|
|
9196
|
-
try {
|
|
9197
|
-
return await new Promise((resolve2, reject) => {
|
|
9198
|
-
let settled = false;
|
|
9199
|
-
const finish = (callback) => {
|
|
9200
|
-
if (settled) return;
|
|
9201
|
-
settled = true;
|
|
9202
|
-
if (timer) clearTimeout(timer);
|
|
9203
|
-
callback();
|
|
9204
|
-
};
|
|
9205
|
-
child.once("error", (error) => finish(() => reject(error)));
|
|
9206
|
-
child.once(
|
|
9207
|
-
"exit",
|
|
9208
|
-
(code, signal) => finish(
|
|
9209
|
-
() => signal ? reject(new Error(`${description} exited by ${signal}`)) : resolve2(code ?? 1)
|
|
9210
|
-
)
|
|
9211
|
-
);
|
|
9212
|
-
timer = setTimeout(
|
|
9213
|
-
() => finish(() => reject(new Error(`${description} timeout`))),
|
|
9214
|
-
timeoutMs
|
|
9215
|
-
);
|
|
9749
|
+
dynamicDependencies.push({
|
|
9750
|
+
specifier: dependencyName,
|
|
9751
|
+
resolvedPackagePath: readPackageIdentity(projectRoot, dependencyRoot).packagePath
|
|
9216
9752
|
});
|
|
9217
|
-
|
|
9218
|
-
if (timer) clearTimeout(timer);
|
|
9753
|
+
queue.push(dependencyRoot);
|
|
9219
9754
|
}
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
const
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
fs29.writeFileSync(
|
|
9228
|
-
isolatedConfig,
|
|
9229
|
-
`${JSON.stringify(
|
|
9230
|
-
{
|
|
9231
|
-
extends: sourceConfig,
|
|
9232
|
-
compilerOptions: {
|
|
9233
|
-
outDir: outputRoot,
|
|
9234
|
-
incremental: false,
|
|
9235
|
-
composite: false,
|
|
9236
|
-
declaration: false,
|
|
9237
|
-
declarationMap: false,
|
|
9238
|
-
sourceMap: false,
|
|
9239
|
-
inlineSourceMap: false
|
|
9240
|
-
}
|
|
9241
|
-
},
|
|
9242
|
-
null,
|
|
9243
|
-
2
|
|
9244
|
-
)}
|
|
9755
|
+
const visited = /* @__PURE__ */ new Set();
|
|
9756
|
+
const materializedPackages = [];
|
|
9757
|
+
const selectedLockRecords = [];
|
|
9758
|
+
fs30.mkdirSync(payloadRoot, { recursive: true, mode: 493 });
|
|
9759
|
+
fs30.writeFileSync(
|
|
9760
|
+
path26.join(payloadRoot, "package.json"),
|
|
9761
|
+
`${JSON.stringify({ private: true, type: "commonjs" })}
|
|
9245
9762
|
`,
|
|
9246
|
-
{ mode:
|
|
9247
|
-
);
|
|
9248
|
-
const child = spawn2(
|
|
9249
|
-
process.execPath,
|
|
9250
|
-
[cliFile, "build", "--path", path25.relative(projectRoot, isolatedConfig)],
|
|
9251
|
-
{
|
|
9252
|
-
cwd: projectRoot,
|
|
9253
|
-
detached: true,
|
|
9254
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
9255
|
-
env: { ...process.env, NODE_ENV: "production" }
|
|
9256
|
-
}
|
|
9763
|
+
{ mode: 420 }
|
|
9257
9764
|
);
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9765
|
+
const budget = measurePayload(payloadRoot);
|
|
9766
|
+
while (queue.length > 0) {
|
|
9767
|
+
const packageRoot = queue.shift();
|
|
9768
|
+
if (visited.has(packageRoot)) continue;
|
|
9769
|
+
visited.add(packageRoot);
|
|
9770
|
+
const identity = validateInstalledPackage(projectRoot, packageRoot, state);
|
|
9771
|
+
const auditor = createMaterializedPackageAuditor(packageRoot, identity);
|
|
9772
|
+
copyDirectoryContents(
|
|
9773
|
+
packageRoot,
|
|
9774
|
+
path26.join(payloadRoot, ...identity.packagePath.split("/")),
|
|
9775
|
+
true,
|
|
9776
|
+
budget,
|
|
9777
|
+
auditor.inspect
|
|
9266
9778
|
);
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9779
|
+
auditor.assertComplete();
|
|
9780
|
+
const island = islands.has(packageRoot);
|
|
9781
|
+
materializedPackages.push({
|
|
9782
|
+
packagePath: identity.packagePath,
|
|
9783
|
+
packageName: identity.packageName,
|
|
9784
|
+
version: identity.version,
|
|
9785
|
+
island
|
|
9786
|
+
});
|
|
9787
|
+
selectedLockRecords.push({
|
|
9788
|
+
path: identity.packagePath,
|
|
9789
|
+
record: comparableLockRecord(state.rootPackages[identity.packagePath])
|
|
9790
|
+
});
|
|
9791
|
+
const dependencies = stringRecord(identity.manifest.dependencies);
|
|
9792
|
+
const optionalDependencies = stringRecord(
|
|
9793
|
+
identity.manifest.optionalDependencies
|
|
9794
|
+
);
|
|
9795
|
+
const peerDependencies = stringRecord(identity.manifest.peerDependencies);
|
|
9796
|
+
const peerMetadata = identity.manifest.peerDependenciesMeta && typeof identity.manifest.peerDependenciesMeta === "object" && !Array.isArray(identity.manifest.peerDependenciesMeta) ? identity.manifest.peerDependenciesMeta : {};
|
|
9797
|
+
for (const dependencyName of [
|
|
9798
|
+
.../* @__PURE__ */ new Set([
|
|
9799
|
+
...Object.keys(dependencies),
|
|
9800
|
+
...Object.keys(optionalDependencies),
|
|
9801
|
+
...Object.keys(peerDependencies)
|
|
9802
|
+
])
|
|
9803
|
+
].sort()) {
|
|
9804
|
+
const dependencyRoot = resolveInstalledDependencyRoot(
|
|
9805
|
+
projectRoot,
|
|
9806
|
+
packageRoot,
|
|
9807
|
+
dependencyName
|
|
9808
|
+
);
|
|
9809
|
+
const peerConfig = peerMetadata[dependencyName];
|
|
9810
|
+
const optionalPeer = Boolean(
|
|
9811
|
+
peerConfig && typeof peerConfig === "object" && peerConfig.optional === true
|
|
9270
9812
|
);
|
|
9813
|
+
const optional = Object.hasOwn(optionalDependencies, dependencyName) || optionalPeer;
|
|
9814
|
+
if (!dependencyRoot) {
|
|
9815
|
+
if (optional) continue;
|
|
9816
|
+
throw new Error(
|
|
9817
|
+
`runtime dependency is not installed: ${identity.packagePath} -> ${dependencyName}`
|
|
9818
|
+
);
|
|
9819
|
+
}
|
|
9820
|
+
queue.push(dependencyRoot);
|
|
9271
9821
|
}
|
|
9272
|
-
} finally {
|
|
9273
|
-
await stopProbe(child);
|
|
9274
|
-
}
|
|
9275
|
-
const candidates = [
|
|
9276
|
-
path25.join(outputRoot, "server", "main.js"),
|
|
9277
|
-
path25.join(outputRoot, "main.js")
|
|
9278
|
-
].filter((candidate) => fs29.existsSync(candidate));
|
|
9279
|
-
if (candidates.length !== 1) {
|
|
9280
|
-
throw new Error(
|
|
9281
|
-
candidates.length === 0 ? "isolated Nest compiled entry missing; checked server/main.js and main.js" : "isolated Nest compiled entry is ambiguous"
|
|
9282
|
-
);
|
|
9283
|
-
}
|
|
9284
|
-
const entry = fs29.realpathSync(candidates[0]);
|
|
9285
|
-
if (!isInside(fs29.realpathSync(outputRoot), entry) || !fs29.statSync(entry).isFile()) {
|
|
9286
|
-
throw new Error("isolated Nest compiled entry escaped output root");
|
|
9287
9822
|
}
|
|
9823
|
+
materializedPackages.sort(
|
|
9824
|
+
(left, right) => left.packagePath.localeCompare(right.packagePath)
|
|
9825
|
+
);
|
|
9826
|
+
selectedLockRecords.sort(
|
|
9827
|
+
(left, right) => left.path.localeCompare(right.path)
|
|
9828
|
+
);
|
|
9829
|
+
return {
|
|
9830
|
+
lockfileSha256: sha256(state.lockContents),
|
|
9831
|
+
dependencyViewSha256: sha256(
|
|
9832
|
+
stableJson({
|
|
9833
|
+
packageJsonSha256: sha256(state.packageContents),
|
|
9834
|
+
lockfileSha256: sha256(state.lockContents),
|
|
9835
|
+
runtime: runtimeIdentity(),
|
|
9836
|
+
selectedLockRecords
|
|
9837
|
+
})
|
|
9838
|
+
),
|
|
9839
|
+
materializedPackages,
|
|
9840
|
+
dynamicDependencies
|
|
9841
|
+
};
|
|
9842
|
+
}
|
|
9843
|
+
function indexPayload(payloadRoot) {
|
|
9844
|
+
const files = [];
|
|
9845
|
+
const budget = { fileCount: 0, totalBytes: 0 };
|
|
9846
|
+
const visit = (directory) => {
|
|
9847
|
+
for (const entry of fs30.readdirSync(directory, { withFileTypes: true })) {
|
|
9848
|
+
const candidate = path26.join(directory, entry.name);
|
|
9849
|
+
if (entry.isSymbolicLink()) {
|
|
9850
|
+
throw new Error(`generation symlink is unsupported: ${candidate}`);
|
|
9851
|
+
}
|
|
9852
|
+
if (entry.isDirectory()) {
|
|
9853
|
+
visit(candidate);
|
|
9854
|
+
continue;
|
|
9855
|
+
}
|
|
9856
|
+
if (!entry.isFile()) {
|
|
9857
|
+
throw new Error(`generation special file is unsupported: ${candidate}`);
|
|
9858
|
+
}
|
|
9859
|
+
const stats = fs30.lstatSync(candidate);
|
|
9860
|
+
if (!stats.isFile()) {
|
|
9861
|
+
throw new Error(`generation special file is unsupported: ${candidate}`);
|
|
9862
|
+
}
|
|
9863
|
+
reserveGenerationBudget(candidate, stats.size, budget);
|
|
9864
|
+
const contents = fs30.readFileSync(candidate);
|
|
9865
|
+
if (contents.length !== stats.size) {
|
|
9866
|
+
throw new Error(
|
|
9867
|
+
`generation file changed while indexing: ${toPosixRelative(payloadRoot, candidate)}`
|
|
9868
|
+
);
|
|
9869
|
+
}
|
|
9870
|
+
files.push({
|
|
9871
|
+
path: `payload/${toPosixRelative(payloadRoot, candidate)}`,
|
|
9872
|
+
sha256: sha256(contents),
|
|
9873
|
+
size: contents.length,
|
|
9874
|
+
mode: stats.mode & 511
|
|
9875
|
+
});
|
|
9876
|
+
}
|
|
9877
|
+
};
|
|
9878
|
+
visit(payloadRoot);
|
|
9879
|
+
files.sort((left, right) => left.path.localeCompare(right.path));
|
|
9288
9880
|
return {
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9881
|
+
files,
|
|
9882
|
+
treeSha256: sha256(stableJson(files)),
|
|
9883
|
+
totalBytes: budget.totalBytes
|
|
9292
9884
|
};
|
|
9293
9885
|
}
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9886
|
+
function reservePort() {
|
|
9887
|
+
return new Promise((resolve2, reject) => {
|
|
9888
|
+
const server = net.createServer();
|
|
9889
|
+
server.once("error", reject);
|
|
9890
|
+
server.listen(0, "127.0.0.1", () => {
|
|
9891
|
+
const address = server.address();
|
|
9892
|
+
if (!address || typeof address === "string") {
|
|
9893
|
+
server.close(
|
|
9894
|
+
() => reject(new Error("isolated probe failed to reserve a port"))
|
|
9895
|
+
);
|
|
9896
|
+
return;
|
|
9897
|
+
}
|
|
9898
|
+
server.close((error) => error ? reject(error) : resolve2(address.port));
|
|
9899
|
+
});
|
|
9900
|
+
});
|
|
9901
|
+
}
|
|
9902
|
+
async function isolatedProbe(projectRoot, payloadRoot, entry, timeoutMs) {
|
|
9903
|
+
const probeRoot = fs30.mkdtempSync(
|
|
9904
|
+
path26.join(os3.tmpdir(), "miaoda-server-generation-probe-")
|
|
9905
|
+
);
|
|
9906
|
+
const probeWorkspaceRoot = path26.join(probeRoot, "workspace");
|
|
9907
|
+
const probeProjectRoot = path26.join(probeWorkspaceRoot, "code");
|
|
9908
|
+
copyProbeWorkspace(projectRoot, probeProjectRoot);
|
|
9909
|
+
const probeGenerationRoot = path26.join(
|
|
9910
|
+
probeProjectRoot,
|
|
9911
|
+
".miaoda-cache",
|
|
9912
|
+
"server",
|
|
9913
|
+
"generations",
|
|
9914
|
+
"probe"
|
|
9915
|
+
);
|
|
9916
|
+
const probePayload = path26.join(probeGenerationRoot, "payload");
|
|
9917
|
+
copyDirectoryContents(payloadRoot, probePayload, false);
|
|
9918
|
+
const probeEntry = path26.join(probeGenerationRoot, ...entry.split("/"));
|
|
9919
|
+
const probeModuleGuard = path26.join(
|
|
9920
|
+
probePayload,
|
|
9921
|
+
"module-resolution-guard.cjs"
|
|
9297
9922
|
);
|
|
9298
|
-
const probeBundle = path25.join(probeRoot, "server.bundle.cjs");
|
|
9299
|
-
fs29.copyFileSync(bundleFile, probeBundle);
|
|
9300
9923
|
const port = await reservePort();
|
|
9301
9924
|
const configuredBasePath = process.env.CLIENT_BASE_PATH;
|
|
9302
9925
|
const basePath = configuredBasePath?.startsWith("/") && !configuredBasePath.startsWith("//") ? configuredBasePath.replace(/\/+$/, "") : "";
|
|
9303
9926
|
const readinessPath = `${basePath}/__innerapi__/capability/list`;
|
|
9304
9927
|
const startedAt = Date.now();
|
|
9305
|
-
const child = spawn2(process.execPath, [
|
|
9306
|
-
cwd:
|
|
9928
|
+
const child = spawn2(process.execPath, [probeEntry], {
|
|
9929
|
+
cwd: probeProjectRoot,
|
|
9307
9930
|
detached: true,
|
|
9308
9931
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9309
9932
|
env: {
|
|
9310
9933
|
...process.env,
|
|
9311
|
-
NODE_PATH: "",
|
|
9934
|
+
NODE_PATH: path26.join(probePayload, "node_modules"),
|
|
9935
|
+
NODE_OPTIONS: `--require=${JSON.stringify(probeModuleGuard)}`,
|
|
9936
|
+
PWD: probeProjectRoot,
|
|
9937
|
+
WORKSPACE_DIR: probeWorkspaceRoot,
|
|
9938
|
+
MIAODA_WORKSPACE_ROOT: probeProjectRoot,
|
|
9312
9939
|
NODE_ENV: "development",
|
|
9313
9940
|
SERVER_HOST: "127.0.0.1",
|
|
9314
9941
|
SERVER_PORT: String(port),
|
|
@@ -9320,26 +9947,15 @@ async function isolatedProbe(bundleFile, timeoutMs) {
|
|
|
9320
9947
|
}
|
|
9321
9948
|
});
|
|
9322
9949
|
registerProbe(child);
|
|
9323
|
-
|
|
9324
|
-
|
|
9325
|
-
child.stdout?.setEncoding("utf8");
|
|
9326
|
-
child.stdout?.on("data", (chunk) => {
|
|
9327
|
-
stdout = `${stdout}${String(chunk)}`.slice(-64 * 1024);
|
|
9328
|
-
});
|
|
9329
|
-
child.stderr?.setEncoding("utf8");
|
|
9330
|
-
child.stderr?.on("data", (chunk) => {
|
|
9331
|
-
stderr += String(chunk);
|
|
9332
|
-
});
|
|
9950
|
+
const stdout = collectChildOutput(child, "stdout");
|
|
9951
|
+
const stderr = collectChildOutput(child, "stderr");
|
|
9333
9952
|
try {
|
|
9334
9953
|
await new Promise((resolve2, reject) => {
|
|
9335
9954
|
const deadline = Date.now() + timeoutMs;
|
|
9336
|
-
const timeoutError = () => new Error(
|
|
9337
|
-
`isolated bundle readiness timeout${`${stderr}
|
|
9338
|
-
${stdout}`.trim() ? `: ${`${stderr}
|
|
9339
|
-
${stdout}`.trim()}` : ""}`
|
|
9340
|
-
);
|
|
9341
9955
|
let settled = false;
|
|
9342
9956
|
let retryTimer;
|
|
9957
|
+
const detail = () => `${stderr()}
|
|
9958
|
+
${stdout()}`.trim();
|
|
9343
9959
|
const finish = (error) => {
|
|
9344
9960
|
if (settled) return;
|
|
9345
9961
|
settled = true;
|
|
@@ -9348,10 +9964,13 @@ ${stdout}`.trim()}` : ""}`
|
|
|
9348
9964
|
else resolve2();
|
|
9349
9965
|
};
|
|
9350
9966
|
const retry = () => {
|
|
9351
|
-
if (settled) return;
|
|
9352
9967
|
const remaining = deadline - Date.now();
|
|
9353
9968
|
if (remaining <= 0) {
|
|
9354
|
-
finish(
|
|
9969
|
+
finish(
|
|
9970
|
+
new Error(
|
|
9971
|
+
`isolated generation readiness timeout${detail() ? `: ${detail()}` : ""}`
|
|
9972
|
+
)
|
|
9973
|
+
);
|
|
9355
9974
|
return;
|
|
9356
9975
|
}
|
|
9357
9976
|
retryTimer = setTimeout(attempt, Math.min(25, remaining));
|
|
@@ -9361,124 +9980,104 @@ ${stdout}`.trim()}` : ""}`
|
|
|
9361
9980
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
9362
9981
|
finish(
|
|
9363
9982
|
new Error(
|
|
9364
|
-
`isolated
|
|
9983
|
+
`isolated generation exited before readiness${detail() ? `: ${detail()}` : ""}`
|
|
9365
9984
|
)
|
|
9366
9985
|
);
|
|
9367
9986
|
return;
|
|
9368
9987
|
}
|
|
9369
9988
|
const remaining = deadline - Date.now();
|
|
9370
|
-
if (remaining <= 0)
|
|
9371
|
-
|
|
9372
|
-
return;
|
|
9373
|
-
}
|
|
9374
|
-
let attemptSettled = false;
|
|
9989
|
+
if (remaining <= 0) return retry();
|
|
9990
|
+
let requestSettled = false;
|
|
9375
9991
|
const request = http.get(
|
|
9376
9992
|
{ host: "127.0.0.1", port, path: readinessPath },
|
|
9377
9993
|
(response) => {
|
|
9378
|
-
if (
|
|
9994
|
+
if (requestSettled || settled) {
|
|
9379
9995
|
response.destroy();
|
|
9380
9996
|
return;
|
|
9381
9997
|
}
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9998
|
+
if (response.statusCode !== 200) {
|
|
9999
|
+
requestSettled = true;
|
|
10000
|
+
response.resume();
|
|
10001
|
+
retry();
|
|
10002
|
+
return;
|
|
10003
|
+
}
|
|
10004
|
+
const chunks = [];
|
|
10005
|
+
let responseBytes = 0;
|
|
10006
|
+
response.on("data", (chunk) => {
|
|
10007
|
+
if (requestSettled || settled) return;
|
|
10008
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
10009
|
+
responseBytes += buffer.length;
|
|
10010
|
+
if (responseBytes > MAX_READINESS_RESPONSE_BYTES) {
|
|
10011
|
+
requestSettled = true;
|
|
10012
|
+
response.destroy();
|
|
10013
|
+
retry();
|
|
10014
|
+
return;
|
|
10015
|
+
}
|
|
10016
|
+
chunks.push(buffer);
|
|
10017
|
+
});
|
|
10018
|
+
response.once("end", () => {
|
|
10019
|
+
if (requestSettled || settled) return;
|
|
10020
|
+
requestSettled = true;
|
|
10021
|
+
if (isCapabilityReadinessPayload(Buffer.concat(chunks))) finish();
|
|
10022
|
+
else retry();
|
|
10023
|
+
});
|
|
10024
|
+
response.once("error", () => {
|
|
10025
|
+
if (requestSettled || settled) return;
|
|
10026
|
+
requestSettled = true;
|
|
10027
|
+
retry();
|
|
10028
|
+
});
|
|
9386
10029
|
}
|
|
9387
10030
|
);
|
|
9388
|
-
request.setTimeout(
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
} else {
|
|
9397
|
-
retry();
|
|
9398
|
-
}
|
|
10031
|
+
request.setTimeout(
|
|
10032
|
+
remaining,
|
|
10033
|
+
() => request.destroy(new Error("isolated generation readiness timeout"))
|
|
10034
|
+
);
|
|
10035
|
+
request.once("error", () => {
|
|
10036
|
+
if (requestSettled || settled) return;
|
|
10037
|
+
requestSettled = true;
|
|
10038
|
+
retry();
|
|
9399
10039
|
});
|
|
9400
10040
|
};
|
|
9401
10041
|
attempt();
|
|
9402
10042
|
});
|
|
9403
|
-
if (fs29.existsSync(path25.join(probeRoot, "node_modules"))) {
|
|
9404
|
-
throw new Error("isolated probe unexpectedly contained node_modules");
|
|
9405
|
-
}
|
|
9406
10043
|
return Date.now() - startedAt;
|
|
9407
10044
|
} finally {
|
|
9408
10045
|
await stopProbe(child);
|
|
9409
|
-
|
|
10046
|
+
fs30.rmSync(probeRoot, { recursive: true, force: true });
|
|
9410
10047
|
}
|
|
9411
10048
|
}
|
|
9412
|
-
function
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
|
|
10049
|
+
function writeBoundedJson(file, value, maxBytes, description) {
|
|
10050
|
+
const contents = `${JSON.stringify(value, null, 2)}
|
|
10051
|
+
`;
|
|
10052
|
+
if (Buffer.byteLength(contents) > maxBytes) {
|
|
10053
|
+
throw new Error(`${description} exceeds ${maxBytes} bytes`);
|
|
10054
|
+
}
|
|
10055
|
+
fs30.writeFileSync(file, contents, {
|
|
9417
10056
|
mode: 384
|
|
9418
10057
|
});
|
|
9419
|
-
fs29.renameSync(temporary, file);
|
|
9420
|
-
}
|
|
9421
|
-
function snapshotCurrentPointer(file) {
|
|
9422
|
-
if (!fs29.existsSync(file)) return void 0;
|
|
9423
|
-
if (fs29.lstatSync(file).isSymbolicLink()) {
|
|
9424
|
-
throw new Error("current pointer symlink is unsupported");
|
|
9425
|
-
}
|
|
9426
|
-
const stats = fs29.statSync(file);
|
|
9427
|
-
if (!stats.isFile()) throw new Error("current pointer is not a file");
|
|
9428
|
-
return { file, dev: stats.dev, ino: stats.ino };
|
|
9429
|
-
}
|
|
9430
|
-
function invalidateCurrentPointerIfUnchanged(identity) {
|
|
9431
|
-
if (!identity || !fs29.existsSync(identity.file)) return;
|
|
9432
|
-
const stats = fs29.lstatSync(identity.file);
|
|
9433
|
-
if (stats.isSymbolicLink() || !stats.isFile() || stats.dev !== identity.dev || stats.ino !== identity.ino) {
|
|
9434
|
-
return;
|
|
9435
|
-
}
|
|
9436
|
-
fs29.unlinkSync(identity.file);
|
|
9437
10058
|
}
|
|
9438
|
-
function
|
|
9439
|
-
|
|
9440
|
-
if (value && typeof value === "object") {
|
|
9441
|
-
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
9442
|
-
}
|
|
9443
|
-
return JSON.stringify(value);
|
|
10059
|
+
function removeLegacyPointer(cacheRoot) {
|
|
10060
|
+
fs30.rmSync(path26.join(cacheRoot, "current.json"), { force: true });
|
|
9444
10061
|
}
|
|
9445
|
-
function
|
|
9446
|
-
const
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
if (fs29.lstatSync(bundleFile).isSymbolicLink() || fs29.lstatSync(manifestFile).isSymbolicLink() || !fs29.statSync(bundleFile).isFile() || !fs29.statSync(manifestFile).isFile()) {
|
|
9455
|
-
throw mismatch();
|
|
9456
|
-
}
|
|
9457
|
-
const existingBundle = fs29.readFileSync(bundleFile);
|
|
9458
|
-
const existingManifest = JSON.parse(
|
|
9459
|
-
fs29.readFileSync(manifestFile, "utf8")
|
|
9460
|
-
);
|
|
9461
|
-
const existingStartupMs = existingManifest?.isolatedProbe?.startupMs;
|
|
9462
|
-
if (sha256(existingBundle) !== sha256(expectedBundle) || !Number.isFinite(existingStartupMs) || existingStartupMs < 0) {
|
|
9463
|
-
throw mismatch();
|
|
9464
|
-
}
|
|
9465
|
-
const expectedWithExistingProbeTime = {
|
|
9466
|
-
...expectedManifest,
|
|
9467
|
-
isolatedProbe: {
|
|
9468
|
-
...expectedManifest.isolatedProbe,
|
|
9469
|
-
startupMs: existingStartupMs
|
|
10062
|
+
function removeStaleBuildArtifacts(cacheRoot) {
|
|
10063
|
+
for (const entry of fs30.readdirSync(cacheRoot)) {
|
|
10064
|
+
if (!/^\.(?:staging|retired)-[a-z0-9-]+$/.test(entry)) continue;
|
|
10065
|
+
const target = path26.join(cacheRoot, entry);
|
|
10066
|
+
const stats = fs30.lstatSync(target);
|
|
10067
|
+
if (stats.isDirectory() && !stats.isSymbolicLink()) {
|
|
10068
|
+
fs30.rmSync(target, { recursive: true, force: true });
|
|
10069
|
+
} else {
|
|
10070
|
+
fs30.rmSync(target, { force: true });
|
|
9470
10071
|
}
|
|
9471
|
-
}
|
|
9472
|
-
if (stableJson(existingManifest) !== stableJson(expectedWithExistingProbeTime))
|
|
9473
|
-
throw mismatch();
|
|
10072
|
+
}
|
|
9474
10073
|
}
|
|
9475
10074
|
async function buildServerStartupBundle(options) {
|
|
9476
10075
|
const startedAt = Date.now();
|
|
9477
10076
|
let stagingRoot;
|
|
9478
|
-
let
|
|
10077
|
+
let cacheRoot;
|
|
9479
10078
|
try {
|
|
9480
|
-
const projectRoot =
|
|
9481
|
-
|
|
10079
|
+
const projectRoot = fs30.realpathSync(path26.resolve(options.projectRoot));
|
|
10080
|
+
cacheRoot = path26.resolve(
|
|
9482
10081
|
projectRoot,
|
|
9483
10082
|
options.cacheRoot ?? ".miaoda-cache/server"
|
|
9484
10083
|
);
|
|
@@ -9489,170 +10088,186 @@ async function buildServerStartupBundle(options) {
|
|
|
9489
10088
|
cacheRoot,
|
|
9490
10089
|
"cache path symlink is unsupported"
|
|
9491
10090
|
);
|
|
9492
|
-
|
|
9493
|
-
|
|
9494
|
-
);
|
|
10091
|
+
fs30.mkdirSync(cacheRoot, { recursive: true, mode: 448 });
|
|
10092
|
+
removeLegacyPointer(cacheRoot);
|
|
10093
|
+
removeStaleBuildArtifacts(cacheRoot);
|
|
9495
10094
|
const timeoutMs = options.probeTimeoutMs ?? 1e4;
|
|
10095
|
+
const compileTimeoutMs = options.compileTimeoutMs ?? 12e4;
|
|
9496
10096
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
9497
10097
|
throw new Error("probe timeout must be positive");
|
|
9498
|
-
const compileTimeoutMs = options.compileTimeoutMs ?? 12e4;
|
|
9499
10098
|
if (!Number.isFinite(compileTimeoutMs) || compileTimeoutMs <= 0)
|
|
9500
10099
|
throw new Error("compile timeout must be positive");
|
|
10100
|
+
const sourceSha256 = workspaceSourceSha256(projectRoot);
|
|
10101
|
+
stagingRoot = path26.join(cacheRoot, `.staging-${randomUUID()}`);
|
|
10102
|
+
fs30.mkdirSync(stagingRoot, { recursive: false, mode: 448 });
|
|
9501
10103
|
const explicitEntry = options.entry ? resolveEntry(projectRoot, options.entry) : void 0;
|
|
9502
|
-
const
|
|
9503
|
-
const
|
|
9504
|
-
|
|
9505
|
-
|
|
9506
|
-
|
|
9507
|
-
path25.join(projectRoot, "package.json"),
|
|
9508
|
-
path25.join(projectRoot, "nest-cli.json")
|
|
9509
|
-
].filter((file) => fs29.existsSync(file))
|
|
9510
|
-
) : nestCompilationSourceInputs(projectRoot, sourceConfig);
|
|
9511
|
-
const sourceInputs = readSourceInputs();
|
|
9512
|
-
const readSourceIdentity = () => sourceIdentitySha256(
|
|
9513
|
-
workspaceSourceSha256(projectRoot),
|
|
9514
|
-
readSourceInputs()
|
|
9515
|
-
);
|
|
9516
|
-
const sourceSha256 = sourceIdentitySha256(
|
|
9517
|
-
workspaceSourceSha256(projectRoot),
|
|
9518
|
-
sourceInputs
|
|
9519
|
-
);
|
|
9520
|
-
const generationsRoot = path25.join(cacheRoot, "generations");
|
|
9521
|
-
fs29.mkdirSync(generationsRoot, { recursive: true });
|
|
9522
|
-
assertNoSymlinkComponents(
|
|
10104
|
+
const distRoot = path26.join(projectRoot, "dist");
|
|
10105
|
+
const compiled = explicitEntry ? {
|
|
10106
|
+
entry: explicitEntry,
|
|
10107
|
+
applicationRoot: isInside(distRoot, explicitEntry) ? distRoot : path26.dirname(explicitEntry)
|
|
10108
|
+
} : await compileNestSource(
|
|
9523
10109
|
projectRoot,
|
|
9524
|
-
|
|
9525
|
-
|
|
10110
|
+
stagingRoot,
|
|
10111
|
+
compileTimeoutMs,
|
|
10112
|
+
resolveNestTsconfig(projectRoot)
|
|
9526
10113
|
);
|
|
9527
|
-
|
|
9528
|
-
let compiled;
|
|
9529
|
-
if (explicitEntry) {
|
|
9530
|
-
compiled = {
|
|
9531
|
-
entry: explicitEntry,
|
|
9532
|
-
applicationRoot: projectRoot,
|
|
9533
|
-
manifestEntry: path25.relative(projectRoot, explicitEntry).split(path25.sep).join("/")
|
|
9534
|
-
};
|
|
9535
|
-
} else {
|
|
9536
|
-
compiled = await compileNestSource(
|
|
9537
|
-
projectRoot,
|
|
9538
|
-
stagingRoot,
|
|
9539
|
-
compileTimeoutMs,
|
|
9540
|
-
sourceConfig
|
|
9541
|
-
);
|
|
9542
|
-
}
|
|
9543
|
-
const entry = compiled.entry;
|
|
9544
|
-
if (readSourceIdentity() !== sourceSha256) {
|
|
10114
|
+
if (workspaceSourceSha256(projectRoot) !== sourceSha256) {
|
|
9545
10115
|
throw new Error("source changed during isolated Nest compilation");
|
|
9546
10116
|
}
|
|
9547
|
-
const
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
target: `node${process.versions.node.split(".")[0]}`,
|
|
9556
|
-
metafile: true,
|
|
9557
|
-
logLevel: "silent",
|
|
9558
|
-
sourcemap: false,
|
|
9559
|
-
plugins: [
|
|
9560
|
-
knownFrameworkDynamicLoaderStubs(),
|
|
9561
|
-
optionalNestDependencyStubs(),
|
|
9562
|
-
fullstackNestRuntimeResolver(projectRoot),
|
|
9563
|
-
legacyFullstackNestOpenApiStub(projectRoot),
|
|
9564
|
-
classTransformerStorageResolver(projectRoot)
|
|
9565
|
-
]
|
|
9566
|
-
});
|
|
9567
|
-
const output = buildResult2.metafile.outputs[stagingBundle] ?? Object.values(buildResult2.metafile.outputs)[0];
|
|
9568
|
-
const unsafeApplicationLoads = findUnsafeApplicationModuleLoads(
|
|
10117
|
+
const payloadRoot = path26.join(stagingRoot, "payload");
|
|
10118
|
+
fs30.mkdirSync(payloadRoot, { recursive: true, mode: 493 });
|
|
10119
|
+
const entry = STARTUP_ENTRY_FILE;
|
|
10120
|
+
const bundleFile = path26.join(
|
|
10121
|
+
stagingRoot,
|
|
10122
|
+
...STARTUP_BUNDLE_FILE.split("/")
|
|
10123
|
+
);
|
|
10124
|
+
const islands = await buildHybridBundle(
|
|
9569
10125
|
projectRoot,
|
|
9570
|
-
compiled.
|
|
9571
|
-
|
|
10126
|
+
compiled.entry,
|
|
10127
|
+
bundleFile
|
|
9572
10128
|
);
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
|
|
9578
|
-
|
|
9579
|
-
|
|
9580
|
-
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
9585
|
-
const
|
|
9586
|
-
|
|
9587
|
-
|
|
10129
|
+
const dynamicIslands = [...islands.values()].map((island) => ({
|
|
10130
|
+
packagePath: island.packagePath,
|
|
10131
|
+
packageName: island.packageName,
|
|
10132
|
+
reasons: [...island.reasons].sort()
|
|
10133
|
+
})).sort((left, right) => left.packagePath.localeCompare(right.packagePath));
|
|
10134
|
+
const {
|
|
10135
|
+
lockfileSha256,
|
|
10136
|
+
dependencyViewSha256,
|
|
10137
|
+
materializedPackages,
|
|
10138
|
+
dynamicDependencies
|
|
10139
|
+
} = materializeDynamicIslands(projectRoot, payloadRoot, islands);
|
|
10140
|
+
writeServerStartupLauncher(payloadRoot);
|
|
10141
|
+
const { files, treeSha256, totalBytes } = indexPayload(payloadRoot);
|
|
10142
|
+
const fileIndexContents = `${JSON.stringify(files, null, 2)}
|
|
10143
|
+
`;
|
|
10144
|
+
if (Buffer.byteLength(fileIndexContents) > MAX_FILE_INDEX_BYTES) {
|
|
10145
|
+
throw new Error("generation file index exceeds 16 MiB");
|
|
9588
10146
|
}
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
10147
|
+
fs30.writeFileSync(
|
|
10148
|
+
path26.join(stagingRoot, "files.mtree.json"),
|
|
10149
|
+
fileIndexContents,
|
|
10150
|
+
{ mode: 384 }
|
|
10151
|
+
);
|
|
10152
|
+
const runtime = runtimeIdentity();
|
|
9592
10153
|
const generationId = sha256(
|
|
9593
|
-
|
|
9594
|
-
|
|
9595
|
-
|
|
10154
|
+
stableJson({
|
|
10155
|
+
artifactFormat: ARTIFACT_FORMAT,
|
|
10156
|
+
builderPolicyVersion: BUILDER_POLICY_VERSION,
|
|
10157
|
+
dependencyMode: DEPENDENCY_MODE,
|
|
10158
|
+
dependencyViewSha256,
|
|
10159
|
+
dynamicDependencies,
|
|
10160
|
+
dynamicIslands,
|
|
10161
|
+
entry,
|
|
9596
10162
|
lockfileSha256,
|
|
9597
|
-
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
10163
|
+
materializedPackages,
|
|
10164
|
+
runtime,
|
|
10165
|
+
schemaVersion: SCHEMA_VERSION,
|
|
10166
|
+
sourceSha256,
|
|
10167
|
+
treeSha256
|
|
10168
|
+
})
|
|
10169
|
+
);
|
|
10170
|
+
const startupMs = await isolatedProbe(
|
|
10171
|
+
projectRoot,
|
|
10172
|
+
payloadRoot,
|
|
10173
|
+
entry,
|
|
10174
|
+
timeoutMs
|
|
9602
10175
|
);
|
|
10176
|
+
if (workspaceSourceSha256(projectRoot) !== sourceSha256) {
|
|
10177
|
+
throw new Error("source changed while building startup generation");
|
|
10178
|
+
}
|
|
9603
10179
|
const manifest = {
|
|
9604
|
-
schemaVersion:
|
|
10180
|
+
schemaVersion: SCHEMA_VERSION,
|
|
9605
10181
|
builderPolicyVersion: BUILDER_POLICY_VERSION,
|
|
10182
|
+
artifactFormat: ARTIFACT_FORMAT,
|
|
9606
10183
|
generationId,
|
|
9607
|
-
entry
|
|
10184
|
+
entry,
|
|
9608
10185
|
sourceSha256,
|
|
9609
|
-
sourceInputs,
|
|
9610
10186
|
lockfileSha256,
|
|
9611
|
-
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
10187
|
+
dependencyViewSha256,
|
|
10188
|
+
dependencyMode: DEPENDENCY_MODE,
|
|
10189
|
+
dynamicDependencies,
|
|
10190
|
+
dynamicIslands,
|
|
10191
|
+
materializedPackages,
|
|
10192
|
+
runtime,
|
|
10193
|
+
artifact: {
|
|
10194
|
+
fileIndex: "files.mtree.json",
|
|
10195
|
+
fileIndexSha256: sha256(fileIndexContents),
|
|
10196
|
+
treeSha256,
|
|
10197
|
+
fileCount: files.length,
|
|
10198
|
+
totalBytes
|
|
10199
|
+
},
|
|
9617
10200
|
isolatedProbe: {
|
|
9618
10201
|
success: true,
|
|
9619
|
-
|
|
10202
|
+
workspaceNodeModulesVisible: false,
|
|
9620
10203
|
startupMs
|
|
9621
10204
|
}
|
|
9622
10205
|
};
|
|
9623
|
-
|
|
10206
|
+
writeBoundedJson(
|
|
10207
|
+
path26.join(stagingRoot, "manifest.json"),
|
|
10208
|
+
manifest,
|
|
10209
|
+
MAX_MANIFEST_BYTES,
|
|
10210
|
+
"startup generation manifest"
|
|
10211
|
+
);
|
|
10212
|
+
writeBoundedJson(
|
|
10213
|
+
path26.join(stagingRoot, "probe.json"),
|
|
10214
|
+
{
|
|
10215
|
+
schemaVersion: SCHEMA_VERSION,
|
|
10216
|
+
generationId,
|
|
10217
|
+
success: true,
|
|
10218
|
+
workspaceNodeModulesVisible: false,
|
|
10219
|
+
startupMs
|
|
10220
|
+
},
|
|
10221
|
+
MAX_PROBE_BYTES,
|
|
10222
|
+
"startup generation probe"
|
|
10223
|
+
);
|
|
10224
|
+
fs30.rmSync(path26.join(stagingRoot, ".compiled"), {
|
|
9624
10225
|
recursive: true,
|
|
9625
10226
|
force: true
|
|
9626
10227
|
});
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
10228
|
+
const generationsRoot = path26.join(cacheRoot, "generations");
|
|
10229
|
+
fs30.mkdirSync(generationsRoot, { recursive: true, mode: 448 });
|
|
10230
|
+
const generationRoot = path26.join(generationsRoot, generationId);
|
|
10231
|
+
const previousGenerations = fs30.readdirSync(generationsRoot);
|
|
10232
|
+
if (previousGenerations.length > 1) {
|
|
10233
|
+
throw new Error("startup generation directory is ambiguous");
|
|
10234
|
+
}
|
|
10235
|
+
const previous = previousGenerations[0];
|
|
10236
|
+
const previousRoot = previous ? path26.join(generationsRoot, previous) : void 0;
|
|
10237
|
+
const retiredRoot = previousRoot ? path26.join(cacheRoot, `.retired-${randomUUID()}`) : void 0;
|
|
10238
|
+
if (previousRoot && retiredRoot) {
|
|
10239
|
+
fs30.renameSync(previousRoot, retiredRoot);
|
|
10240
|
+
}
|
|
10241
|
+
try {
|
|
10242
|
+
fs30.renameSync(stagingRoot, generationRoot);
|
|
10243
|
+
} catch (publishError) {
|
|
10244
|
+
if (previousRoot && retiredRoot && fs30.existsSync(retiredRoot)) {
|
|
10245
|
+
fs30.renameSync(retiredRoot, previousRoot);
|
|
10246
|
+
}
|
|
10247
|
+
throw publishError;
|
|
10248
|
+
}
|
|
10249
|
+
if (previousRoot && retiredRoot) {
|
|
10250
|
+
try {
|
|
10251
|
+
fs30.rmSync(retiredRoot, { recursive: true, force: true });
|
|
10252
|
+
} catch (pruneError) {
|
|
10253
|
+
fs30.rmSync(generationRoot, { recursive: true, force: true });
|
|
10254
|
+
fs30.renameSync(retiredRoot, previousRoot);
|
|
10255
|
+
throw pruneError;
|
|
10256
|
+
}
|
|
9639
10257
|
}
|
|
9640
10258
|
stagingRoot = void 0;
|
|
9641
|
-
atomicWriteJson(path25.join(cacheRoot, "current.json"), {
|
|
9642
|
-
schemaVersion: 1,
|
|
9643
|
-
generationId
|
|
9644
|
-
});
|
|
9645
10259
|
return {
|
|
9646
10260
|
built: true,
|
|
9647
10261
|
generationId,
|
|
9648
|
-
|
|
9649
|
-
|
|
10262
|
+
generationRoot,
|
|
10263
|
+
entryFile: path26.join(generationRoot, ...entry.split("/")),
|
|
10264
|
+
manifestFile: path26.join(generationRoot, "manifest.json"),
|
|
9650
10265
|
reasons: [],
|
|
9651
10266
|
elapsedMs: Date.now() - startedAt
|
|
9652
10267
|
};
|
|
9653
10268
|
} catch (error) {
|
|
9654
|
-
if (stagingRoot)
|
|
9655
|
-
|
|
10269
|
+
if (stagingRoot) fs30.rmSync(stagingRoot, { recursive: true, force: true });
|
|
10270
|
+
if (cacheRoot) removeLegacyPointer(cacheRoot);
|
|
9656
10271
|
return {
|
|
9657
10272
|
built: false,
|
|
9658
10273
|
reasons: [error instanceof Error ? error.message : String(error)],
|
|
@@ -9705,24 +10320,21 @@ var preUploadStaticCommand = {
|
|
|
9705
10320
|
};
|
|
9706
10321
|
var serverStartupBundleCommand = {
|
|
9707
10322
|
name: "server-startup-bundle",
|
|
9708
|
-
description: "Build and isolate-probe a
|
|
10323
|
+
description: "Build and isolate-probe a recycle-only NestJS startup generation",
|
|
9709
10324
|
register(program) {
|
|
9710
10325
|
program.command(this.name).description(this.description).option("--project-root <dir>", "Application project root", process.cwd()).option(
|
|
9711
|
-
"--entry <file>",
|
|
9712
|
-
"Advanced: bundle an existing compiled entry instead of isolated Nest compilation"
|
|
9713
|
-
).option(
|
|
9714
|
-
"--cache-root <dir>",
|
|
9715
|
-
"Server startup cache root",
|
|
9716
|
-
".miaoda-cache/server"
|
|
9717
|
-
).option(
|
|
9718
10326
|
"--probe-timeout-ms <ms>",
|
|
9719
10327
|
"Isolated availability probe timeout in milliseconds",
|
|
9720
10328
|
"10000"
|
|
9721
10329
|
).action(
|
|
9722
10330
|
async (options) => {
|
|
10331
|
+
const probeTimeoutMs = Number(options.probeTimeoutMs);
|
|
10332
|
+
if (!Number.isFinite(probeTimeoutMs) || probeTimeoutMs <= 0) {
|
|
10333
|
+
throw new Error("--probe-timeout-ms must be a positive number");
|
|
10334
|
+
}
|
|
9723
10335
|
const result = await buildServerStartupBundle({
|
|
9724
|
-
|
|
9725
|
-
probeTimeoutMs
|
|
10336
|
+
projectRoot: options.projectRoot,
|
|
10337
|
+
probeTimeoutMs
|
|
9726
10338
|
});
|
|
9727
10339
|
console.log(JSON.stringify(result));
|
|
9728
10340
|
if (!result.built) process.exitCode = 2;
|
|
@@ -9756,13 +10368,13 @@ var commands = [
|
|
|
9756
10368
|
|
|
9757
10369
|
// src/index.ts
|
|
9758
10370
|
for (const filename of [".env.local", ".env"]) {
|
|
9759
|
-
const envPath =
|
|
9760
|
-
if (
|
|
10371
|
+
const envPath = path27.join(process.cwd(), filename);
|
|
10372
|
+
if (fs31.existsSync(envPath)) {
|
|
9761
10373
|
dotenvConfig({ path: envPath });
|
|
9762
10374
|
}
|
|
9763
10375
|
}
|
|
9764
|
-
var __dirname =
|
|
9765
|
-
var pkg = JSON.parse(
|
|
10376
|
+
var __dirname = path27.dirname(fileURLToPath5(import.meta.url));
|
|
10377
|
+
var pkg = JSON.parse(fs31.readFileSync(path27.join(__dirname, "../package.json"), "utf-8"));
|
|
9766
10378
|
var cli = new FullstackCLI(pkg.version);
|
|
9767
10379
|
cli.useAll(commands);
|
|
9768
10380
|
cli.run();
|