@lark-apaas/fullstack-cli 1.1.59 → 1.1.61-alpha.20260818172555
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/client-dependency-graph.d.ts +37 -0
- package/dist/client-dependency-graph.js +466 -0
- package/dist/index.js +3482 -143
- package/package.json +4 -1
- package/templates/scripts/cache-generation-preflight.mjs +1346 -0
- package/templates/scripts/cache-generation-prune.mjs +174 -0
- package/templates/scripts/cache-runtime-coordinator.mjs +487 -0
- package/templates/scripts/dev.js +433 -59
- package/templates/scripts/dev.sh +2 -0
- package/templates/scripts/lint.js +2 -25
- package/templates/scripts/patch-vite-dependency-graph-hash.mjs +141 -0
- package/templates/scripts/server-cache-module-resolver.cjs +63 -0
- package/templates/scripts/server-cache-runtime.mjs +681 -0
- package/templates/scripts/server-startup-runtime.mjs +496 -0
- package/templates/scripts/server-transition-runtime.mjs +655 -0
- package/templates/scripts/vite-cache-runtime.mjs +3100 -0
- package/templates/scripts/workspace-client-runtime.mjs +176 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import fs35 from "fs";
|
|
3
|
+
import path32 from "path";
|
|
4
4
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
5
|
-
import { config as dotenvConfig } from "dotenv";
|
|
6
5
|
|
|
7
6
|
// src/cli.ts
|
|
8
7
|
import { Command } from "commander";
|
|
@@ -2554,6 +2553,20 @@ function buildDefaultRules(opts) {
|
|
|
2554
2553
|
command: "fullstack-cli action-plugin init",
|
|
2555
2554
|
overwrite: false
|
|
2556
2555
|
},
|
|
2556
|
+
// Cache generation keeps workspace source live and only snapshots the
|
|
2557
|
+
// automatically traced Nest runtime dependencies.
|
|
2558
|
+
{
|
|
2559
|
+
type: "add-script",
|
|
2560
|
+
name: "build:server-runtime-dependencies:from-dist",
|
|
2561
|
+
command: "fullstack-cli build server-runtime-dependencies",
|
|
2562
|
+
overwrite: true
|
|
2563
|
+
},
|
|
2564
|
+
{
|
|
2565
|
+
type: "patch-script",
|
|
2566
|
+
name: "build:cache:from-dist",
|
|
2567
|
+
to: "npm run build:server-runtime-dependencies:from-dist && fullstack-cli build app-runtime-manifest --runtime-manifest-file ${MIAODA_PLATFORM_RUNTIME_MANIFEST:-/opt/miaoda/preview-runtime/runtime-manifest.json} && npm run build:vite-cache && fullstack-cli build cache-generation --runtime-manifest-file ${MIAODA_PLATFORM_RUNTIME_MANIFEST:-/opt/miaoda/preview-runtime/runtime-manifest.json}",
|
|
2568
|
+
ifStartsWith: "npm run build:server-cache:from-dist"
|
|
2569
|
+
},
|
|
2557
2570
|
// 6. 替换 drizzle.config.ts(仅当文件存在时)
|
|
2558
2571
|
{
|
|
2559
2572
|
from: "templates/drizzle.config.ts",
|
|
@@ -2604,7 +2617,11 @@ function defaultProfile(opts) {
|
|
|
2604
2617
|
return {
|
|
2605
2618
|
sync: buildDefaultRules(opts),
|
|
2606
2619
|
// 文件权限设置(所有 .sh 文件设置为可执行:'**/*.sh': 0o755)
|
|
2607
|
-
|
|
2620
|
+
// Workspace / TOS restore may materialize scripts with 0644 even when the
|
|
2621
|
+
// platform template tracks the executable bit. `npm run dev` executes
|
|
2622
|
+
// scripts/dev.sh directly, so repairing the mode is part of sync's
|
|
2623
|
+
// platform contract rather than an image-entrypoint side effect.
|
|
2624
|
+
permissions: { "**/*.sh": 493 },
|
|
2608
2625
|
activateGitHooks: true
|
|
2609
2626
|
};
|
|
2610
2627
|
}
|
|
@@ -3502,6 +3519,26 @@ function resolveGrayscaleVersions(_cwd, configJson) {
|
|
|
3502
3519
|
return versions;
|
|
3503
3520
|
}
|
|
3504
3521
|
|
|
3522
|
+
// src/utils/npm-child.ts
|
|
3523
|
+
function sanitizedNpmEnv(source = process.env) {
|
|
3524
|
+
const env = { ...source };
|
|
3525
|
+
for (const key of [
|
|
3526
|
+
"FORCE_AUTHN_INNERAPI_DOMAIN",
|
|
3527
|
+
"FORCE_AUTHN_ACCESS_SECRET",
|
|
3528
|
+
"FORCE_AUTHN_ACCESS_KEY",
|
|
3529
|
+
"NODE_OPTIONS",
|
|
3530
|
+
"NODE_PATH",
|
|
3531
|
+
"BASH_ENV",
|
|
3532
|
+
"ENV",
|
|
3533
|
+
"NPM_CONFIG_IGNORE_SCRIPTS",
|
|
3534
|
+
"npm_config_ignore_scripts"
|
|
3535
|
+
]) {
|
|
3536
|
+
delete env[key];
|
|
3537
|
+
}
|
|
3538
|
+
env.npm_config_ignore_scripts = "true";
|
|
3539
|
+
return env;
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3505
3542
|
// src/commands/upgrade/deps/run.handler.ts
|
|
3506
3543
|
function parseSemver(version) {
|
|
3507
3544
|
const match = version.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
@@ -3560,8 +3597,9 @@ function upgradePackages(packages, version, cwd) {
|
|
|
3560
3597
|
packages.forEach((pkg2) => {
|
|
3561
3598
|
const target = `${pkg2}@${version}`;
|
|
3562
3599
|
console.log(`[fullstack-cli] Installing ${target}...`);
|
|
3563
|
-
const result = spawnSync4("npm", ["install", target], {
|
|
3600
|
+
const result = spawnSync4("npm", ["install", target, "--ignore-scripts=true"], {
|
|
3564
3601
|
cwd,
|
|
3602
|
+
env: sanitizedNpmEnv(),
|
|
3565
3603
|
stdio: "inherit"
|
|
3566
3604
|
});
|
|
3567
3605
|
if (result.error || result.status !== 0) {
|
|
@@ -3572,8 +3610,9 @@ function upgradePackages(packages, version, cwd) {
|
|
|
3572
3610
|
console.log("[fullstack-cli] Upgrading to latest compatible versions...");
|
|
3573
3611
|
packages.forEach((pkg2) => {
|
|
3574
3612
|
console.log(`[fullstack-cli] Updating ${pkg2}...`);
|
|
3575
|
-
const result = spawnSync4("npm", ["update", pkg2], {
|
|
3613
|
+
const result = spawnSync4("npm", ["update", pkg2, "--ignore-scripts=true"], {
|
|
3576
3614
|
cwd,
|
|
3615
|
+
env: sanitizedNpmEnv(),
|
|
3577
3616
|
stdio: "inherit"
|
|
3578
3617
|
});
|
|
3579
3618
|
if (result.error || result.status !== 0) {
|
|
@@ -3633,8 +3672,9 @@ function installGrayscaleVersions(packages, grayscaleVersions, cwd, dryRun, mode
|
|
|
3633
3672
|
}
|
|
3634
3673
|
const targets = upgradePlan.map(({ pkg: pkg2, version }) => `${pkg2}@${version}`);
|
|
3635
3674
|
console.log(`[fullstack-cli] Installing ${targets.join(" ")}...`);
|
|
3636
|
-
const result = spawnSync4("npm", ["install", ...targets], {
|
|
3675
|
+
const result = spawnSync4("npm", ["install", ...targets, "--ignore-scripts=true"], {
|
|
3637
3676
|
cwd,
|
|
3677
|
+
env: sanitizedNpmEnv(),
|
|
3638
3678
|
stdio: "inherit"
|
|
3639
3679
|
});
|
|
3640
3680
|
if (result.error || result.status !== 0) {
|
|
@@ -3826,28 +3866,96 @@ var upgradeCommand = {
|
|
|
3826
3866
|
|
|
3827
3867
|
// src/commands/action-plugin/utils.ts
|
|
3828
3868
|
import fs13 from "fs";
|
|
3869
|
+
import os from "os";
|
|
3870
|
+
import path12 from "path";
|
|
3871
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
3872
|
+
|
|
3873
|
+
// src/commands/action-plugin/validation.ts
|
|
3829
3874
|
import path11 from "path";
|
|
3830
|
-
|
|
3875
|
+
var SCOPED_PACKAGE_NAME = /^@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$/;
|
|
3876
|
+
var REGISTRY_PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
|
|
3877
|
+
var PLUGIN_VERSION = /^(?:latest|[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z][0-9A-Za-z.-]*)?(?:\+[0-9A-Za-z][0-9A-Za-z.-]*)?)$/;
|
|
3878
|
+
var PEER_DEP_RANGE = /^[0-9A-Za-z*^~<>=|.\-\s]+$/;
|
|
3879
|
+
function assertScopedPackageName(value, label = "package name") {
|
|
3880
|
+
if (typeof value !== "string" || !SCOPED_PACKAGE_NAME.test(value)) {
|
|
3881
|
+
throw new Error(`Invalid ${label}: ${String(value)}`);
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
function assertRegistryPackageName(value, label = "package name") {
|
|
3885
|
+
if (typeof value !== "string" || !REGISTRY_PACKAGE_NAME.test(value)) {
|
|
3886
|
+
throw new Error(`Invalid ${label}: ${String(value)}`);
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
function assertPluginVersion(value) {
|
|
3890
|
+
if (typeof value !== "string" || !PLUGIN_VERSION.test(value)) {
|
|
3891
|
+
throw new Error(`Invalid plugin version: ${String(value)}`);
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
function assertSafePeerDependencySpec(value) {
|
|
3895
|
+
if (typeof value !== "string") {
|
|
3896
|
+
throw new Error(`Invalid peer dependency spec: ${String(value)}`);
|
|
3897
|
+
}
|
|
3898
|
+
const spec = value.trim();
|
|
3899
|
+
const lower = spec.toLowerCase();
|
|
3900
|
+
if (spec.length === 0 || !PEER_DEP_RANGE.test(spec) || lower.startsWith("file:") || lower.startsWith("git") || lower.startsWith("http:") || lower.startsWith("https:") || lower.startsWith("npm:") || spec.includes("/") || spec.includes("\\")) {
|
|
3901
|
+
throw new Error(`Invalid peer dependency spec: ${value}`);
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
function resolveContainedPath(root, ...segments) {
|
|
3905
|
+
const resolvedRoot = path11.resolve(root);
|
|
3906
|
+
const resolved = path11.resolve(resolvedRoot, ...segments);
|
|
3907
|
+
if (!resolved.startsWith(`${resolvedRoot}${path11.sep}`)) {
|
|
3908
|
+
throw new Error(`Resolved path escapes allowed root: ${resolved}`);
|
|
3909
|
+
}
|
|
3910
|
+
return resolved;
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3913
|
+
// src/commands/action-plugin/utils.ts
|
|
3831
3914
|
function parsePluginName(input) {
|
|
3832
|
-
|
|
3833
|
-
|
|
3915
|
+
if (typeof input !== "string") {
|
|
3916
|
+
throw new Error(
|
|
3917
|
+
`Invalid plugin name format: ${input}. Expected format: @scope/name or @scope/name@version`
|
|
3918
|
+
);
|
|
3919
|
+
}
|
|
3920
|
+
const versionSeparator = input.lastIndexOf("@");
|
|
3921
|
+
const hasVersion = versionSeparator > 0;
|
|
3922
|
+
const name = hasVersion ? input.slice(0, versionSeparator) : input;
|
|
3923
|
+
const version = hasVersion ? input.slice(versionSeparator + 1) : "latest";
|
|
3924
|
+
try {
|
|
3925
|
+
assertScopedPackageName(name, "plugin name");
|
|
3926
|
+
assertPluginVersion(version);
|
|
3927
|
+
} catch {
|
|
3834
3928
|
throw new Error(
|
|
3835
3929
|
`Invalid plugin name format: ${input}. Expected format: @scope/name or @scope/name@version`
|
|
3836
3930
|
);
|
|
3837
3931
|
}
|
|
3838
3932
|
return {
|
|
3839
|
-
name
|
|
3840
|
-
version
|
|
3933
|
+
name,
|
|
3934
|
+
version
|
|
3841
3935
|
};
|
|
3842
3936
|
}
|
|
3843
3937
|
function getProjectRoot() {
|
|
3844
3938
|
return process.cwd();
|
|
3845
3939
|
}
|
|
3940
|
+
function assertRealDirectoryIfExists(directory, label) {
|
|
3941
|
+
if (!fs13.existsSync(directory)) {
|
|
3942
|
+
return;
|
|
3943
|
+
}
|
|
3944
|
+
const stat = fs13.lstatSync(directory);
|
|
3945
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
3946
|
+
throw new Error(`${label} must be a real directory`);
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3846
3949
|
function getPackageJsonPath() {
|
|
3847
|
-
return
|
|
3950
|
+
return path12.join(getProjectRoot(), "package.json");
|
|
3848
3951
|
}
|
|
3849
3952
|
function getPluginPath(pluginName) {
|
|
3850
|
-
|
|
3953
|
+
assertScopedPackageName(pluginName, "plugin name");
|
|
3954
|
+
const nodeModulesPath = path12.resolve(getProjectRoot(), "node_modules");
|
|
3955
|
+
const pluginPath = resolveContainedPath(nodeModulesPath, pluginName);
|
|
3956
|
+
assertRealDirectoryIfExists(nodeModulesPath, "node_modules");
|
|
3957
|
+
assertRealDirectoryIfExists(path12.dirname(pluginPath), "plugin scope directory");
|
|
3958
|
+
return pluginPath;
|
|
3851
3959
|
}
|
|
3852
3960
|
function readPackageJson2() {
|
|
3853
3961
|
const pkgPath = getPackageJsonPath();
|
|
@@ -3886,6 +3994,7 @@ function npmInstall(tgzPath) {
|
|
|
3886
3994
|
console.log(`[action-plugin] Running npm install ${tgzPath}...`);
|
|
3887
3995
|
const result = spawnSync6("npm", ["install", tgzPath, "--no-save", "--no-package-lock", "--ignore-scripts"], {
|
|
3888
3996
|
cwd: getProjectRoot(),
|
|
3997
|
+
env: sanitizedNpmEnv(),
|
|
3889
3998
|
stdio: "inherit"
|
|
3890
3999
|
});
|
|
3891
4000
|
if (result.error) {
|
|
@@ -3896,7 +4005,7 @@ function npmInstall(tgzPath) {
|
|
|
3896
4005
|
}
|
|
3897
4006
|
}
|
|
3898
4007
|
function getPackageVersion(pluginName) {
|
|
3899
|
-
const pkgJsonPath =
|
|
4008
|
+
const pkgJsonPath = path12.join(getPluginPath(pluginName), "package.json");
|
|
3900
4009
|
if (!fs13.existsSync(pkgJsonPath)) {
|
|
3901
4010
|
return null;
|
|
3902
4011
|
}
|
|
@@ -3909,7 +4018,7 @@ function getPackageVersion(pluginName) {
|
|
|
3909
4018
|
}
|
|
3910
4019
|
}
|
|
3911
4020
|
function readPluginPackageJson(pluginPath) {
|
|
3912
|
-
const pkgJsonPath =
|
|
4021
|
+
const pkgJsonPath = path12.join(pluginPath, "package.json");
|
|
3913
4022
|
if (!fs13.existsSync(pkgJsonPath)) {
|
|
3914
4023
|
return null;
|
|
3915
4024
|
}
|
|
@@ -3921,29 +4030,39 @@ function readPluginPackageJson(pluginPath) {
|
|
|
3921
4030
|
}
|
|
3922
4031
|
}
|
|
3923
4032
|
function extractTgzToNodeModules(tgzPath, pluginName) {
|
|
3924
|
-
|
|
3925
|
-
const
|
|
3926
|
-
const
|
|
4033
|
+
assertScopedPackageName(pluginName, "plugin name");
|
|
4034
|
+
const nodeModulesPath = path12.resolve(getProjectRoot(), "node_modules");
|
|
4035
|
+
const targetDir = resolveContainedPath(nodeModulesPath, pluginName);
|
|
4036
|
+
const scopeDir = path12.dirname(targetDir);
|
|
4037
|
+
if (!fs13.existsSync(nodeModulesPath)) {
|
|
4038
|
+
fs13.mkdirSync(nodeModulesPath, { recursive: true });
|
|
4039
|
+
}
|
|
4040
|
+
assertRealDirectoryIfExists(nodeModulesPath, "node_modules");
|
|
3927
4041
|
if (!fs13.existsSync(scopeDir)) {
|
|
3928
4042
|
fs13.mkdirSync(scopeDir, { recursive: true });
|
|
3929
4043
|
}
|
|
4044
|
+
assertRealDirectoryIfExists(scopeDir, "plugin scope directory");
|
|
3930
4045
|
if (fs13.existsSync(targetDir)) {
|
|
3931
4046
|
fs13.rmSync(targetDir, { recursive: true });
|
|
3932
4047
|
}
|
|
3933
|
-
const tempDir =
|
|
3934
|
-
if (fs13.existsSync(tempDir)) {
|
|
3935
|
-
fs13.rmSync(tempDir, { recursive: true });
|
|
3936
|
-
}
|
|
3937
|
-
fs13.mkdirSync(tempDir, { recursive: true });
|
|
4048
|
+
const tempDir = fs13.mkdtempSync(path12.join(os.tmpdir(), "fullstack-cli-extract-"));
|
|
3938
4049
|
try {
|
|
3939
|
-
|
|
3940
|
-
|
|
4050
|
+
const tarResult = spawnSync6("tar", ["-xzf", tgzPath, "-C", tempDir], {
|
|
4051
|
+
stdio: "pipe"
|
|
4052
|
+
});
|
|
4053
|
+
if (tarResult.error) {
|
|
4054
|
+
throw new Error(`Failed to extract plugin archive: ${tarResult.error.message}`);
|
|
4055
|
+
}
|
|
4056
|
+
if (tarResult.status !== 0) {
|
|
4057
|
+
throw new Error(`Failed to extract plugin archive: tar exited with code ${tarResult.status}`);
|
|
4058
|
+
}
|
|
4059
|
+
const extractedDir = path12.join(tempDir, "package");
|
|
3941
4060
|
if (fs13.existsSync(extractedDir)) {
|
|
3942
4061
|
fs13.renameSync(extractedDir, targetDir);
|
|
3943
4062
|
} else {
|
|
3944
4063
|
const files = fs13.readdirSync(tempDir);
|
|
3945
4064
|
if (files.length === 1) {
|
|
3946
|
-
fs13.renameSync(
|
|
4065
|
+
fs13.renameSync(path12.join(tempDir, files[0]), targetDir);
|
|
3947
4066
|
} else {
|
|
3948
4067
|
throw new Error("Unexpected tgz structure");
|
|
3949
4068
|
}
|
|
@@ -3960,9 +4079,11 @@ function checkMissingPeerDeps(peerDeps) {
|
|
|
3960
4079
|
return [];
|
|
3961
4080
|
}
|
|
3962
4081
|
const missing = [];
|
|
3963
|
-
const nodeModulesPath =
|
|
4082
|
+
const nodeModulesPath = path12.join(getProjectRoot(), "node_modules");
|
|
3964
4083
|
for (const [depName, _version] of Object.entries(peerDeps)) {
|
|
3965
|
-
|
|
4084
|
+
assertRegistryPackageName(depName, "peer dependency name");
|
|
4085
|
+
assertSafePeerDependencySpec(_version);
|
|
4086
|
+
const depPath = resolveContainedPath(nodeModulesPath, depName);
|
|
3966
4087
|
if (!fs13.existsSync(depPath)) {
|
|
3967
4088
|
missing.push(depName);
|
|
3968
4089
|
}
|
|
@@ -3973,9 +4094,13 @@ function installMissingDeps(deps) {
|
|
|
3973
4094
|
if (deps.length === 0) {
|
|
3974
4095
|
return;
|
|
3975
4096
|
}
|
|
4097
|
+
for (const depName of deps) {
|
|
4098
|
+
assertRegistryPackageName(depName, "peer dependency name");
|
|
4099
|
+
}
|
|
3976
4100
|
console.log(`[action-plugin] Installing missing dependencies: ${deps.join(", ")}`);
|
|
3977
|
-
const result = spawnSync6("npm", ["install", ...deps, "--no-save", "--no-package-lock"], {
|
|
4101
|
+
const result = spawnSync6("npm", ["install", ...deps, "--no-save", "--no-package-lock", "--ignore-scripts=true"], {
|
|
3978
4102
|
cwd: getProjectRoot(),
|
|
4103
|
+
env: sanitizedNpmEnv(),
|
|
3979
4104
|
stdio: "inherit"
|
|
3980
4105
|
});
|
|
3981
4106
|
if (result.error) {
|
|
@@ -3986,6 +4111,7 @@ function installMissingDeps(deps) {
|
|
|
3986
4111
|
}
|
|
3987
4112
|
}
|
|
3988
4113
|
function removePluginDirectory(pluginName) {
|
|
4114
|
+
assertScopedPackageName(pluginName, "plugin name");
|
|
3989
4115
|
const pluginPath = getPluginPath(pluginName);
|
|
3990
4116
|
if (fs13.existsSync(pluginPath)) {
|
|
3991
4117
|
fs13.rmSync(pluginPath, { recursive: true });
|
|
@@ -3996,9 +4122,12 @@ function removePluginDirectory(pluginName) {
|
|
|
3996
4122
|
// src/commands/action-plugin/api-client.ts
|
|
3997
4123
|
import { HttpClient as HttpClient2 } from "@lark-apaas/http-client";
|
|
3998
4124
|
import fs14 from "fs";
|
|
3999
|
-
import
|
|
4125
|
+
import path13 from "path";
|
|
4000
4126
|
var PLUGIN_CACHE_DIR = "node_modules/.cache/fullstack-cli/plugins";
|
|
4001
4127
|
async function getPluginVersions(keys, latestOnly = true) {
|
|
4128
|
+
for (const key of keys) {
|
|
4129
|
+
assertScopedPackageName(key, "plugin key");
|
|
4130
|
+
}
|
|
4002
4131
|
const client = getHttpClient();
|
|
4003
4132
|
const response = await client.post(`/api/v1/studio/innerapi/plugins/-/versions/batch_get?keys=${keys.join(",")}&latest_only=${latestOnly}`);
|
|
4004
4133
|
if (!response.ok || response.status !== 200) {
|
|
@@ -4012,6 +4141,8 @@ async function getPluginVersions(keys, latestOnly = true) {
|
|
|
4012
4141
|
return result.data.pluginVersions;
|
|
4013
4142
|
}
|
|
4014
4143
|
async function getPluginVersion(pluginKey, requestedVersion) {
|
|
4144
|
+
assertScopedPackageName(pluginKey, "plugin key");
|
|
4145
|
+
assertPluginVersion(requestedVersion);
|
|
4015
4146
|
const isLatest = requestedVersion === "latest";
|
|
4016
4147
|
const versions = await getPluginVersions([pluginKey], isLatest);
|
|
4017
4148
|
const pluginVersions = versions[pluginKey];
|
|
@@ -4019,6 +4150,7 @@ async function getPluginVersion(pluginKey, requestedVersion) {
|
|
|
4019
4150
|
throw new Error(`Plugin not found: ${pluginKey}`);
|
|
4020
4151
|
}
|
|
4021
4152
|
if (isLatest) {
|
|
4153
|
+
assertPluginVersion(pluginVersions[0].version);
|
|
4022
4154
|
return pluginVersions[0];
|
|
4023
4155
|
}
|
|
4024
4156
|
const targetVersion = pluginVersions.find((v) => v.version === requestedVersion);
|
|
@@ -4030,10 +4162,8 @@ async function getPluginVersion(pluginKey, requestedVersion) {
|
|
|
4030
4162
|
return targetVersion;
|
|
4031
4163
|
}
|
|
4032
4164
|
function parsePluginKey(key) {
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
throw new Error(`Invalid plugin key format: ${key}`);
|
|
4036
|
-
}
|
|
4165
|
+
assertScopedPackageName(key, "plugin key");
|
|
4166
|
+
const match = key.match(/^(@[^/]+)\/([^/]+)$/);
|
|
4037
4167
|
return { scope: match[1], name: match[2] };
|
|
4038
4168
|
}
|
|
4039
4169
|
async function downloadFromInner(pluginKey, version) {
|
|
@@ -4060,19 +4190,32 @@ async function downloadFromPublic(downloadURL) {
|
|
|
4060
4190
|
return Buffer.from(arrayBuffer);
|
|
4061
4191
|
}
|
|
4062
4192
|
function getPluginCacheDir() {
|
|
4063
|
-
return
|
|
4193
|
+
return path13.join(process.cwd(), PLUGIN_CACHE_DIR);
|
|
4064
4194
|
}
|
|
4065
4195
|
function ensureCacheDir() {
|
|
4066
4196
|
const cacheDir = getPluginCacheDir();
|
|
4067
|
-
|
|
4068
|
-
|
|
4197
|
+
const projectRoot = path13.resolve(process.cwd());
|
|
4198
|
+
const relative = path13.relative(projectRoot, cacheDir);
|
|
4199
|
+
let current = projectRoot;
|
|
4200
|
+
for (const segment of relative.split(path13.sep)) {
|
|
4201
|
+
current = path13.join(current, segment);
|
|
4202
|
+
if (fs14.existsSync(current)) {
|
|
4203
|
+
const stat = fs14.lstatSync(current);
|
|
4204
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
4205
|
+
throw new Error(`Plugin cache path must be a real directory: ${current}`);
|
|
4206
|
+
}
|
|
4207
|
+
} else {
|
|
4208
|
+
fs14.mkdirSync(current);
|
|
4209
|
+
}
|
|
4069
4210
|
}
|
|
4070
4211
|
}
|
|
4071
4212
|
function getTempFilePath(pluginKey, version) {
|
|
4213
|
+
assertScopedPackageName(pluginKey, "plugin key");
|
|
4214
|
+
assertPluginVersion(version);
|
|
4072
4215
|
ensureCacheDir();
|
|
4073
4216
|
const safeKey = pluginKey.replace(/[/@]/g, "_");
|
|
4074
4217
|
const filename = `${safeKey}@${version}.tgz`;
|
|
4075
|
-
return
|
|
4218
|
+
return resolveContainedPath(getPluginCacheDir(), filename);
|
|
4076
4219
|
}
|
|
4077
4220
|
var MAX_RETRIES = 2;
|
|
4078
4221
|
async function withRetry(operation, description, maxRetries = MAX_RETRIES) {
|
|
@@ -4120,10 +4263,12 @@ async function downloadPlugin(pluginKey, requestedVersion) {
|
|
|
4120
4263
|
function cleanupTempFile(tgzPath) {
|
|
4121
4264
|
}
|
|
4122
4265
|
function getCachePath(pluginKey, version) {
|
|
4266
|
+
assertScopedPackageName(pluginKey, "plugin key");
|
|
4267
|
+
assertPluginVersion(version);
|
|
4123
4268
|
ensureCacheDir();
|
|
4124
4269
|
const safeKey = pluginKey.replace(/[/@]/g, "_");
|
|
4125
4270
|
const filename = `${safeKey}@${version}.tgz`;
|
|
4126
|
-
return
|
|
4271
|
+
return resolveContainedPath(getPluginCacheDir(), filename);
|
|
4127
4272
|
}
|
|
4128
4273
|
function hasCachedPlugin(pluginKey, version) {
|
|
4129
4274
|
const cachePath = getCachePath(pluginKey, version);
|
|
@@ -4142,7 +4287,7 @@ function listCachedPlugins() {
|
|
|
4142
4287
|
if (!match) continue;
|
|
4143
4288
|
const [, rawName, version] = match;
|
|
4144
4289
|
const name = rawName.replace(/^_/, "@").replace(/_/, "/");
|
|
4145
|
-
const filePath =
|
|
4290
|
+
const filePath = path13.join(cacheDir, file);
|
|
4146
4291
|
const stat = fs14.statSync(filePath);
|
|
4147
4292
|
result.push({
|
|
4148
4293
|
name,
|
|
@@ -4163,7 +4308,7 @@ function cleanAllCache() {
|
|
|
4163
4308
|
let count = 0;
|
|
4164
4309
|
for (const file of files) {
|
|
4165
4310
|
if (file.endsWith(".tgz")) {
|
|
4166
|
-
fs14.unlinkSync(
|
|
4311
|
+
fs14.unlinkSync(path13.join(cacheDir, file));
|
|
4167
4312
|
count++;
|
|
4168
4313
|
}
|
|
4169
4314
|
}
|
|
@@ -4180,12 +4325,12 @@ function cleanPluginCache(pluginKey, version) {
|
|
|
4180
4325
|
for (const file of files) {
|
|
4181
4326
|
if (version) {
|
|
4182
4327
|
if (file === `${safeKey}@${version}.tgz`) {
|
|
4183
|
-
fs14.unlinkSync(
|
|
4328
|
+
fs14.unlinkSync(path13.join(cacheDir, file));
|
|
4184
4329
|
count++;
|
|
4185
4330
|
}
|
|
4186
4331
|
} else {
|
|
4187
4332
|
if (file.startsWith(`${safeKey}@`) && file.endsWith(".tgz")) {
|
|
4188
|
-
fs14.unlinkSync(
|
|
4333
|
+
fs14.unlinkSync(path13.join(cacheDir, file));
|
|
4189
4334
|
count++;
|
|
4190
4335
|
}
|
|
4191
4336
|
}
|
|
@@ -4196,6 +4341,8 @@ function cleanPluginCache(pluginKey, version) {
|
|
|
4196
4341
|
// src/commands/action-plugin/init.handler.ts
|
|
4197
4342
|
async function installOneForInit(name, version) {
|
|
4198
4343
|
try {
|
|
4344
|
+
assertScopedPackageName(name, "plugin name");
|
|
4345
|
+
assertPluginVersion(version);
|
|
4199
4346
|
const installedVersion = getPackageVersion(name);
|
|
4200
4347
|
if (installedVersion === version) {
|
|
4201
4348
|
return { name, version, success: true, skipped: true };
|
|
@@ -4614,24 +4761,24 @@ var actionPluginCommandGroup = {
|
|
|
4614
4761
|
// src/commands/capability/utils.ts
|
|
4615
4762
|
import fs15 from "fs";
|
|
4616
4763
|
import { createRequire as createRequire2 } from "module";
|
|
4617
|
-
import
|
|
4764
|
+
import path14 from "path";
|
|
4618
4765
|
var CAPABILITIES_DIR = "server/capabilities";
|
|
4619
4766
|
var SHARED_CAPABILITIES_DIR = "shared/capabilities";
|
|
4620
4767
|
function getProjectRoot2() {
|
|
4621
4768
|
return process.cwd();
|
|
4622
4769
|
}
|
|
4623
4770
|
function getCapabilitiesDir() {
|
|
4624
|
-
const sharedDir =
|
|
4771
|
+
const sharedDir = path14.join(getProjectRoot2(), SHARED_CAPABILITIES_DIR);
|
|
4625
4772
|
if (fs15.existsSync(sharedDir)) {
|
|
4626
4773
|
return sharedDir;
|
|
4627
4774
|
}
|
|
4628
|
-
return
|
|
4775
|
+
return path14.join(getProjectRoot2(), CAPABILITIES_DIR);
|
|
4629
4776
|
}
|
|
4630
4777
|
function getCapabilityPath(id) {
|
|
4631
|
-
return
|
|
4778
|
+
return path14.join(getCapabilitiesDir(), `${id}.json`);
|
|
4632
4779
|
}
|
|
4633
4780
|
function getPluginManifestPath(pluginKey) {
|
|
4634
|
-
return
|
|
4781
|
+
return path14.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
|
|
4635
4782
|
}
|
|
4636
4783
|
function capabilitiesDirExists() {
|
|
4637
4784
|
return fs15.existsSync(getCapabilitiesDir());
|
|
@@ -4698,7 +4845,7 @@ function hasValidParamsSchema(paramsSchema) {
|
|
|
4698
4845
|
}
|
|
4699
4846
|
async function loadPlugin(pluginKey) {
|
|
4700
4847
|
try {
|
|
4701
|
-
const userRequire = createRequire2(
|
|
4848
|
+
const userRequire = createRequire2(path14.join(getProjectRoot2(), "package.json"));
|
|
4702
4849
|
const resolvedPath = userRequire.resolve(pluginKey);
|
|
4703
4850
|
const pluginModule = await import(resolvedPath);
|
|
4704
4851
|
const pluginPackage = pluginModule.default ?? pluginModule;
|
|
@@ -4862,8 +5009,8 @@ import { execFile } from "child_process";
|
|
|
4862
5009
|
|
|
4863
5010
|
// src/commands/component/registry-preparer.ts
|
|
4864
5011
|
import fs16 from "fs";
|
|
4865
|
-
import
|
|
4866
|
-
import
|
|
5012
|
+
import path15 from "path";
|
|
5013
|
+
import os2 from "os";
|
|
4867
5014
|
|
|
4868
5015
|
// src/commands/component/service.ts
|
|
4869
5016
|
import { mapValues } from "es-toolkit";
|
|
@@ -4918,7 +5065,7 @@ async function sendInstallEvent(key) {
|
|
|
4918
5065
|
}
|
|
4919
5066
|
|
|
4920
5067
|
// src/commands/component/registry-preparer.ts
|
|
4921
|
-
var REGISTRY_TEMP_DIR =
|
|
5068
|
+
var REGISTRY_TEMP_DIR = path15.join(os2.tmpdir(), "miaoda-registry");
|
|
4922
5069
|
function parseComponentKey(key) {
|
|
4923
5070
|
const match = key.match(/^@([^/]+)\/(.+)$/);
|
|
4924
5071
|
if (!match) {
|
|
@@ -4930,7 +5077,7 @@ function parseComponentKey(key) {
|
|
|
4930
5077
|
}
|
|
4931
5078
|
function getLocalRegistryPath(key) {
|
|
4932
5079
|
const { scope, name } = parseComponentKey(key);
|
|
4933
|
-
return
|
|
5080
|
+
return path15.join(REGISTRY_TEMP_DIR, scope, `${name}.json`);
|
|
4934
5081
|
}
|
|
4935
5082
|
function ensureDir(dirPath) {
|
|
4936
5083
|
if (!fs16.existsSync(dirPath)) {
|
|
@@ -4967,7 +5114,7 @@ async function prepareRecursive(key, visited) {
|
|
|
4967
5114
|
registryDependencies: deps.map((dep) => getLocalRegistryPath(dep))
|
|
4968
5115
|
};
|
|
4969
5116
|
const localPath = getLocalRegistryPath(key);
|
|
4970
|
-
ensureDir(
|
|
5117
|
+
ensureDir(path15.dirname(localPath));
|
|
4971
5118
|
fs16.writeFileSync(localPath, JSON.stringify(rewrittenItem, null, 2), "utf-8");
|
|
4972
5119
|
debug("\u4FDD\u5B58\u5230: %s", localPath);
|
|
4973
5120
|
}
|
|
@@ -5158,11 +5305,11 @@ var componentCommandGroup = {
|
|
|
5158
5305
|
|
|
5159
5306
|
// src/commands/migration/version-manager.ts
|
|
5160
5307
|
import fs17 from "fs";
|
|
5161
|
-
import
|
|
5308
|
+
import path16 from "path";
|
|
5162
5309
|
var PACKAGE_JSON = "package.json";
|
|
5163
5310
|
var VERSION_FIELD = "migrationVersion";
|
|
5164
5311
|
function getPackageJsonPath2() {
|
|
5165
|
-
return
|
|
5312
|
+
return path16.join(process.cwd(), PACKAGE_JSON);
|
|
5166
5313
|
}
|
|
5167
5314
|
function getCurrentVersion() {
|
|
5168
5315
|
const pkgPath = getPackageJsonPath2();
|
|
@@ -5181,26 +5328,26 @@ function setCurrentVersion(version) {
|
|
|
5181
5328
|
|
|
5182
5329
|
// src/commands/migration/versions/v001_capability/json-migrator/detector.ts
|
|
5183
5330
|
import fs19 from "fs";
|
|
5184
|
-
import
|
|
5331
|
+
import path18 from "path";
|
|
5185
5332
|
|
|
5186
5333
|
// src/commands/migration/versions/v001_capability/utils.ts
|
|
5187
5334
|
import fs18 from "fs";
|
|
5188
|
-
import
|
|
5335
|
+
import path17 from "path";
|
|
5189
5336
|
var CAPABILITIES_DIR2 = "server/capabilities";
|
|
5190
5337
|
function getProjectRoot3() {
|
|
5191
5338
|
return process.cwd();
|
|
5192
5339
|
}
|
|
5193
5340
|
function getCapabilitiesDir2() {
|
|
5194
|
-
return
|
|
5341
|
+
return path17.join(getProjectRoot3(), CAPABILITIES_DIR2);
|
|
5195
5342
|
}
|
|
5196
5343
|
function getPluginManifestPath2(pluginKey) {
|
|
5197
|
-
return
|
|
5344
|
+
return path17.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
|
|
5198
5345
|
}
|
|
5199
5346
|
|
|
5200
5347
|
// src/commands/migration/versions/v001_capability/json-migrator/detector.ts
|
|
5201
5348
|
function detectJsonMigration() {
|
|
5202
5349
|
const capabilitiesDir = getCapabilitiesDir2();
|
|
5203
|
-
const oldFilePath =
|
|
5350
|
+
const oldFilePath = path18.join(capabilitiesDir, "capabilities.json");
|
|
5204
5351
|
if (!fs19.existsSync(oldFilePath)) {
|
|
5205
5352
|
return {
|
|
5206
5353
|
needsMigration: false,
|
|
@@ -5260,7 +5407,7 @@ async function check(options) {
|
|
|
5260
5407
|
|
|
5261
5408
|
// src/commands/migration/versions/v001_capability/json-migrator/index.ts
|
|
5262
5409
|
import fs20 from "fs";
|
|
5263
|
-
import
|
|
5410
|
+
import path19 from "path";
|
|
5264
5411
|
|
|
5265
5412
|
// src/commands/migration/versions/v001_capability/mapping.ts
|
|
5266
5413
|
var DEFAULT_PLUGIN_VERSION = "1.0.0";
|
|
@@ -5500,7 +5647,7 @@ function loadExistingCapabilities() {
|
|
|
5500
5647
|
continue;
|
|
5501
5648
|
}
|
|
5502
5649
|
try {
|
|
5503
|
-
const filePath =
|
|
5650
|
+
const filePath = path19.join(capabilitiesDir, file);
|
|
5504
5651
|
const content = fs20.readFileSync(filePath, "utf-8");
|
|
5505
5652
|
const capability = JSON.parse(content);
|
|
5506
5653
|
if (capability.id && capability.pluginKey) {
|
|
@@ -5559,7 +5706,7 @@ async function migrateJsonFiles(options) {
|
|
|
5559
5706
|
}
|
|
5560
5707
|
const capabilitiesDir = getCapabilitiesDir2();
|
|
5561
5708
|
for (const cap of newCapabilities) {
|
|
5562
|
-
const filePath =
|
|
5709
|
+
const filePath = path19.join(capabilitiesDir, `${cap.id}.json`);
|
|
5563
5710
|
const content = JSON.stringify(cap, null, 2);
|
|
5564
5711
|
fs20.writeFileSync(filePath, content, "utf-8");
|
|
5565
5712
|
console.log(` \u2713 Created: ${cap.id}.json`);
|
|
@@ -5653,12 +5800,12 @@ async function installPlugins(capabilities, options) {
|
|
|
5653
5800
|
}
|
|
5654
5801
|
|
|
5655
5802
|
// src/commands/migration/versions/v001_capability/code-migrator/index.ts
|
|
5656
|
-
import
|
|
5803
|
+
import path21 from "path";
|
|
5657
5804
|
import { Project as Project3 } from "ts-morph";
|
|
5658
5805
|
|
|
5659
5806
|
// src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
|
|
5660
5807
|
import fs22 from "fs";
|
|
5661
|
-
import
|
|
5808
|
+
import path20 from "path";
|
|
5662
5809
|
var EXCLUDED_DIRS = [
|
|
5663
5810
|
"node_modules",
|
|
5664
5811
|
"dist",
|
|
@@ -5675,7 +5822,7 @@ var EXCLUDED_PATTERNS = [
|
|
|
5675
5822
|
function scanDirectory(dir, files = []) {
|
|
5676
5823
|
const entries = fs22.readdirSync(dir, { withFileTypes: true });
|
|
5677
5824
|
for (const entry of entries) {
|
|
5678
|
-
const fullPath =
|
|
5825
|
+
const fullPath = path20.join(dir, entry.name);
|
|
5679
5826
|
if (entry.isDirectory()) {
|
|
5680
5827
|
if (EXCLUDED_DIRS.includes(entry.name)) {
|
|
5681
5828
|
continue;
|
|
@@ -5691,7 +5838,7 @@ function scanDirectory(dir, files = []) {
|
|
|
5691
5838
|
return files;
|
|
5692
5839
|
}
|
|
5693
5840
|
function scanServerFiles() {
|
|
5694
|
-
const serverDir =
|
|
5841
|
+
const serverDir = path20.join(getProjectRoot3(), "server");
|
|
5695
5842
|
if (!fs22.existsSync(serverDir)) {
|
|
5696
5843
|
return [];
|
|
5697
5844
|
}
|
|
@@ -6075,7 +6222,7 @@ function analyzeFile(project, filePath, actionNameMap) {
|
|
|
6075
6222
|
const callSites = analyzeCallSites(sourceFile, imports);
|
|
6076
6223
|
const classInfo = analyzeClass(sourceFile);
|
|
6077
6224
|
const { canMigrate, reason } = canAutoMigrate(classInfo);
|
|
6078
|
-
const relativePath =
|
|
6225
|
+
const relativePath = path21.relative(getProjectRoot3(), filePath);
|
|
6079
6226
|
return {
|
|
6080
6227
|
filePath: relativePath,
|
|
6081
6228
|
imports,
|
|
@@ -6086,7 +6233,7 @@ function analyzeFile(project, filePath, actionNameMap) {
|
|
|
6086
6233
|
};
|
|
6087
6234
|
}
|
|
6088
6235
|
function migrateFile(project, analysis, dryRun) {
|
|
6089
|
-
const absolutePath =
|
|
6236
|
+
const absolutePath = path21.join(getProjectRoot3(), analysis.filePath);
|
|
6090
6237
|
if (!analysis.canAutoMigrate) {
|
|
6091
6238
|
return {
|
|
6092
6239
|
filePath: analysis.filePath,
|
|
@@ -6190,12 +6337,12 @@ function getSuggestion(analysis) {
|
|
|
6190
6337
|
|
|
6191
6338
|
// src/commands/migration/versions/v001_capability/cleanup.ts
|
|
6192
6339
|
import fs23 from "fs";
|
|
6193
|
-
import
|
|
6340
|
+
import path22 from "path";
|
|
6194
6341
|
function cleanupOldFiles(capabilities, dryRun) {
|
|
6195
6342
|
const deletedFiles = [];
|
|
6196
6343
|
const errors = [];
|
|
6197
6344
|
const capabilitiesDir = getCapabilitiesDir2();
|
|
6198
|
-
const oldJsonPath =
|
|
6345
|
+
const oldJsonPath = path22.join(capabilitiesDir, "capabilities.json");
|
|
6199
6346
|
if (fs23.existsSync(oldJsonPath)) {
|
|
6200
6347
|
try {
|
|
6201
6348
|
if (!dryRun) {
|
|
@@ -6207,7 +6354,7 @@ function cleanupOldFiles(capabilities, dryRun) {
|
|
|
6207
6354
|
}
|
|
6208
6355
|
}
|
|
6209
6356
|
for (const cap of capabilities) {
|
|
6210
|
-
const tsFilePath =
|
|
6357
|
+
const tsFilePath = path22.join(capabilitiesDir, `${cap.id}.ts`);
|
|
6211
6358
|
if (fs23.existsSync(tsFilePath)) {
|
|
6212
6359
|
try {
|
|
6213
6360
|
if (!dryRun) {
|
|
@@ -6228,7 +6375,7 @@ function cleanupOldFiles(capabilities, dryRun) {
|
|
|
6228
6375
|
|
|
6229
6376
|
// src/commands/migration/versions/v001_capability/report-generator.ts
|
|
6230
6377
|
import fs24 from "fs";
|
|
6231
|
-
import
|
|
6378
|
+
import path23 from "path";
|
|
6232
6379
|
var REPORT_FILE = "capability-migration-report.md";
|
|
6233
6380
|
function printSummary(result) {
|
|
6234
6381
|
const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
|
|
@@ -6394,11 +6541,11 @@ async function generateReport(result) {
|
|
|
6394
6541
|
if (!fs24.existsSync(logDir)) {
|
|
6395
6542
|
return;
|
|
6396
6543
|
}
|
|
6397
|
-
const reportDir =
|
|
6544
|
+
const reportDir = path23.join(logDir, "migration");
|
|
6398
6545
|
if (!fs24.existsSync(reportDir)) {
|
|
6399
6546
|
fs24.mkdirSync(reportDir, { recursive: true });
|
|
6400
6547
|
}
|
|
6401
|
-
const reportPath =
|
|
6548
|
+
const reportPath = path23.join(reportDir, REPORT_FILE);
|
|
6402
6549
|
fs24.writeFileSync(reportPath, lines.join("\n"), "utf-8");
|
|
6403
6550
|
console.log(`\u{1F4C4} Report generated: ${reportPath}`);
|
|
6404
6551
|
}
|
|
@@ -6931,7 +7078,7 @@ var migrationCommand = {
|
|
|
6931
7078
|
};
|
|
6932
7079
|
|
|
6933
7080
|
// src/commands/read-logs/index.ts
|
|
6934
|
-
import
|
|
7081
|
+
import path24 from "path";
|
|
6935
7082
|
|
|
6936
7083
|
// src/commands/read-logs/std-utils.ts
|
|
6937
7084
|
import fs25 from "fs";
|
|
@@ -7698,7 +7845,7 @@ function sanitizeStructuredLog(value) {
|
|
|
7698
7845
|
delete sanitized.pid;
|
|
7699
7846
|
return sanitized;
|
|
7700
7847
|
}
|
|
7701
|
-
var TRANSIENT_CONNECTION_ERROR_PATTERN = /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENETUNREACH|
|
|
7848
|
+
var TRANSIENT_CONNECTION_ERROR_PATTERN = /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENETUNREACH|proxy error|\[Proxy\] (?:Error:\s*$|Error during|Connection error|Non-connection error|Headers already sent|Service (?:recovered|did not recover))/i;
|
|
7702
7849
|
function hasErrorInStdLines(lines) {
|
|
7703
7850
|
const filtered = lines.filter((line) => !TRANSIENT_CONNECTION_ERROR_PATTERN.test(line));
|
|
7704
7851
|
const combined = filtered.join("\n");
|
|
@@ -7833,30 +7980,30 @@ async function readLogsJsonResult(options) {
|
|
|
7833
7980
|
};
|
|
7834
7981
|
}
|
|
7835
7982
|
function resolveLogFilePath(logDir, type) {
|
|
7836
|
-
const base =
|
|
7983
|
+
const base = path24.isAbsolute(logDir) ? logDir : path24.join(process.cwd(), logDir);
|
|
7837
7984
|
if (type === "server") {
|
|
7838
|
-
return
|
|
7985
|
+
return path24.join(base, "server.log");
|
|
7839
7986
|
}
|
|
7840
7987
|
if (type === "trace") {
|
|
7841
|
-
return
|
|
7988
|
+
return path24.join(base, "trace.log");
|
|
7842
7989
|
}
|
|
7843
7990
|
if (type === "server-std") {
|
|
7844
|
-
return
|
|
7991
|
+
return path24.join(base, "server.std.log");
|
|
7845
7992
|
}
|
|
7846
7993
|
if (type === "client-std") {
|
|
7847
|
-
return
|
|
7994
|
+
return path24.join(base, "client.std.log");
|
|
7848
7995
|
}
|
|
7849
7996
|
if (type === "dev") {
|
|
7850
|
-
return
|
|
7997
|
+
return path24.join(base, "dev.log");
|
|
7851
7998
|
}
|
|
7852
7999
|
if (type === "dev-std") {
|
|
7853
|
-
return
|
|
8000
|
+
return path24.join(base, "dev.std.log");
|
|
7854
8001
|
}
|
|
7855
8002
|
if (type === "install-dep-std") {
|
|
7856
|
-
return
|
|
8003
|
+
return path24.join(base, "install-dep.std.log");
|
|
7857
8004
|
}
|
|
7858
8005
|
if (type === "browser") {
|
|
7859
|
-
return
|
|
8006
|
+
return path24.join(base, "browser.log");
|
|
7860
8007
|
}
|
|
7861
8008
|
throw new Error(`Unsupported log type: ${type}`);
|
|
7862
8009
|
}
|
|
@@ -8034,8 +8181,8 @@ function camelToKebab(str) {
|
|
|
8034
8181
|
|
|
8035
8182
|
// src/commands/build/upload-static.handler.ts
|
|
8036
8183
|
import * as fs28 from "fs";
|
|
8037
|
-
import * as
|
|
8038
|
-
import * as
|
|
8184
|
+
import * as os3 from "os";
|
|
8185
|
+
import * as path25 from "path";
|
|
8039
8186
|
import { execFileSync } from "child_process";
|
|
8040
8187
|
function readCredentialsFromEnv() {
|
|
8041
8188
|
const uploadPrefix = process.env.STATIC_UPLOAD_PREFIX;
|
|
@@ -8059,7 +8206,7 @@ async function uploadStatic(options) {
|
|
|
8059
8206
|
endpoint = UPLOAD_STATIC_DEFAULTS.endpoint,
|
|
8060
8207
|
region = UPLOAD_STATIC_DEFAULTS.region
|
|
8061
8208
|
} = options;
|
|
8062
|
-
const resolvedStaticDir =
|
|
8209
|
+
const resolvedStaticDir = path25.resolve(staticDir);
|
|
8063
8210
|
if (!fs28.existsSync(resolvedStaticDir)) {
|
|
8064
8211
|
console.error(`${LOG_PREFIX} \u76EE\u5F55\u4E0D\u5B58\u5728: ${resolvedStaticDir}\uFF0C\u8DF3\u8FC7\u4E0A\u4F20`);
|
|
8065
8212
|
return;
|
|
@@ -8093,7 +8240,7 @@ async function uploadStatic(options) {
|
|
|
8093
8240
|
({ AccessKeyID: accessKeyID, SecretAccessKey: secretAccessKey, SessionToken: sessionToken } = uploadCredential);
|
|
8094
8241
|
}
|
|
8095
8242
|
console.error(`${LOG_PREFIX} \u4E0A\u4F20\u76EE\u6807: ${uploadPrefix}`);
|
|
8096
|
-
const confPath =
|
|
8243
|
+
const confPath = path25.join(os3.tmpdir(), `.tosutilconfig-static-${process.pid}`);
|
|
8097
8244
|
fs28.writeFileSync(confPath, "");
|
|
8098
8245
|
try {
|
|
8099
8246
|
console.error(`${LOG_PREFIX} \u914D\u7F6E tosutil...`);
|
|
@@ -8128,7 +8275,7 @@ async function uploadStatic(options) {
|
|
|
8128
8275
|
}
|
|
8129
8276
|
}
|
|
8130
8277
|
function resolveTosutilPath(tosutilPath) {
|
|
8131
|
-
if (
|
|
8278
|
+
if (path25.isAbsolute(tosutilPath)) {
|
|
8132
8279
|
return fs28.existsSync(tosutilPath) ? tosutilPath : null;
|
|
8133
8280
|
}
|
|
8134
8281
|
try {
|
|
@@ -8221,62 +8368,3254 @@ async function preUploadStatic(options) {
|
|
|
8221
8368
|
}
|
|
8222
8369
|
}
|
|
8223
8370
|
|
|
8224
|
-
// src/commands/build/
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8371
|
+
// src/commands/build/server-cache-bundle.handler.ts
|
|
8372
|
+
import fs29 from "fs";
|
|
8373
|
+
import http from "http";
|
|
8374
|
+
import net from "net";
|
|
8375
|
+
import os4 from "os";
|
|
8376
|
+
import path26 from "path";
|
|
8377
|
+
import { builtinModules, createRequire as createRequire3 } from "module";
|
|
8378
|
+
import { spawn as spawn2 } from "child_process";
|
|
8379
|
+
import { createHash } from "crypto";
|
|
8380
|
+
import { build } from "esbuild";
|
|
8381
|
+
import { parse } from "acorn";
|
|
8382
|
+
import { simple as walkSimple } from "acorn-walk";
|
|
8383
|
+
var OPTIONAL_NEST_DEPENDENCIES = [
|
|
8384
|
+
"@nestjs/microservices",
|
|
8385
|
+
"@nestjs/microservices/microservices-module",
|
|
8386
|
+
"@nestjs/websockets/socket-module",
|
|
8387
|
+
"@node-rs/xxhash",
|
|
8388
|
+
"fsevents"
|
|
8389
|
+
];
|
|
8390
|
+
var BUILTINS = /* @__PURE__ */ new Set([
|
|
8391
|
+
...builtinModules,
|
|
8392
|
+
...builtinModules.map((name) => `node:${name}`)
|
|
8393
|
+
]);
|
|
8394
|
+
var DEFAULT_COMPILED_ENTRIES = [
|
|
8395
|
+
"dist/server/main.js",
|
|
8396
|
+
"dist/main.js"
|
|
8397
|
+
];
|
|
8398
|
+
var BUILD_ONLY_SERVER_CACHE_PACKAGES = [
|
|
8399
|
+
"@lark-apaas/nestjs-openapi-devtools",
|
|
8400
|
+
"@hey-api/openapi-ts",
|
|
8401
|
+
"typescript",
|
|
8402
|
+
"jiti",
|
|
8403
|
+
"nypm"
|
|
8404
|
+
];
|
|
8405
|
+
function workspaceSourceSha256(projectRoot) {
|
|
8406
|
+
const files = [];
|
|
8407
|
+
const visit = (directory) => {
|
|
8408
|
+
if (!fs29.existsSync(directory)) return;
|
|
8409
|
+
for (const entry of fs29.readdirSync(directory, { withFileTypes: true })) {
|
|
8410
|
+
const candidate = path26.join(directory, entry.name);
|
|
8411
|
+
if (entry.isSymbolicLink()) continue;
|
|
8412
|
+
if (entry.isDirectory()) visit(candidate);
|
|
8413
|
+
else if (entry.isFile()) files.push(candidate);
|
|
8414
|
+
}
|
|
8415
|
+
};
|
|
8416
|
+
for (const root of ["server", "shared", "src"]) {
|
|
8417
|
+
visit(path26.join(projectRoot, root));
|
|
8232
8418
|
}
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
await uploadStatic(options);
|
|
8240
|
-
});
|
|
8419
|
+
const hash = createHash("sha256");
|
|
8420
|
+
for (const file of files.sort()) {
|
|
8421
|
+
hash.update(path26.relative(projectRoot, file).split(path26.sep).join("/"));
|
|
8422
|
+
hash.update("\0");
|
|
8423
|
+
hash.update(fs29.readFileSync(file));
|
|
8424
|
+
hash.update("\0");
|
|
8241
8425
|
}
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8426
|
+
return hash.digest("hex");
|
|
8427
|
+
}
|
|
8428
|
+
function absolute(root, candidate) {
|
|
8429
|
+
return path26.isAbsolute(candidate) ? candidate : path26.resolve(root, candidate);
|
|
8430
|
+
}
|
|
8431
|
+
function isPathInside(root, candidate) {
|
|
8432
|
+
const relative = path26.relative(root, candidate);
|
|
8433
|
+
return relative === "" || !relative.startsWith("..") && !path26.isAbsolute(relative);
|
|
8434
|
+
}
|
|
8435
|
+
function validateOwnedServerOutput(projectRoot, outfile, metadataFile) {
|
|
8436
|
+
const cacheRoot = path26.join(projectRoot, ".miaoda-cache");
|
|
8437
|
+
if (!isPathInside(cacheRoot, outfile) || path26.basename(path26.dirname(outfile)) !== "server" || path26.basename(outfile) !== "server.bundle.cjs" || metadataFile !== `${outfile}.meta.json`) {
|
|
8438
|
+
return "server cache output must be <projectRoot>/.miaoda-cache/**/server/server.bundle.cjs with adjacent metadata";
|
|
8439
|
+
}
|
|
8440
|
+
let current = path26.dirname(outfile);
|
|
8441
|
+
while (current !== projectRoot) {
|
|
8442
|
+
if (fs29.existsSync(current) && fs29.lstatSync(current).isSymbolicLink()) {
|
|
8443
|
+
return `server cache output directory symlink is unsupported: ${current}`;
|
|
8444
|
+
}
|
|
8445
|
+
const parent = path26.dirname(current);
|
|
8446
|
+
if (parent === current || !isPathInside(projectRoot, parent)) {
|
|
8447
|
+
return "server cache output escaped project root";
|
|
8448
|
+
}
|
|
8449
|
+
current = parent;
|
|
8450
|
+
}
|
|
8451
|
+
return void 0;
|
|
8452
|
+
}
|
|
8453
|
+
function resolveCompiledEntry(projectRoot, requestedEntry) {
|
|
8454
|
+
if (requestedEntry) {
|
|
8455
|
+
const entry = absolute(projectRoot, requestedEntry);
|
|
8456
|
+
return fs29.existsSync(entry) ? { entry, reasons: [] } : { reasons: [`compiled entry missing: ${entry}`] };
|
|
8457
|
+
}
|
|
8458
|
+
const candidates = DEFAULT_COMPILED_ENTRIES.map(
|
|
8459
|
+
(candidate) => absolute(projectRoot, candidate)
|
|
8460
|
+
).filter((candidate) => fs29.existsSync(candidate));
|
|
8461
|
+
if (candidates.length === 1) return { entry: candidates[0], reasons: [] };
|
|
8462
|
+
if (candidates.length > 1) {
|
|
8463
|
+
return {
|
|
8464
|
+
reasons: [
|
|
8465
|
+
`compiled entry is ambiguous; pass --entry explicitly: ${candidates.join(", ")}`
|
|
8466
|
+
]
|
|
8467
|
+
};
|
|
8468
|
+
}
|
|
8469
|
+
return {
|
|
8470
|
+
reasons: [
|
|
8471
|
+
`compiled entry missing; checked: ${DEFAULT_COMPILED_ENTRIES.map(
|
|
8472
|
+
(candidate) => absolute(projectRoot, candidate)
|
|
8473
|
+
).join(", ")}`
|
|
8474
|
+
]
|
|
8475
|
+
};
|
|
8476
|
+
}
|
|
8477
|
+
function optionalDependencyStubPlugin() {
|
|
8478
|
+
const escaped = OPTIONAL_NEST_DEPENDENCIES.map(
|
|
8479
|
+
(name) => name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
8480
|
+
);
|
|
8481
|
+
const filter = new RegExp(`^(?:${escaped.join("|")})$`);
|
|
8482
|
+
return {
|
|
8483
|
+
name: "miaoda-optional-nest-dependency-stubs",
|
|
8484
|
+
setup(esbuild) {
|
|
8485
|
+
esbuild.onResolve({ filter }, (args) => ({
|
|
8486
|
+
path: args.path,
|
|
8487
|
+
namespace: "miaoda-optional-nest-dependency"
|
|
8488
|
+
}));
|
|
8489
|
+
esbuild.onLoad(
|
|
8490
|
+
{ filter: /.*/, namespace: "miaoda-optional-nest-dependency" },
|
|
8491
|
+
(args) => ({
|
|
8492
|
+
contents: `const error = new Error(${JSON.stringify(
|
|
8493
|
+
`Optional dependency is unavailable in cache runtime: ${args.path}`
|
|
8494
|
+
)}); error.code = 'MODULE_NOT_FOUND'; throw error;`,
|
|
8495
|
+
loader: "js"
|
|
8496
|
+
})
|
|
8497
|
+
);
|
|
8498
|
+
}
|
|
8499
|
+
};
|
|
8500
|
+
}
|
|
8501
|
+
function classTransformerStorageResolver(projectRoot) {
|
|
8502
|
+
const projectRequire = createRequire3(path26.join(projectRoot, "package.json"));
|
|
8503
|
+
return {
|
|
8504
|
+
name: "miaoda-class-transformer-storage-resolver",
|
|
8505
|
+
setup(esbuild) {
|
|
8506
|
+
esbuild.onResolve({ filter: /^class-transformer\/storage$/ }, () => {
|
|
8507
|
+
try {
|
|
8508
|
+
return {
|
|
8509
|
+
path: projectRequire.resolve("class-transformer/cjs/storage.js")
|
|
8510
|
+
};
|
|
8511
|
+
} catch {
|
|
8512
|
+
return void 0;
|
|
8513
|
+
}
|
|
8514
|
+
});
|
|
8515
|
+
}
|
|
8516
|
+
};
|
|
8517
|
+
}
|
|
8518
|
+
function resolveProjectPackage(projectRoot, specifier) {
|
|
8519
|
+
return createRequire3(path26.join(projectRoot, "package.json")).resolve(
|
|
8520
|
+
specifier
|
|
8521
|
+
);
|
|
8522
|
+
}
|
|
8523
|
+
function fullstackNestRuntimeResolver(projectRoot) {
|
|
8524
|
+
return {
|
|
8525
|
+
name: "miaoda-fullstack-nest-runtime-resolver",
|
|
8526
|
+
setup(esbuild) {
|
|
8527
|
+
esbuild.onResolve(
|
|
8528
|
+
{ filter: /^@lark-apaas\/fullstack-nestjs-core$/ },
|
|
8529
|
+
() => {
|
|
8530
|
+
try {
|
|
8531
|
+
return {
|
|
8532
|
+
path: resolveProjectPackage(
|
|
8533
|
+
projectRoot,
|
|
8534
|
+
"@lark-apaas/fullstack-nestjs-core/runtime"
|
|
8535
|
+
)
|
|
8536
|
+
};
|
|
8537
|
+
} catch (runtimeError) {
|
|
8538
|
+
try {
|
|
8539
|
+
return {
|
|
8540
|
+
path: resolveProjectPackage(
|
|
8541
|
+
projectRoot,
|
|
8542
|
+
"@lark-apaas/fullstack-nestjs-core"
|
|
8543
|
+
)
|
|
8544
|
+
};
|
|
8545
|
+
} catch (rootError) {
|
|
8546
|
+
return {
|
|
8547
|
+
errors: [
|
|
8548
|
+
{
|
|
8549
|
+
text: `@lark-apaas/fullstack-nestjs-core cannot be resolved from the project: runtime=${runtimeError instanceof Error ? runtimeError.message : String(runtimeError)}; root=${rootError instanceof Error ? rootError.message : String(rootError)}`
|
|
8550
|
+
}
|
|
8551
|
+
]
|
|
8552
|
+
};
|
|
8553
|
+
}
|
|
8554
|
+
}
|
|
8555
|
+
}
|
|
8556
|
+
);
|
|
8557
|
+
}
|
|
8558
|
+
};
|
|
8559
|
+
}
|
|
8560
|
+
function legacyFullstackNestOpenApiStub(projectRoot) {
|
|
8561
|
+
let runtimeOnlyEntryAvailable = false;
|
|
8562
|
+
try {
|
|
8563
|
+
resolveProjectPackage(
|
|
8564
|
+
projectRoot,
|
|
8565
|
+
"@lark-apaas/fullstack-nestjs-core/runtime"
|
|
8566
|
+
);
|
|
8567
|
+
runtimeOnlyEntryAvailable = true;
|
|
8568
|
+
} catch {
|
|
8569
|
+
}
|
|
8570
|
+
return {
|
|
8571
|
+
name: "miaoda-legacy-nest-openapi-stub",
|
|
8572
|
+
setup(esbuild) {
|
|
8573
|
+
if (runtimeOnlyEntryAvailable) return;
|
|
8574
|
+
esbuild.onResolve(
|
|
8575
|
+
{ filter: /^@lark-apaas\/nestjs-openapi-devtools$/ },
|
|
8576
|
+
() => ({
|
|
8577
|
+
path: "@lark-apaas/nestjs-openapi-devtools",
|
|
8578
|
+
namespace: "miaoda-legacy-nest-openapi-stub"
|
|
8579
|
+
})
|
|
8580
|
+
);
|
|
8581
|
+
esbuild.onLoad(
|
|
8582
|
+
{ filter: /.*/, namespace: "miaoda-legacy-nest-openapi-stub" },
|
|
8583
|
+
() => ({
|
|
8584
|
+
contents: "class DisabledOpenApiModule { static async mount() {} }\nmodule.exports = { DevToolsModule: DisabledOpenApiModule, DevToolsV2Module: DisabledOpenApiModule };",
|
|
8585
|
+
loader: "js"
|
|
8586
|
+
})
|
|
8587
|
+
);
|
|
8588
|
+
}
|
|
8589
|
+
};
|
|
8590
|
+
}
|
|
8591
|
+
function rejectNativeAddonsPlugin() {
|
|
8592
|
+
return {
|
|
8593
|
+
name: "miaoda-reject-native-addons",
|
|
8594
|
+
setup(esbuild) {
|
|
8595
|
+
esbuild.onResolve({ filter: /\.node$/ }, (args) => {
|
|
8596
|
+
if (args.path.startsWith(".") && fs29.existsSync(path26.resolve(args.resolveDir, `${args.path}.js`))) {
|
|
8597
|
+
return void 0;
|
|
8598
|
+
}
|
|
8599
|
+
return {
|
|
8600
|
+
errors: [
|
|
8601
|
+
{
|
|
8602
|
+
text: `native addons are unsupported in the server cache bundle: ${args.path}`
|
|
8603
|
+
}
|
|
8604
|
+
]
|
|
8605
|
+
};
|
|
8606
|
+
});
|
|
8607
|
+
}
|
|
8608
|
+
};
|
|
8609
|
+
}
|
|
8610
|
+
function findPackageRoot(entryPath) {
|
|
8611
|
+
let current = path26.dirname(entryPath);
|
|
8612
|
+
while (current !== path26.dirname(current)) {
|
|
8613
|
+
if (fs29.existsSync(path26.join(current, "package.json"))) return current;
|
|
8614
|
+
current = path26.dirname(current);
|
|
8615
|
+
}
|
|
8616
|
+
return void 0;
|
|
8617
|
+
}
|
|
8618
|
+
function canonicalSourcePath(projectRoot, sourcePath) {
|
|
8619
|
+
const relativeOrigin = path26.relative(projectRoot, sourcePath).split(path26.sep).join("/");
|
|
8620
|
+
const nestedPackageMarker = "/node_modules/";
|
|
8621
|
+
const nestedPackageIndex = relativeOrigin.lastIndexOf(nestedPackageMarker);
|
|
8622
|
+
const firstPackageIndex = relativeOrigin.indexOf("node_modules/");
|
|
8623
|
+
if (nestedPackageIndex >= 0) {
|
|
8624
|
+
return `node_modules/${relativeOrigin.slice(
|
|
8625
|
+
nestedPackageIndex + nestedPackageMarker.length
|
|
8626
|
+
)}`;
|
|
8627
|
+
}
|
|
8628
|
+
return firstPackageIndex > 0 ? relativeOrigin.slice(firstPackageIndex) : relativeOrigin;
|
|
8629
|
+
}
|
|
8630
|
+
function parseJavaScriptSource(source) {
|
|
8631
|
+
try {
|
|
8632
|
+
return parse(source, {
|
|
8633
|
+
ecmaVersion: "latest",
|
|
8634
|
+
sourceType: "module",
|
|
8635
|
+
allowHashBang: true,
|
|
8636
|
+
locations: true
|
|
8637
|
+
});
|
|
8638
|
+
} catch {
|
|
8639
|
+
return parse(source, {
|
|
8640
|
+
ecmaVersion: "latest",
|
|
8641
|
+
sourceType: "script",
|
|
8642
|
+
allowHashBang: true,
|
|
8643
|
+
allowReturnOutsideFunction: true,
|
|
8644
|
+
locations: true
|
|
8249
8645
|
});
|
|
8250
8646
|
}
|
|
8251
|
-
}
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
}
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8647
|
+
}
|
|
8648
|
+
function staticStringValue(node) {
|
|
8649
|
+
if (!node) return void 0;
|
|
8650
|
+
if (node.type === "Literal" && typeof node.value === "string") {
|
|
8651
|
+
return node.value;
|
|
8652
|
+
}
|
|
8653
|
+
if (node.type === "TemplateLiteral" && node.expressions.length === 0) {
|
|
8654
|
+
return node.quasis[0]?.value?.cooked ?? "";
|
|
8655
|
+
}
|
|
8656
|
+
return void 0;
|
|
8657
|
+
}
|
|
8658
|
+
function isImportMetaUrl(node) {
|
|
8659
|
+
return Boolean(
|
|
8660
|
+
node?.type === "MemberExpression" && staticPropertyName(node) === "url" && node.object?.type === "MetaProperty" && node.object.meta?.name === "import" && node.object.property?.name === "meta"
|
|
8661
|
+
);
|
|
8662
|
+
}
|
|
8663
|
+
function isBundleDirectoryExpression(node) {
|
|
8664
|
+
if (!node) return false;
|
|
8665
|
+
if (node.type === "Identifier" && node.name === "__dirname") return true;
|
|
8666
|
+
if (node.type !== "CallExpression") return false;
|
|
8667
|
+
const property = staticPropertyName(node.callee);
|
|
8668
|
+
if (property === "dirname" && (node.arguments[0]?.type === "Identifier" && node.arguments[0].name === "__filename" ? true : node.arguments[0]?.type === "CallExpression" && staticPropertyName(node.arguments[0].callee) === "fileURLToPath" && isImportMetaUrl(node.arguments[0].arguments[0]))) {
|
|
8669
|
+
return true;
|
|
8670
|
+
}
|
|
8671
|
+
return false;
|
|
8672
|
+
}
|
|
8673
|
+
function canonicalRuntimeAssetPath(candidate) {
|
|
8674
|
+
const normalized = candidate.split(path26.sep).join("/");
|
|
8675
|
+
if (!normalized || normalized === "." || normalized !== path26.posix.normalize(normalized) || normalized.startsWith("../") || path26.posix.isAbsolute(normalized) || normalized.includes("\\")) {
|
|
8676
|
+
return void 0;
|
|
8677
|
+
}
|
|
8678
|
+
return normalized;
|
|
8679
|
+
}
|
|
8680
|
+
function resolveRuntimeAssetExpression(projectRoot, sourcePath, node) {
|
|
8681
|
+
const direct = staticStringValue(node);
|
|
8682
|
+
if (direct !== void 0 && !path26.isAbsolute(direct)) {
|
|
8683
|
+
const destination2 = canonicalRuntimeAssetPath(direct);
|
|
8684
|
+
return destination2 ? { source: path26.resolve(projectRoot, direct), destination: destination2 } : void 0;
|
|
8685
|
+
}
|
|
8686
|
+
if (node?.type === "NewExpression" && node.callee?.type === "Identifier" && node.callee.name === "URL") {
|
|
8687
|
+
const relative2 = staticStringValue(node.arguments[0]);
|
|
8688
|
+
if (relative2 && isImportMetaUrl(node.arguments[1])) {
|
|
8689
|
+
const destination2 = canonicalRuntimeAssetPath(
|
|
8690
|
+
relative2.replace(/^\.\//, "")
|
|
8691
|
+
);
|
|
8692
|
+
return destination2 ? {
|
|
8693
|
+
source: path26.resolve(path26.dirname(sourcePath), relative2),
|
|
8694
|
+
destination: destination2
|
|
8695
|
+
} : void 0;
|
|
8696
|
+
}
|
|
8697
|
+
}
|
|
8698
|
+
if (node?.type !== "CallExpression") return void 0;
|
|
8699
|
+
const property = staticPropertyName(node.callee);
|
|
8700
|
+
if (!["join", "resolve"].includes(property ?? "")) return void 0;
|
|
8701
|
+
if (!isBundleDirectoryExpression(node.arguments[0])) return void 0;
|
|
8702
|
+
const segments = node.arguments.slice(1).map(staticStringValue);
|
|
8703
|
+
if (segments.some((segment) => segment === void 0)) return void 0;
|
|
8704
|
+
const relative = path26.join(...segments);
|
|
8705
|
+
const destination = canonicalRuntimeAssetPath(relative);
|
|
8706
|
+
return destination ? {
|
|
8707
|
+
source: path26.resolve(path26.dirname(sourcePath), relative),
|
|
8708
|
+
destination
|
|
8709
|
+
} : void 0;
|
|
8710
|
+
}
|
|
8711
|
+
function isFsModuleSpecifier(node) {
|
|
8712
|
+
return ["fs", "node:fs"].includes(staticStringValue(node) ?? "");
|
|
8713
|
+
}
|
|
8714
|
+
function containsFsModuleLoad(node) {
|
|
8715
|
+
if (!node) return false;
|
|
8716
|
+
if (node.type === "CallExpression" && node.callee?.type === "Identifier" && node.callee.name === "require" && isFsModuleSpecifier(node.arguments[0])) {
|
|
8717
|
+
return true;
|
|
8718
|
+
}
|
|
8719
|
+
if (node.type === "CallExpression") {
|
|
8720
|
+
return node.arguments.some(
|
|
8721
|
+
(argument) => containsFsModuleLoad(argument)
|
|
8722
|
+
);
|
|
8723
|
+
}
|
|
8724
|
+
if (node.type === "MemberExpression") {
|
|
8725
|
+
return containsFsModuleLoad(node.object);
|
|
8726
|
+
}
|
|
8727
|
+
if (node.type === "ChainExpression") {
|
|
8728
|
+
return containsFsModuleLoad(node.expression);
|
|
8729
|
+
}
|
|
8730
|
+
return false;
|
|
8731
|
+
}
|
|
8732
|
+
function rootIdentifier(node) {
|
|
8733
|
+
let current = node;
|
|
8734
|
+
while (current?.type === "MemberExpression") current = current.object;
|
|
8735
|
+
return current?.type === "Identifier" ? current.name : void 0;
|
|
8736
|
+
}
|
|
8737
|
+
function collectFsBindings(ast, runtimeFsMethods) {
|
|
8738
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
8739
|
+
const methods = /* @__PURE__ */ new Set();
|
|
8740
|
+
walkSimple(ast, {
|
|
8741
|
+
ImportDeclaration(node) {
|
|
8742
|
+
if (!isFsModuleSpecifier(node.source)) return;
|
|
8743
|
+
for (const specifier of node.specifiers ?? []) {
|
|
8744
|
+
if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
|
|
8745
|
+
namespaces.add(specifier.local.name);
|
|
8746
|
+
continue;
|
|
8747
|
+
}
|
|
8748
|
+
if (specifier.type !== "ImportSpecifier") continue;
|
|
8749
|
+
const imported = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
|
|
8750
|
+
if (typeof imported === "string" && runtimeFsMethods.has(imported)) {
|
|
8751
|
+
methods.add(specifier.local.name);
|
|
8752
|
+
}
|
|
8753
|
+
}
|
|
8754
|
+
},
|
|
8755
|
+
VariableDeclarator(node) {
|
|
8756
|
+
if (!containsFsModuleLoad(node.init)) return;
|
|
8757
|
+
if (node.id?.type === "Identifier") {
|
|
8758
|
+
const importedMethod = staticPropertyName(node.init);
|
|
8759
|
+
if (importedMethod && runtimeFsMethods.has(importedMethod)) {
|
|
8760
|
+
methods.add(node.id.name);
|
|
8761
|
+
} else {
|
|
8762
|
+
namespaces.add(node.id.name);
|
|
8763
|
+
}
|
|
8764
|
+
return;
|
|
8765
|
+
}
|
|
8766
|
+
if (node.id?.type === "ObjectPattern") {
|
|
8767
|
+
for (const property of node.id.properties ?? []) {
|
|
8768
|
+
if (property.type === "RestElement") continue;
|
|
8769
|
+
const imported = property.key.type === "Identifier" ? property.key.name : staticStringValue(property.key);
|
|
8770
|
+
const local = property.value.type === "Identifier" ? property.value.name : void 0;
|
|
8771
|
+
if (typeof imported === "string" && runtimeFsMethods.has(imported) && typeof local === "string") {
|
|
8772
|
+
methods.add(local);
|
|
8773
|
+
}
|
|
8774
|
+
}
|
|
8775
|
+
}
|
|
8776
|
+
}
|
|
8777
|
+
});
|
|
8778
|
+
return { namespaces, methods };
|
|
8779
|
+
}
|
|
8780
|
+
function resolveFsMethod(callee, bindings, runtimeFsMethods) {
|
|
8781
|
+
if (callee.type === "Identifier" && bindings.methods.has(callee.name)) {
|
|
8782
|
+
return callee.name;
|
|
8783
|
+
}
|
|
8784
|
+
const method = staticPropertyName(callee);
|
|
8785
|
+
if (!method || !runtimeFsMethods.has(method)) return void 0;
|
|
8786
|
+
if (callee.type !== "MemberExpression") return void 0;
|
|
8787
|
+
if (containsFsModuleLoad(callee.object)) return method;
|
|
8788
|
+
const root = rootIdentifier(callee.object);
|
|
8789
|
+
return root && bindings.namespaces.has(root) ? method : void 0;
|
|
8790
|
+
}
|
|
8791
|
+
function isChildProcessModuleSpecifier(node) {
|
|
8792
|
+
return ["child_process", "node:child_process"].includes(
|
|
8793
|
+
staticStringValue(node) ?? ""
|
|
8794
|
+
);
|
|
8795
|
+
}
|
|
8796
|
+
function containsChildProcessLoad(node) {
|
|
8797
|
+
if (!node) return false;
|
|
8798
|
+
if (node.type === "CallExpression" && node.callee?.type === "Identifier" && node.callee.name === "require" && isChildProcessModuleSpecifier(node.arguments[0])) {
|
|
8799
|
+
return true;
|
|
8800
|
+
}
|
|
8801
|
+
if (node.type === "MemberExpression") {
|
|
8802
|
+
return containsChildProcessLoad(node.object);
|
|
8803
|
+
}
|
|
8804
|
+
return false;
|
|
8805
|
+
}
|
|
8806
|
+
function collectChildProcessForkBindings(ast) {
|
|
8807
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
8808
|
+
const methods = /* @__PURE__ */ new Set();
|
|
8809
|
+
walkSimple(ast, {
|
|
8810
|
+
ImportDeclaration(node) {
|
|
8811
|
+
if (!isChildProcessModuleSpecifier(node.source)) return;
|
|
8812
|
+
for (const specifier of node.specifiers ?? []) {
|
|
8813
|
+
if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
|
|
8814
|
+
namespaces.add(specifier.local.name);
|
|
8815
|
+
} else if (specifier.type === "ImportSpecifier" && (specifier.imported?.name === "fork" || specifier.imported?.value === "fork")) {
|
|
8816
|
+
methods.add(specifier.local.name);
|
|
8817
|
+
}
|
|
8818
|
+
}
|
|
8819
|
+
},
|
|
8820
|
+
VariableDeclarator(node) {
|
|
8821
|
+
if (!containsChildProcessLoad(node.init)) return;
|
|
8822
|
+
if (node.id?.type === "Identifier") {
|
|
8823
|
+
if (staticPropertyName(node.init) === "fork") {
|
|
8824
|
+
methods.add(node.id.name);
|
|
8825
|
+
} else {
|
|
8826
|
+
namespaces.add(node.id.name);
|
|
8827
|
+
}
|
|
8828
|
+
} else if (node.id?.type === "ObjectPattern") {
|
|
8829
|
+
for (const property of node.id.properties ?? []) {
|
|
8830
|
+
const imported = property.type !== "RestElement" && property.key?.type === "Identifier" ? property.key.name : property.type !== "RestElement" ? staticStringValue(property.key) : void 0;
|
|
8831
|
+
if (property.type !== "RestElement" && imported === "fork" && property.value?.type === "Identifier") {
|
|
8832
|
+
methods.add(property.value.name);
|
|
8833
|
+
}
|
|
8834
|
+
}
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
});
|
|
8838
|
+
return { namespaces, methods };
|
|
8839
|
+
}
|
|
8840
|
+
function isChildProcessFork(callee, bindings) {
|
|
8841
|
+
if (callee.type === "Identifier") return bindings.methods.has(callee.name);
|
|
8842
|
+
if (callee.type !== "MemberExpression" || staticPropertyName(callee) !== "fork") {
|
|
8843
|
+
return false;
|
|
8276
8844
|
}
|
|
8845
|
+
if (containsChildProcessLoad(callee.object)) return true;
|
|
8846
|
+
const root = rootIdentifier(callee.object);
|
|
8847
|
+
return Boolean(root && bindings.namespaces.has(root));
|
|
8277
8848
|
}
|
|
8278
|
-
|
|
8279
|
-
|
|
8849
|
+
function materializeServerRuntimeAssets(projectRoot, metafile, bundleDirectory, configuredAssets = []) {
|
|
8850
|
+
const candidates = [];
|
|
8851
|
+
const warnings = [];
|
|
8852
|
+
const runtimeFsMethods = /* @__PURE__ */ new Set([
|
|
8853
|
+
"readFile",
|
|
8854
|
+
"readFileSync",
|
|
8855
|
+
"createReadStream",
|
|
8856
|
+
"open",
|
|
8857
|
+
"openSync"
|
|
8858
|
+
]);
|
|
8859
|
+
for (const input of Object.keys(metafile.inputs).sort()) {
|
|
8860
|
+
if (!/\.(?:cjs|mjs|js)$/.test(input)) continue;
|
|
8861
|
+
const sourcePath = path26.resolve(projectRoot, input);
|
|
8862
|
+
if (!fs29.existsSync(sourcePath) || !fs29.statSync(sourcePath).isFile()) {
|
|
8863
|
+
continue;
|
|
8864
|
+
}
|
|
8865
|
+
const source = fs29.readFileSync(sourcePath, "utf8");
|
|
8866
|
+
const origin = canonicalSourcePath(projectRoot, sourcePath);
|
|
8867
|
+
const ast = parseJavaScriptSource(source);
|
|
8868
|
+
const fsBindings = collectFsBindings(ast, runtimeFsMethods);
|
|
8869
|
+
const childProcessBindings = collectChildProcessForkBindings(ast);
|
|
8870
|
+
const recordRuntimeAsset = (expressionNode) => {
|
|
8871
|
+
const resolved = resolveRuntimeAssetExpression(
|
|
8872
|
+
projectRoot,
|
|
8873
|
+
sourcePath,
|
|
8874
|
+
expressionNode
|
|
8875
|
+
);
|
|
8876
|
+
if (resolved && fs29.existsSync(resolved.source)) {
|
|
8877
|
+
candidates.push({ ...resolved, origin });
|
|
8878
|
+
return;
|
|
8879
|
+
}
|
|
8880
|
+
const expression = source.slice(
|
|
8881
|
+
expressionNode?.start ?? 0,
|
|
8882
|
+
expressionNode?.end ?? source.length
|
|
8883
|
+
);
|
|
8884
|
+
warnings.push({
|
|
8885
|
+
kind: resolved ? "missing-runtime-asset" : "dynamic-runtime-asset",
|
|
8886
|
+
source: origin,
|
|
8887
|
+
expressionHash: createHash("sha256").update(expression).digest("hex").slice(0, 16),
|
|
8888
|
+
message: resolved ? `Static runtime asset is unavailable at build time: ${resolved.destination}` : "Runtime asset path cannot be determined statically"
|
|
8889
|
+
});
|
|
8890
|
+
};
|
|
8891
|
+
walkSimple(ast, {
|
|
8892
|
+
CallExpression(node) {
|
|
8893
|
+
const method = resolveFsMethod(
|
|
8894
|
+
node.callee,
|
|
8895
|
+
fsBindings,
|
|
8896
|
+
runtimeFsMethods
|
|
8897
|
+
);
|
|
8898
|
+
if (method || isChildProcessFork(node.callee, childProcessBindings)) {
|
|
8899
|
+
recordRuntimeAsset(node.arguments[0]);
|
|
8900
|
+
}
|
|
8901
|
+
},
|
|
8902
|
+
NewExpression(node) {
|
|
8903
|
+
if (node.callee?.type === "Identifier" && node.callee.name === "URL" && isImportMetaUrl(node.arguments[1])) {
|
|
8904
|
+
recordRuntimeAsset(node);
|
|
8905
|
+
return;
|
|
8906
|
+
}
|
|
8907
|
+
if (node.callee?.type === "Identifier" && ["Worker", "SharedWorker"].includes(node.callee.name)) {
|
|
8908
|
+
recordRuntimeAsset(node.arguments[0]);
|
|
8909
|
+
}
|
|
8910
|
+
}
|
|
8911
|
+
});
|
|
8912
|
+
}
|
|
8913
|
+
for (const configured of configuredAssets) {
|
|
8914
|
+
if (typeof configured?.source !== "string" || !configured.source || typeof configured?.path !== "string") {
|
|
8915
|
+
throw new Error("configured runtime asset must include source and path");
|
|
8916
|
+
}
|
|
8917
|
+
const destination = canonicalRuntimeAssetPath(configured.path);
|
|
8918
|
+
if (!destination) {
|
|
8919
|
+
throw new Error(
|
|
8920
|
+
`configured runtime asset path is invalid: ${configured.path}`
|
|
8921
|
+
);
|
|
8922
|
+
}
|
|
8923
|
+
const source = path26.resolve(projectRoot, configured.source);
|
|
8924
|
+
if (!isPathInside(projectRoot, source) || !fs29.existsSync(source)) {
|
|
8925
|
+
throw new Error(
|
|
8926
|
+
`configured runtime asset source is invalid: ${configured.source}`
|
|
8927
|
+
);
|
|
8928
|
+
}
|
|
8929
|
+
candidates.push({ source, destination, origin: "package.json" });
|
|
8930
|
+
}
|
|
8931
|
+
const published = /* @__PURE__ */ new Map();
|
|
8932
|
+
const assertNoSymlinkPath = (source) => {
|
|
8933
|
+
const relative = path26.relative(projectRoot, source);
|
|
8934
|
+
if (!relative || relative.startsWith("..") || path26.isAbsolute(relative)) {
|
|
8935
|
+
throw new Error(`server runtime asset source escaped project: ${source}`);
|
|
8936
|
+
}
|
|
8937
|
+
let current = projectRoot;
|
|
8938
|
+
for (const segment of relative.split(path26.sep)) {
|
|
8939
|
+
current = path26.join(current, segment);
|
|
8940
|
+
if (fs29.lstatSync(current).isSymbolicLink()) {
|
|
8941
|
+
throw new Error(
|
|
8942
|
+
`server runtime asset symlink is unsupported: ${current}`
|
|
8943
|
+
);
|
|
8944
|
+
}
|
|
8945
|
+
}
|
|
8946
|
+
};
|
|
8947
|
+
const publishFile = (source, destination) => {
|
|
8948
|
+
const assetPath = canonicalRuntimeAssetPath(destination);
|
|
8949
|
+
if (!assetPath) {
|
|
8950
|
+
throw new Error(`server runtime asset path is invalid: ${destination}`);
|
|
8951
|
+
}
|
|
8952
|
+
assertNoSymlinkPath(source);
|
|
8953
|
+
const target = path26.join(bundleDirectory, ...assetPath.split("/"));
|
|
8954
|
+
const content = fs29.readFileSync(source);
|
|
8955
|
+
const sha2563 = createHash("sha256").update(content).digest("hex");
|
|
8956
|
+
const existing = published.get(assetPath);
|
|
8957
|
+
if (existing && existing.sha256 !== sha2563) {
|
|
8958
|
+
throw new Error(`server runtime asset collision: ${assetPath}`);
|
|
8959
|
+
}
|
|
8960
|
+
if (!existing) {
|
|
8961
|
+
fs29.mkdirSync(path26.dirname(target), { recursive: true });
|
|
8962
|
+
fs29.writeFileSync(target, content);
|
|
8963
|
+
published.set(assetPath, {
|
|
8964
|
+
path: assetPath,
|
|
8965
|
+
sha256: sha2563,
|
|
8966
|
+
size: content.length
|
|
8967
|
+
});
|
|
8968
|
+
}
|
|
8969
|
+
};
|
|
8970
|
+
const publishCandidate = (source, destination) => {
|
|
8971
|
+
assertNoSymlinkPath(source);
|
|
8972
|
+
const stat = fs29.lstatSync(source);
|
|
8973
|
+
if (stat.isSymbolicLink()) {
|
|
8974
|
+
throw new Error(`server runtime asset symlink is unsupported: ${source}`);
|
|
8975
|
+
}
|
|
8976
|
+
if (stat.isFile()) {
|
|
8977
|
+
publishFile(source, destination);
|
|
8978
|
+
return;
|
|
8979
|
+
}
|
|
8980
|
+
if (!stat.isDirectory()) {
|
|
8981
|
+
throw new Error(`server runtime asset type is unsupported: ${source}`);
|
|
8982
|
+
}
|
|
8983
|
+
for (const entry of fs29.readdirSync(source, { withFileTypes: true })) {
|
|
8984
|
+
publishCandidate(
|
|
8985
|
+
path26.join(source, entry.name),
|
|
8986
|
+
path26.posix.join(destination, entry.name)
|
|
8987
|
+
);
|
|
8988
|
+
}
|
|
8989
|
+
};
|
|
8990
|
+
for (const candidate of candidates.sort(
|
|
8991
|
+
(left, right) => left.destination.localeCompare(right.destination)
|
|
8992
|
+
)) {
|
|
8993
|
+
publishCandidate(candidate.source, candidate.destination);
|
|
8994
|
+
}
|
|
8995
|
+
return {
|
|
8996
|
+
assets: Array.from(published.values()).sort(
|
|
8997
|
+
(left, right) => left.path.localeCompare(right.path)
|
|
8998
|
+
),
|
|
8999
|
+
warnings: warnings.filter(
|
|
9000
|
+
(warning, index, all) => all.findIndex(
|
|
9001
|
+
(item) => item.kind === warning.kind && item.source === warning.source && item.expressionHash === warning.expressionHash
|
|
9002
|
+
) === index
|
|
9003
|
+
).sort(
|
|
9004
|
+
(left, right) => `${left.source}:${left.expressionHash}`.localeCompare(
|
|
9005
|
+
`${right.source}:${right.expressionHash}`
|
|
9006
|
+
)
|
|
9007
|
+
)
|
|
9008
|
+
};
|
|
9009
|
+
}
|
|
9010
|
+
function resolveStaticActionPlugins(projectRoot, configuredPlugins) {
|
|
9011
|
+
const projectRequire = createRequire3(path26.join(projectRoot, "package.json"));
|
|
9012
|
+
const plugins = [];
|
|
9013
|
+
const reasons = [];
|
|
9014
|
+
for (const [name, configuredVersion] of Object.entries(
|
|
9015
|
+
configuredPlugins
|
|
9016
|
+
).sort(([left], [right]) => left.localeCompare(right))) {
|
|
9017
|
+
if (typeof configuredVersion !== "string" || configuredVersion === "") {
|
|
9018
|
+
reasons.push(`Action Plugin ${name} has an invalid configured version`);
|
|
9019
|
+
continue;
|
|
9020
|
+
}
|
|
9021
|
+
try {
|
|
9022
|
+
const entry = projectRequire.resolve(name);
|
|
9023
|
+
const packageRoot2 = findPackageRoot(entry);
|
|
9024
|
+
if (!packageRoot2) {
|
|
9025
|
+
reasons.push(`Action Plugin package root not found: ${name}`);
|
|
9026
|
+
continue;
|
|
9027
|
+
}
|
|
9028
|
+
const packageJson = JSON.parse(
|
|
9029
|
+
fs29.readFileSync(path26.join(packageRoot2, "package.json"), "utf8")
|
|
9030
|
+
);
|
|
9031
|
+
if (packageJson.name !== name) {
|
|
9032
|
+
reasons.push(
|
|
9033
|
+
`Action Plugin package name mismatch: configured=${name} installed=${packageJson.name ?? "<missing>"}`
|
|
9034
|
+
);
|
|
9035
|
+
continue;
|
|
9036
|
+
}
|
|
9037
|
+
if (packageJson.version !== configuredVersion) {
|
|
9038
|
+
reasons.push(
|
|
9039
|
+
`Action Plugin version mismatch: ${name} configured=${configuredVersion} installed=${packageJson.version ?? "<missing>"}`
|
|
9040
|
+
);
|
|
9041
|
+
continue;
|
|
9042
|
+
}
|
|
9043
|
+
const manifestPath = path26.join(packageRoot2, "manifest.json");
|
|
9044
|
+
if (!fs29.existsSync(manifestPath)) {
|
|
9045
|
+
reasons.push(`Action Plugin manifest is missing: ${name}`);
|
|
9046
|
+
continue;
|
|
9047
|
+
}
|
|
9048
|
+
const manifest = JSON.parse(fs29.readFileSync(manifestPath, "utf8"));
|
|
9049
|
+
if (manifest.name !== void 0 && manifest.name !== name) {
|
|
9050
|
+
reasons.push(
|
|
9051
|
+
`Action Plugin manifest name mismatch: configured=${name} manifest=${String(manifest.name)}`
|
|
9052
|
+
);
|
|
9053
|
+
continue;
|
|
9054
|
+
}
|
|
9055
|
+
if (manifest.version !== void 0 && manifest.version !== configuredVersion) {
|
|
9056
|
+
reasons.push(
|
|
9057
|
+
`Action Plugin manifest version mismatch: ${name} configured=${configuredVersion} manifest=${String(manifest.version)}`
|
|
9058
|
+
);
|
|
9059
|
+
continue;
|
|
9060
|
+
}
|
|
9061
|
+
plugins.push({ name, version: configuredVersion, entry, manifest });
|
|
9062
|
+
} catch (error) {
|
|
9063
|
+
reasons.push(
|
|
9064
|
+
`Action Plugin cannot be statically resolved: ${name}: ${error instanceof Error ? error.message : String(error)}`
|
|
9065
|
+
);
|
|
9066
|
+
}
|
|
9067
|
+
}
|
|
9068
|
+
return { plugins, reasons };
|
|
9069
|
+
}
|
|
9070
|
+
function staticActionPluginRegistry(projectRoot, plugins, actionPluginProbe) {
|
|
9071
|
+
if (plugins.length === 0) {
|
|
9072
|
+
return { name: "miaoda-static-action-plugin-registry", setup() {
|
|
9073
|
+
} };
|
|
9074
|
+
}
|
|
9075
|
+
const capabilityEntry = resolveProjectPackage(
|
|
9076
|
+
projectRoot,
|
|
9077
|
+
"@lark-apaas/nestjs-capability"
|
|
9078
|
+
);
|
|
9079
|
+
const registryEntries = plugins.map(
|
|
9080
|
+
(plugin, index) => `[${JSON.stringify(plugin.name)}, { version: ${JSON.stringify(plugin.version)}, manifest: ${JSON.stringify(plugin.manifest)}, pluginPackage: __miaodaActionPlugin${index} }]`
|
|
9081
|
+
).join(",\n");
|
|
9082
|
+
const staticImports = plugins.map(
|
|
9083
|
+
(plugin, index) => `const __miaodaActionPlugin${index} = require(${JSON.stringify(plugin.entry)});`
|
|
9084
|
+
).join("\n");
|
|
9085
|
+
const contents = `
|
|
9086
|
+
const __miaodaCapability = require(${JSON.stringify(capabilityEntry)});
|
|
9087
|
+
${staticImports}
|
|
9088
|
+
const __miaodaActionPluginRegistry = new Map([${registryEntries}]);
|
|
9089
|
+
const __miaodaActionPluginProbe = ${JSON.stringify(actionPluginProbe ?? null)};
|
|
9090
|
+
if (process.env.MIAODA_SERVER_CACHE_PROBE === 'true') {
|
|
9091
|
+
for (const [__miaodaPluginKey, __miaodaRegistration] of __miaodaActionPluginRegistry) {
|
|
9092
|
+
const __miaodaPluginPackage = __miaodaRegistration.pluginPackage.default ?? __miaodaRegistration.pluginPackage;
|
|
9093
|
+
if (typeof __miaodaPluginPackage.create !== 'function') {
|
|
9094
|
+
throw new Error('MIAODA_ACTION_PLUGIN_PROBE_CREATE_MISSING:' + __miaodaPluginKey);
|
|
9095
|
+
}
|
|
9096
|
+
}
|
|
9097
|
+
console.error('MIAODA_ACTION_PLUGIN_REGISTRY_OK:' + __miaodaActionPluginRegistry.size);
|
|
9098
|
+
}
|
|
9099
|
+
if (process.env.MIAODA_SERVER_CACHE_PROBE === 'true' && __miaodaActionPluginProbe) {
|
|
9100
|
+
const __miaodaProbeRegistration = __miaodaActionPluginRegistry.get(__miaodaActionPluginProbe.key);
|
|
9101
|
+
if (!__miaodaProbeRegistration) {
|
|
9102
|
+
throw new Error('MIAODA_ACTION_PLUGIN_PROBE_NOT_REGISTERED:' + __miaodaActionPluginProbe.key);
|
|
9103
|
+
}
|
|
9104
|
+
const __miaodaProbePackage = __miaodaProbeRegistration.pluginPackage.default ?? __miaodaProbeRegistration.pluginPackage;
|
|
9105
|
+
if (typeof __miaodaProbePackage.create !== 'function') {
|
|
9106
|
+
throw new Error('MIAODA_ACTION_PLUGIN_PROBE_CREATE_MISSING:' + __miaodaActionPluginProbe.key);
|
|
9107
|
+
}
|
|
9108
|
+
Promise.resolve(__miaodaProbePackage.create(__miaodaActionPluginProbe.config))
|
|
9109
|
+
.then(() => console.error('MIAODA_ACTION_PLUGIN_PROBE_OK:' + __miaodaActionPluginProbe.key))
|
|
9110
|
+
.catch(error => {
|
|
9111
|
+
console.error('MIAODA_ACTION_PLUGIN_PROBE_FAILED:' + __miaodaActionPluginProbe.key + ':' + (error?.message ?? String(error)));
|
|
9112
|
+
process.exitCode = 1;
|
|
9113
|
+
});
|
|
9114
|
+
}
|
|
9115
|
+
const __miaodaPluginLoader = __miaodaCapability.PluginLoaderService;
|
|
9116
|
+
if (typeof __miaodaPluginLoader !== 'function') {
|
|
9117
|
+
throw new Error('MIAODA_STATIC_ACTION_PLUGIN_REGISTRY_UNSUPPORTED');
|
|
9118
|
+
}
|
|
9119
|
+
const __miaodaPluginLoaderPrototype = __miaodaPluginLoader.prototype;
|
|
9120
|
+
__miaodaPluginLoaderPrototype.getManifest = function getStaticManifest(pluginKey) {
|
|
9121
|
+
return __miaodaActionPluginRegistry.get(pluginKey)?.manifest ?? null;
|
|
9122
|
+
};
|
|
9123
|
+
__miaodaPluginLoaderPrototype.createPluginInstance = async function createStaticPluginInstance(pluginKey, config) {
|
|
9124
|
+
const registered = __miaodaActionPluginRegistry.get(pluginKey);
|
|
9125
|
+
if (!registered) throw new __miaodaCapability.PluginNotFoundError(pluginKey);
|
|
9126
|
+
const pluginPackage = registered.pluginPackage.default ?? registered.pluginPackage;
|
|
9127
|
+
if (typeof pluginPackage.create !== 'function') {
|
|
9128
|
+
throw new __miaodaCapability.PluginLoadError(pluginKey, 'Plugin does not export create() function');
|
|
9129
|
+
}
|
|
9130
|
+
return pluginPackage.create(config);
|
|
9131
|
+
};
|
|
9132
|
+
__miaodaPluginLoaderPrototype.isPluginInstalled = function isStaticPluginInstalled(pluginKey) {
|
|
9133
|
+
return __miaodaActionPluginRegistry.has(pluginKey);
|
|
9134
|
+
};
|
|
9135
|
+
__miaodaPluginLoaderPrototype.clearCache = function clearStaticPluginCache(pluginKey) {
|
|
9136
|
+
if (pluginKey) {
|
|
9137
|
+
this.pluginInstances?.delete(pluginKey);
|
|
9138
|
+
this.manifestCache?.delete(pluginKey);
|
|
9139
|
+
return;
|
|
9140
|
+
}
|
|
9141
|
+
this.pluginInstances?.clear();
|
|
9142
|
+
this.manifestCache?.clear();
|
|
9143
|
+
};
|
|
9144
|
+
module.exports = __miaodaCapability;
|
|
9145
|
+
`;
|
|
9146
|
+
return {
|
|
9147
|
+
name: "miaoda-static-action-plugin-registry",
|
|
9148
|
+
setup(esbuild) {
|
|
9149
|
+
esbuild.onResolve({ filter: /^@lark-apaas\/nestjs-capability$/ }, () => ({
|
|
9150
|
+
path: "@lark-apaas/nestjs-capability",
|
|
9151
|
+
namespace: "miaoda-static-action-plugin-registry"
|
|
9152
|
+
}));
|
|
9153
|
+
esbuild.onLoad(
|
|
9154
|
+
{
|
|
9155
|
+
filter: /.*/,
|
|
9156
|
+
namespace: "miaoda-static-action-plugin-registry"
|
|
9157
|
+
},
|
|
9158
|
+
() => ({ contents, loader: "js", resolveDir: projectRoot })
|
|
9159
|
+
);
|
|
9160
|
+
}
|
|
9161
|
+
};
|
|
9162
|
+
}
|
|
9163
|
+
function collectExternalImports(metafile, outfile, projectRoot) {
|
|
9164
|
+
const realOutfile = fs29.existsSync(outfile) ? fs29.realpathSync(outfile) : path26.resolve(outfile);
|
|
9165
|
+
const output = Object.entries(metafile.outputs).find(([candidate]) => {
|
|
9166
|
+
const resolvedCandidate = path26.resolve(projectRoot, candidate);
|
|
9167
|
+
return resolvedCandidate === path26.resolve(outfile) || fs29.existsSync(resolvedCandidate) && fs29.realpathSync(resolvedCandidate) === realOutfile;
|
|
9168
|
+
})?.[1];
|
|
9169
|
+
if (!output) return [];
|
|
9170
|
+
const externalImports = new Set(
|
|
9171
|
+
output.imports.filter((item) => item.external).map((item) => item.path).filter((item) => !BUILTINS.has(item) && !item.startsWith("node:"))
|
|
9172
|
+
);
|
|
9173
|
+
if (fs29.existsSync(outfile)) {
|
|
9174
|
+
const ast = parseJavaScriptSource(fs29.readFileSync(outfile, "utf8"));
|
|
9175
|
+
walkSimple(ast, {
|
|
9176
|
+
CallExpression(node) {
|
|
9177
|
+
if (staticPropertyName(node.callee) !== "resolve" || node.callee?.type !== "MemberExpression" || node.callee.object?.type !== "Identifier" || !["require", "__require"].includes(node.callee.object.name)) {
|
|
9178
|
+
return;
|
|
9179
|
+
}
|
|
9180
|
+
const specifier = staticStringValue(node.arguments?.[0]);
|
|
9181
|
+
if (!specifier || specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("#") || BUILTINS.has(specifier) || specifier.startsWith("node:")) {
|
|
9182
|
+
return;
|
|
9183
|
+
}
|
|
9184
|
+
externalImports.add(specifier);
|
|
9185
|
+
}
|
|
9186
|
+
});
|
|
9187
|
+
}
|
|
9188
|
+
return Array.from(externalImports).sort();
|
|
9189
|
+
}
|
|
9190
|
+
function collectBuildOnlyInputs(projectRoot, metafile) {
|
|
9191
|
+
return Array.from(
|
|
9192
|
+
new Set(
|
|
9193
|
+
Object.keys(metafile.inputs).flatMap((input) => {
|
|
9194
|
+
const source = canonicalSourcePath(
|
|
9195
|
+
projectRoot,
|
|
9196
|
+
path26.resolve(projectRoot, input)
|
|
9197
|
+
);
|
|
9198
|
+
const normalized = `/${source.replace(/^\.\//, "")}/`;
|
|
9199
|
+
return BUILD_ONLY_SERVER_CACHE_PACKAGES.filter(
|
|
9200
|
+
(packageName) => normalized.includes(`/node_modules/${packageName}/`)
|
|
9201
|
+
);
|
|
9202
|
+
})
|
|
9203
|
+
)
|
|
9204
|
+
).sort();
|
|
9205
|
+
}
|
|
9206
|
+
function isStaticString(node) {
|
|
9207
|
+
if (!node) return false;
|
|
9208
|
+
if (node.type === "Literal") return typeof node.value === "string";
|
|
9209
|
+
return node.type === "TemplateLiteral" && node.expressions.length === 0;
|
|
9210
|
+
}
|
|
9211
|
+
function staticPropertyName(node) {
|
|
9212
|
+
if (node?.type !== "MemberExpression") return void 0;
|
|
9213
|
+
if (!node.computed && node.property.type === "Identifier") {
|
|
9214
|
+
return node.property.name;
|
|
9215
|
+
}
|
|
9216
|
+
if (node.computed && node.property.type === "Literal" && typeof node.property.value === "string") {
|
|
9217
|
+
return node.property.value;
|
|
9218
|
+
}
|
|
9219
|
+
return void 0;
|
|
9220
|
+
}
|
|
9221
|
+
function collectDynamicImportWarnings(projectRoot, metafile) {
|
|
9222
|
+
const warnings = [];
|
|
9223
|
+
const sourceInputs = Object.keys(metafile.inputs).filter((input) => /\.(?:cjs|mjs|js)$/.test(input)).sort();
|
|
9224
|
+
for (const input of sourceInputs) {
|
|
9225
|
+
const sourcePath = path26.resolve(projectRoot, input);
|
|
9226
|
+
if (!fs29.existsSync(sourcePath) || !fs29.statSync(sourcePath).isFile()) {
|
|
9227
|
+
continue;
|
|
9228
|
+
}
|
|
9229
|
+
const source = fs29.readFileSync(sourcePath, "utf8");
|
|
9230
|
+
const ast = parseJavaScriptSource(source);
|
|
9231
|
+
const origin = canonicalSourcePath(projectRoot, sourcePath);
|
|
9232
|
+
const fingerprint = (kind, node, message) => {
|
|
9233
|
+
const expression = source.slice(node.start, node.end);
|
|
9234
|
+
const hash = createHash("sha256").update(expression).digest("hex").slice(0, 16);
|
|
9235
|
+
warnings.push({ kind, source: origin, expressionHash: hash, message });
|
|
9236
|
+
};
|
|
9237
|
+
walkSimple(ast, {
|
|
9238
|
+
CallExpression(node) {
|
|
9239
|
+
if (node.callee.type === "Identifier" && node.callee.name === "require" && !isStaticString(node.arguments[0])) {
|
|
9240
|
+
fingerprint(
|
|
9241
|
+
"dynamic-require",
|
|
9242
|
+
node,
|
|
9243
|
+
"Variable module loading remains in bundle"
|
|
9244
|
+
);
|
|
9245
|
+
}
|
|
9246
|
+
const property = staticPropertyName(node.callee);
|
|
9247
|
+
const resolverObject = node.callee.type === "MemberExpression" ? node.callee.object : void 0;
|
|
9248
|
+
if (node.callee.type === "Identifier" && node.callee.name === "createRequire") {
|
|
9249
|
+
fingerprint(
|
|
9250
|
+
"create-require",
|
|
9251
|
+
node,
|
|
9252
|
+
"Runtime module resolver is created in bundle"
|
|
9253
|
+
);
|
|
9254
|
+
} else if (property === "resolve" && resolverObject?.type === "Identifier" && resolverObject.name === "require" && !isStaticString(node.arguments[0])) {
|
|
9255
|
+
fingerprint(
|
|
9256
|
+
"dynamic-require-resolve",
|
|
9257
|
+
node,
|
|
9258
|
+
"Variable require.resolve target remains in bundle"
|
|
9259
|
+
);
|
|
9260
|
+
} else if (property === "resolve" && resolverObject?.type === "Identifier" && ["import", "module"].includes(resolverObject.name) && !isStaticString(node.arguments[0])) {
|
|
9261
|
+
fingerprint(
|
|
9262
|
+
"runtime-module-resolution",
|
|
9263
|
+
node,
|
|
9264
|
+
"Variable runtime module resolution remains in bundle"
|
|
9265
|
+
);
|
|
9266
|
+
}
|
|
9267
|
+
},
|
|
9268
|
+
ImportExpression(node) {
|
|
9269
|
+
if (!isStaticString(node.source)) {
|
|
9270
|
+
fingerprint(
|
|
9271
|
+
"dynamic-import",
|
|
9272
|
+
node,
|
|
9273
|
+
"Variable dynamic import remains in bundle"
|
|
9274
|
+
);
|
|
9275
|
+
}
|
|
9276
|
+
}
|
|
9277
|
+
});
|
|
9278
|
+
}
|
|
9279
|
+
return warnings.filter(
|
|
9280
|
+
(warning, index, all) => all.findIndex(
|
|
9281
|
+
(item) => item.kind === warning.kind && item.source === warning.source && item.expressionHash === warning.expressionHash
|
|
9282
|
+
) === index
|
|
9283
|
+
).sort(
|
|
9284
|
+
(left, right) => `${left.kind}:${left.source}:${left.expressionHash}`.localeCompare(
|
|
9285
|
+
`${right.kind}:${right.source}:${right.expressionHash}`
|
|
9286
|
+
)
|
|
9287
|
+
);
|
|
9288
|
+
}
|
|
9289
|
+
async function reservePort() {
|
|
9290
|
+
return new Promise((resolve2, reject) => {
|
|
9291
|
+
const server = net.createServer();
|
|
9292
|
+
server.once("error", reject);
|
|
9293
|
+
server.listen(0, "127.0.0.1", () => {
|
|
9294
|
+
const address = server.address();
|
|
9295
|
+
if (!address || typeof address === "string") {
|
|
9296
|
+
server.close(() => reject(new Error("unable to reserve probe port")));
|
|
9297
|
+
return;
|
|
9298
|
+
}
|
|
9299
|
+
server.close((error) => error ? reject(error) : resolve2(address.port));
|
|
9300
|
+
});
|
|
9301
|
+
});
|
|
9302
|
+
}
|
|
9303
|
+
function resolveLegacyCapabilityProbe(projectRoot) {
|
|
9304
|
+
const capabilitiesRoot = path26.join(projectRoot, "server", "capabilities");
|
|
9305
|
+
if (!fs29.existsSync(capabilitiesRoot)) {
|
|
9306
|
+
return { files: [], expectedIds: [] };
|
|
9307
|
+
}
|
|
9308
|
+
const rootStat = fs29.lstatSync(capabilitiesRoot);
|
|
9309
|
+
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
9310
|
+
throw new Error(
|
|
9311
|
+
"legacy capability probe directory must be a regular directory"
|
|
9312
|
+
);
|
|
9313
|
+
}
|
|
9314
|
+
const realProjectRoot = fs29.realpathSync(projectRoot);
|
|
9315
|
+
const realCapabilitiesRoot = fs29.realpathSync(capabilitiesRoot);
|
|
9316
|
+
if (!isPathInside(realProjectRoot, realCapabilitiesRoot)) {
|
|
9317
|
+
throw new Error("legacy capability probe directory escaped project root");
|
|
9318
|
+
}
|
|
9319
|
+
const files = [];
|
|
9320
|
+
const expectedIds = [];
|
|
9321
|
+
for (const name of fs29.readdirSync(realCapabilitiesRoot).sort()) {
|
|
9322
|
+
if (!name.endsWith(".json")) continue;
|
|
9323
|
+
const source = path26.join(realCapabilitiesRoot, name);
|
|
9324
|
+
const stat = fs29.lstatSync(source);
|
|
9325
|
+
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
9326
|
+
throw new Error(`legacy capability probe file is unsafe: ${name}`);
|
|
9327
|
+
}
|
|
9328
|
+
const parsed = JSON.parse(fs29.readFileSync(source, "utf8"));
|
|
9329
|
+
if (typeof parsed.id !== "string" || parsed.id.length === 0) {
|
|
9330
|
+
throw new Error(`legacy capability probe file has no id: ${name}`);
|
|
9331
|
+
}
|
|
9332
|
+
files.push({ source, name });
|
|
9333
|
+
expectedIds.push(parsed.id);
|
|
9334
|
+
}
|
|
9335
|
+
return { files, expectedIds };
|
|
9336
|
+
}
|
|
9337
|
+
function resolveAvailabilityProbeConfig(projectRoot, configured) {
|
|
9338
|
+
if (configured === void 0) {
|
|
9339
|
+
const configuredBasePath = process.env.CLIENT_BASE_PATH;
|
|
9340
|
+
const basePath = typeof configuredBasePath === "string" && configuredBasePath.startsWith("/") && !configuredBasePath.startsWith("//") ? configuredBasePath : "/";
|
|
9341
|
+
const normalizedBasePath = basePath === "/" ? "" : basePath.replace(/\/+$/, "");
|
|
9342
|
+
const capabilityPath = `${normalizedBasePath}/__innerapi__/capability/list`;
|
|
9343
|
+
return {
|
|
9344
|
+
readiness: { path: capabilityPath, expectedStatus: 200 },
|
|
9345
|
+
business: {
|
|
9346
|
+
path: capabilityPath,
|
|
9347
|
+
expectedStatus: 200,
|
|
9348
|
+
bodyIncludes: '"status_code":"0"'
|
|
9349
|
+
},
|
|
9350
|
+
legacyCapabilityProbe: resolveLegacyCapabilityProbe(projectRoot)
|
|
9351
|
+
};
|
|
9352
|
+
}
|
|
9353
|
+
if (!configured?.readiness || !configured.business) {
|
|
9354
|
+
throw new Error(
|
|
9355
|
+
"miaodaCache.availabilityProbe.readiness and business are required"
|
|
9356
|
+
);
|
|
9357
|
+
}
|
|
9358
|
+
const normalize = (name, value) => {
|
|
9359
|
+
const requestPath = value?.path;
|
|
9360
|
+
const expectedStatus = value?.expectedStatus;
|
|
9361
|
+
if (typeof requestPath !== "string" || !requestPath.startsWith("/") || requestPath.startsWith("//") || !Number.isSafeInteger(expectedStatus) || expectedStatus < 100 || expectedStatus > 599 || value?.bodyIncludes !== void 0 && typeof value.bodyIncludes !== "string") {
|
|
9362
|
+
throw new Error(`invalid ${name} availability probe configuration`);
|
|
9363
|
+
}
|
|
9364
|
+
return {
|
|
9365
|
+
path: requestPath,
|
|
9366
|
+
expectedStatus,
|
|
9367
|
+
...value?.bodyIncludes ? { bodyIncludes: value.bodyIncludes } : {}
|
|
9368
|
+
};
|
|
9369
|
+
};
|
|
9370
|
+
return {
|
|
9371
|
+
readiness: normalize("readiness", configured.readiness),
|
|
9372
|
+
business: normalize("business", configured.business)
|
|
9373
|
+
};
|
|
9374
|
+
}
|
|
9375
|
+
function requestHttp(port, request) {
|
|
9376
|
+
return new Promise((resolve2, reject) => {
|
|
9377
|
+
const clientRequest = http.request(
|
|
9378
|
+
{
|
|
9379
|
+
host: "127.0.0.1",
|
|
9380
|
+
port,
|
|
9381
|
+
path: request.path,
|
|
9382
|
+
method: "GET",
|
|
9383
|
+
timeout: 1e3,
|
|
9384
|
+
headers: { connection: "close" }
|
|
9385
|
+
},
|
|
9386
|
+
(response) => {
|
|
9387
|
+
let body = "";
|
|
9388
|
+
response.setEncoding("utf8");
|
|
9389
|
+
response.on("data", (chunk) => {
|
|
9390
|
+
body = `${body}${String(chunk)}`.slice(0, 64 * 1024);
|
|
9391
|
+
});
|
|
9392
|
+
response.once(
|
|
9393
|
+
"end",
|
|
9394
|
+
() => resolve2({ status: response.statusCode ?? 0, body })
|
|
9395
|
+
);
|
|
9396
|
+
}
|
|
9397
|
+
);
|
|
9398
|
+
clientRequest.once("timeout", () => {
|
|
9399
|
+
clientRequest.destroy(new Error("HTTP probe timed out"));
|
|
9400
|
+
});
|
|
9401
|
+
clientRequest.once("error", reject);
|
|
9402
|
+
clientRequest.end();
|
|
9403
|
+
});
|
|
9404
|
+
}
|
|
9405
|
+
function requestMatches(response, request) {
|
|
9406
|
+
return response.status === request.expectedStatus && (request.bodyIncludes === void 0 || response.body.includes(request.bodyIncludes));
|
|
9407
|
+
}
|
|
9408
|
+
async function terminateProcessGroup(child) {
|
|
9409
|
+
if (child.exitCode !== null || child.signalCode !== null) return;
|
|
9410
|
+
const exited = new Promise(
|
|
9411
|
+
(resolve2) => child.once("exit", () => resolve2())
|
|
9412
|
+
);
|
|
9413
|
+
try {
|
|
9414
|
+
child.kill("SIGTERM");
|
|
9415
|
+
} catch {
|
|
9416
|
+
}
|
|
9417
|
+
await Promise.race([
|
|
9418
|
+
exited,
|
|
9419
|
+
new Promise((resolve2) => setTimeout(resolve2, 500))
|
|
9420
|
+
]);
|
|
9421
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
9422
|
+
try {
|
|
9423
|
+
process.kill(-child.pid, "SIGKILL");
|
|
9424
|
+
} catch {
|
|
9425
|
+
child.kill("SIGKILL");
|
|
9426
|
+
}
|
|
9427
|
+
await exited;
|
|
9428
|
+
}
|
|
9429
|
+
}
|
|
9430
|
+
async function runAvailabilityProbe(bundleFile, runtimeAssets, timeoutMs, config, actionPluginCount, actionPluginProbeKey) {
|
|
9431
|
+
const probeRoot = fs29.mkdtempSync(
|
|
9432
|
+
path26.join(os4.tmpdir(), "server-cache-probe-")
|
|
9433
|
+
);
|
|
9434
|
+
const isolatedBundle = path26.join(probeRoot, "server.bundle.cjs");
|
|
9435
|
+
fs29.copyFileSync(bundleFile, isolatedBundle);
|
|
9436
|
+
for (const asset of runtimeAssets) {
|
|
9437
|
+
const source = path26.join(
|
|
9438
|
+
path26.dirname(bundleFile),
|
|
9439
|
+
...asset.path.split("/")
|
|
9440
|
+
);
|
|
9441
|
+
const destination = path26.join(probeRoot, ...asset.path.split("/"));
|
|
9442
|
+
fs29.mkdirSync(path26.dirname(destination), { recursive: true });
|
|
9443
|
+
fs29.copyFileSync(source, destination);
|
|
9444
|
+
}
|
|
9445
|
+
if (config.legacyCapabilityProbe) {
|
|
9446
|
+
const capabilityRoot = path26.join(probeRoot, "server", "capabilities");
|
|
9447
|
+
fs29.mkdirSync(capabilityRoot, { recursive: true });
|
|
9448
|
+
for (const file of config.legacyCapabilityProbe.files) {
|
|
9449
|
+
fs29.copyFileSync(file.source, path26.join(capabilityRoot, file.name));
|
|
9450
|
+
}
|
|
9451
|
+
}
|
|
9452
|
+
const port = await reservePort();
|
|
9453
|
+
let stdout = "";
|
|
9454
|
+
let stderr = "";
|
|
9455
|
+
let responseText = "";
|
|
9456
|
+
const checks = [];
|
|
9457
|
+
const startedAt = Date.now();
|
|
9458
|
+
const child = spawn2(process.execPath, [isolatedBundle], {
|
|
9459
|
+
cwd: probeRoot,
|
|
9460
|
+
detached: true,
|
|
9461
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
9462
|
+
env: {
|
|
9463
|
+
...process.env,
|
|
9464
|
+
NODE_PATH: "",
|
|
9465
|
+
// The cache bundle serves the development preview. Probe the same module
|
|
9466
|
+
// graph instead of forcing production mode, which disables Miaoda's
|
|
9467
|
+
// internal capability route and produces a false HTTP 500.
|
|
9468
|
+
NODE_ENV: "development",
|
|
9469
|
+
SERVER_HOST: "127.0.0.1",
|
|
9470
|
+
SERVER_PORT: String(port),
|
|
9471
|
+
MIAODA_SERVER_CACHE_PROBE: "true",
|
|
9472
|
+
DEPRECATED_SKIP_INIT_DB_CONNECTION: process.env.DEPRECATED_SKIP_INIT_DB_CONNECTION ?? "true",
|
|
9473
|
+
FORCE_AUTHN_INNERAPI_DOMAIN: process.env.FORCE_AUTHN_INNERAPI_DOMAIN ?? "http://127.0.0.1",
|
|
9474
|
+
FORCE_AUTHN_ACCESS_KEY: process.env.FORCE_AUTHN_ACCESS_KEY ?? "server-cache-probe",
|
|
9475
|
+
FORCE_AUTHN_ACCESS_SECRET: process.env.FORCE_AUTHN_ACCESS_SECRET ?? "server-cache-probe"
|
|
9476
|
+
}
|
|
9477
|
+
});
|
|
9478
|
+
child.stdout?.setEncoding("utf8");
|
|
9479
|
+
child.stdout?.on("data", (chunk) => {
|
|
9480
|
+
stdout = `${stdout}${String(chunk)}`.slice(-8 * 1024);
|
|
9481
|
+
});
|
|
9482
|
+
child.stderr?.setEncoding("utf8");
|
|
9483
|
+
child.stderr?.on("data", (chunk) => {
|
|
9484
|
+
stderr = `${stderr}${String(chunk)}`.slice(-8 * 1024);
|
|
9485
|
+
});
|
|
9486
|
+
try {
|
|
9487
|
+
const nodeModulesPresent = fs29.existsSync(
|
|
9488
|
+
path26.join(probeRoot, "node_modules")
|
|
9489
|
+
);
|
|
9490
|
+
checks.push({
|
|
9491
|
+
name: "isolated-node-modules",
|
|
9492
|
+
success: !nodeModulesPresent,
|
|
9493
|
+
message: nodeModulesPresent ? "node_modules unexpectedly exists in isolated probe directory" : "node_modules is absent"
|
|
9494
|
+
});
|
|
9495
|
+
const runtimeAssetsReadable = runtimeAssets.every((asset) => {
|
|
9496
|
+
const file = path26.join(probeRoot, ...asset.path.split("/"));
|
|
9497
|
+
return fs29.existsSync(file) && fs29.statSync(file).isFile() && fs29.statSync(file).size === asset.size && createHash("sha256").update(fs29.readFileSync(file)).digest("hex") === asset.sha256;
|
|
9498
|
+
});
|
|
9499
|
+
checks.push({
|
|
9500
|
+
name: "runtime-assets",
|
|
9501
|
+
success: runtimeAssetsReadable,
|
|
9502
|
+
message: runtimeAssetsReadable ? `${runtimeAssets.length} runtime assets are readable` : "runtime asset integrity check failed in isolated directory"
|
|
9503
|
+
});
|
|
9504
|
+
let readinessResponse;
|
|
9505
|
+
let lastReadinessError = "";
|
|
9506
|
+
while (Date.now() - startedAt < timeoutMs && child.exitCode === null && child.signalCode === null) {
|
|
9507
|
+
try {
|
|
9508
|
+
const response = await requestHttp(port, config.readiness);
|
|
9509
|
+
responseText = `${responseText}
|
|
9510
|
+
${response.body}`.slice(-64 * 1024);
|
|
9511
|
+
readinessResponse = response;
|
|
9512
|
+
if (requestMatches(response, config.readiness)) break;
|
|
9513
|
+
lastReadinessError = `unexpected HTTP ${response.status}`;
|
|
9514
|
+
} catch (error) {
|
|
9515
|
+
lastReadinessError = error instanceof Error ? error.message : String(error);
|
|
9516
|
+
}
|
|
9517
|
+
await new Promise((resolve2) => setTimeout(resolve2, 25));
|
|
9518
|
+
}
|
|
9519
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
9520
|
+
await new Promise((resolve2) => setTimeout(resolve2, 50));
|
|
9521
|
+
}
|
|
9522
|
+
const readinessSuccess = Boolean(
|
|
9523
|
+
readinessResponse && requestMatches(readinessResponse, config.readiness)
|
|
9524
|
+
);
|
|
9525
|
+
const startupMs = Date.now() - startedAt;
|
|
9526
|
+
checks.push({
|
|
9527
|
+
name: "http-readiness",
|
|
9528
|
+
success: readinessSuccess,
|
|
9529
|
+
path: config.readiness.path,
|
|
9530
|
+
status: readinessResponse?.status,
|
|
9531
|
+
elapsedMs: startupMs,
|
|
9532
|
+
...!readinessSuccess ? {
|
|
9533
|
+
message: child.exitCode !== null ? `process exited before readiness: ${child.exitCode}` : lastReadinessError || "HTTP readiness timed out"
|
|
9534
|
+
} : {}
|
|
9535
|
+
});
|
|
9536
|
+
let businessResponse;
|
|
9537
|
+
let businessError = "";
|
|
9538
|
+
if (readinessSuccess) {
|
|
9539
|
+
try {
|
|
9540
|
+
businessResponse = await requestHttp(port, config.business);
|
|
9541
|
+
responseText = `${responseText}
|
|
9542
|
+
${businessResponse.body}`.slice(
|
|
9543
|
+
-64 * 1024
|
|
9544
|
+
);
|
|
9545
|
+
} catch (error) {
|
|
9546
|
+
businessError = error instanceof Error ? error.message : String(error);
|
|
9547
|
+
}
|
|
9548
|
+
}
|
|
9549
|
+
const businessSuccess = Boolean(
|
|
9550
|
+
businessResponse && requestMatches(businessResponse, config.business)
|
|
9551
|
+
);
|
|
9552
|
+
checks.push({
|
|
9553
|
+
name: "business-api",
|
|
9554
|
+
success: businessSuccess,
|
|
9555
|
+
path: config.business.path,
|
|
9556
|
+
status: businessResponse?.status,
|
|
9557
|
+
...!businessSuccess ? {
|
|
9558
|
+
message: businessError || (businessResponse ? `expected HTTP ${config.business.expectedStatus}${config.business.bodyIncludes ? ` containing ${JSON.stringify(config.business.bodyIncludes)}` : ""}, received HTTP ${businessResponse.status}` : "business API was not requested because readiness failed")
|
|
9559
|
+
} : {}
|
|
9560
|
+
});
|
|
9561
|
+
if (config.legacyCapabilityProbe) {
|
|
9562
|
+
let actualIds = [];
|
|
9563
|
+
let capabilityError = "";
|
|
9564
|
+
try {
|
|
9565
|
+
const payload = JSON.parse(businessResponse?.body ?? "");
|
|
9566
|
+
actualIds = (payload.data?.capabilities ?? []).map((capability) => capability.id).filter((id) => typeof id === "string").sort();
|
|
9567
|
+
} catch (error) {
|
|
9568
|
+
capabilityError = error instanceof Error ? error.message : String(error);
|
|
9569
|
+
}
|
|
9570
|
+
const expectedIds = [...config.legacyCapabilityProbe.expectedIds].sort();
|
|
9571
|
+
const missingIds = expectedIds.filter((id) => !actualIds.includes(id));
|
|
9572
|
+
checks.push({
|
|
9573
|
+
name: "capability-configs",
|
|
9574
|
+
success: businessSuccess && capabilityError.length === 0 && missingIds.length === 0,
|
|
9575
|
+
message: capabilityError.length > 0 ? `capability response is invalid JSON: ${capabilityError}` : missingIds.length > 0 ? `capability response missed: ${missingIds.join(", ")}` : `${expectedIds.length} workspace capability configs loaded`
|
|
9576
|
+
});
|
|
9577
|
+
}
|
|
9578
|
+
if (actionPluginCount > 0) {
|
|
9579
|
+
const marker = `MIAODA_ACTION_PLUGIN_REGISTRY_OK:${actionPluginCount}`;
|
|
9580
|
+
const markerDeadline = Date.now() + Math.min(1e3, timeoutMs);
|
|
9581
|
+
while (!stderr.includes(marker) && Date.now() < markerDeadline) {
|
|
9582
|
+
await new Promise((resolve2) => setTimeout(resolve2, 10));
|
|
9583
|
+
}
|
|
9584
|
+
checks.push({
|
|
9585
|
+
name: "action-plugin-registry",
|
|
9586
|
+
success: stderr.includes(marker),
|
|
9587
|
+
message: stderr.includes(marker) ? `${actionPluginCount} static Action Plugin packages registered` : `static Action Plugin registry marker missing: expected ${actionPluginCount}`
|
|
9588
|
+
});
|
|
9589
|
+
}
|
|
9590
|
+
if (actionPluginProbeKey) {
|
|
9591
|
+
const marker = `MIAODA_ACTION_PLUGIN_PROBE_OK:${actionPluginProbeKey}`;
|
|
9592
|
+
const markerDeadline = Date.now() + Math.min(1e3, timeoutMs);
|
|
9593
|
+
while (!stderr.includes(marker) && Date.now() < markerDeadline) {
|
|
9594
|
+
await new Promise((resolve2) => setTimeout(resolve2, 10));
|
|
9595
|
+
}
|
|
9596
|
+
checks.push({
|
|
9597
|
+
name: "action-plugin-instantiation",
|
|
9598
|
+
success: stderr.includes(marker),
|
|
9599
|
+
message: stderr.includes(marker) ? `static Action Plugin instantiated: ${actionPluginProbeKey}` : `static Action Plugin probe marker missing: ${actionPluginProbeKey}`
|
|
9600
|
+
});
|
|
9601
|
+
}
|
|
9602
|
+
await new Promise((resolve2) => setTimeout(resolve2, 25));
|
|
9603
|
+
checks.push({
|
|
9604
|
+
name: "process-alive",
|
|
9605
|
+
success: child.exitCode === null && child.signalCode === null,
|
|
9606
|
+
...child.exitCode !== null ? { message: `process exited with code ${child.exitCode}` } : {}
|
|
9607
|
+
});
|
|
9608
|
+
const moduleNotFound = /MODULE_NOT_FOUND/.test(
|
|
9609
|
+
`${stdout}
|
|
9610
|
+
${stderr}
|
|
9611
|
+
${responseText}`
|
|
9612
|
+
);
|
|
9613
|
+
checks.push({
|
|
9614
|
+
name: "module-resolution",
|
|
9615
|
+
success: !moduleNotFound,
|
|
9616
|
+
...moduleNotFound ? { message: "MODULE_NOT_FOUND appeared in stderr or HTTP response" } : {}
|
|
9617
|
+
});
|
|
9618
|
+
const success = checks.every((check2) => check2.success);
|
|
9619
|
+
return {
|
|
9620
|
+
success,
|
|
9621
|
+
nodeModulesPresent,
|
|
9622
|
+
port,
|
|
9623
|
+
startupMs,
|
|
9624
|
+
checks,
|
|
9625
|
+
...stdout.trim() ? { stdout: stdout.trim() } : {},
|
|
9626
|
+
...stderr.trim() ? { stderr: stderr.trim() } : {}
|
|
9627
|
+
};
|
|
9628
|
+
} finally {
|
|
9629
|
+
await terminateProcessGroup(child);
|
|
9630
|
+
fs29.rmSync(probeRoot, { recursive: true, force: true });
|
|
9631
|
+
}
|
|
9632
|
+
}
|
|
9633
|
+
async function buildServerCacheBundle(options) {
|
|
9634
|
+
const startedAt = Date.now();
|
|
9635
|
+
const projectRoot = path26.resolve(options.projectRoot);
|
|
9636
|
+
const outfile = absolute(
|
|
9637
|
+
projectRoot,
|
|
9638
|
+
options.outfile ?? ".miaoda-cache/server/server.bundle.cjs"
|
|
9639
|
+
);
|
|
9640
|
+
const metadataFile = absolute(
|
|
9641
|
+
projectRoot,
|
|
9642
|
+
options.metadataFile ?? `${outfile}.meta.json`
|
|
9643
|
+
);
|
|
9644
|
+
const fail = (reasons) => ({
|
|
9645
|
+
built: false,
|
|
9646
|
+
reasons,
|
|
9647
|
+
elapsedMs: Date.now() - startedAt
|
|
9648
|
+
});
|
|
9649
|
+
const outputValidationError = validateOwnedServerOutput(
|
|
9650
|
+
projectRoot,
|
|
9651
|
+
outfile,
|
|
9652
|
+
metadataFile
|
|
9653
|
+
);
|
|
9654
|
+
if (outputValidationError) return fail([outputValidationError]);
|
|
9655
|
+
const serverOutputRoot = path26.dirname(outfile);
|
|
9656
|
+
fs29.rmSync(serverOutputRoot, { recursive: true, force: true });
|
|
9657
|
+
const resolvedEntry = resolveCompiledEntry(projectRoot, options.entry);
|
|
9658
|
+
if (!resolvedEntry.entry) return fail(resolvedEntry.reasons);
|
|
9659
|
+
const entry = resolvedEntry.entry;
|
|
9660
|
+
if (outfile === entry || metadataFile === entry || outfile === metadataFile) {
|
|
9661
|
+
return fail(["bundle output conflicts with an input or metadata file"]);
|
|
9662
|
+
}
|
|
9663
|
+
const packageJsonPath = path26.join(projectRoot, "package.json");
|
|
9664
|
+
if (!fs29.existsSync(packageJsonPath)) {
|
|
9665
|
+
return fail([`package.json missing: ${packageJsonPath}`]);
|
|
9666
|
+
}
|
|
9667
|
+
const packageJson = JSON.parse(fs29.readFileSync(packageJsonPath, "utf8"));
|
|
9668
|
+
let availabilityProbeConfig;
|
|
9669
|
+
try {
|
|
9670
|
+
availabilityProbeConfig = resolveAvailabilityProbeConfig(
|
|
9671
|
+
projectRoot,
|
|
9672
|
+
packageJson.miaodaCache?.availabilityProbe
|
|
9673
|
+
);
|
|
9674
|
+
} catch (error) {
|
|
9675
|
+
return fail([error instanceof Error ? error.message : String(error)]);
|
|
9676
|
+
}
|
|
9677
|
+
const actionPluginResolution = resolveStaticActionPlugins(
|
|
9678
|
+
projectRoot,
|
|
9679
|
+
packageJson.actionPlugins ?? {}
|
|
9680
|
+
);
|
|
9681
|
+
if (actionPluginResolution.reasons.length > 0) {
|
|
9682
|
+
return fail(actionPluginResolution.reasons);
|
|
9683
|
+
}
|
|
9684
|
+
const actionPlugins = actionPluginResolution.plugins;
|
|
9685
|
+
const configuredActionPluginProbe = packageJson.miaodaCache?.actionPluginProbe;
|
|
9686
|
+
const actionPluginProbe = configuredActionPluginProbe === void 0 ? void 0 : typeof configuredActionPluginProbe.key === "string" && configuredActionPluginProbe.key ? {
|
|
9687
|
+
key: configuredActionPluginProbe.key,
|
|
9688
|
+
config: configuredActionPluginProbe.config
|
|
9689
|
+
} : null;
|
|
9690
|
+
if (actionPluginProbe === null) {
|
|
9691
|
+
return fail(["Action Plugin probe key is invalid"]);
|
|
9692
|
+
}
|
|
9693
|
+
if (actionPluginProbe && !actionPlugins.some((plugin) => plugin.name === actionPluginProbe.key)) {
|
|
9694
|
+
return fail([
|
|
9695
|
+
`Action Plugin probe is not configured in actionPlugins: ${actionPluginProbe.key}`
|
|
9696
|
+
]);
|
|
9697
|
+
}
|
|
9698
|
+
fs29.mkdirSync(path26.dirname(serverOutputRoot), { recursive: true });
|
|
9699
|
+
const tempRoot = fs29.mkdtempSync(
|
|
9700
|
+
path26.join(path26.dirname(serverOutputRoot), ".server-build-")
|
|
9701
|
+
);
|
|
9702
|
+
const tempOutfile = path26.join(tempRoot, "server.bundle.cjs");
|
|
9703
|
+
try {
|
|
9704
|
+
const result = await build({
|
|
9705
|
+
absWorkingDir: projectRoot,
|
|
9706
|
+
entryPoints: [entry],
|
|
9707
|
+
outfile: tempOutfile,
|
|
9708
|
+
bundle: true,
|
|
9709
|
+
platform: "node",
|
|
9710
|
+
format: "cjs",
|
|
9711
|
+
target: "node22",
|
|
9712
|
+
treeShaking: true,
|
|
9713
|
+
keepNames: true,
|
|
9714
|
+
legalComments: "none",
|
|
9715
|
+
sourcemap: false,
|
|
9716
|
+
metafile: true,
|
|
9717
|
+
logLevel: "silent",
|
|
9718
|
+
define: {
|
|
9719
|
+
"import.meta.url": "__miaoda_server_cache_import_meta_url__"
|
|
9720
|
+
},
|
|
9721
|
+
banner: {
|
|
9722
|
+
js: 'const __miaoda_server_cache_import_meta_url__ = require("node:url").pathToFileURL(__filename).href;'
|
|
9723
|
+
},
|
|
9724
|
+
plugins: [
|
|
9725
|
+
rejectNativeAddonsPlugin(),
|
|
9726
|
+
fullstackNestRuntimeResolver(projectRoot),
|
|
9727
|
+
legacyFullstackNestOpenApiStub(projectRoot),
|
|
9728
|
+
staticActionPluginRegistry(
|
|
9729
|
+
projectRoot,
|
|
9730
|
+
actionPlugins,
|
|
9731
|
+
actionPluginProbe ?? void 0
|
|
9732
|
+
),
|
|
9733
|
+
classTransformerStorageResolver(projectRoot),
|
|
9734
|
+
optionalDependencyStubPlugin()
|
|
9735
|
+
]
|
|
9736
|
+
});
|
|
9737
|
+
if (!result.metafile) return fail(["esbuild metafile missing"]);
|
|
9738
|
+
for (const warning of result.warnings) {
|
|
9739
|
+
console.warn(
|
|
9740
|
+
`[server-cache-bundle] WARN ${JSON.stringify({
|
|
9741
|
+
kind: "esbuild-warning",
|
|
9742
|
+
message: warning.text,
|
|
9743
|
+
location: warning.location
|
|
9744
|
+
})}`
|
|
9745
|
+
);
|
|
9746
|
+
}
|
|
9747
|
+
const nativeInputs = Object.keys(result.metafile.inputs).filter(
|
|
9748
|
+
(input) => input.endsWith(".node")
|
|
9749
|
+
);
|
|
9750
|
+
if (nativeInputs.length > 0) {
|
|
9751
|
+
return fail([
|
|
9752
|
+
`native addons are unsupported: ${nativeInputs.join(", ")}`
|
|
9753
|
+
]);
|
|
9754
|
+
}
|
|
9755
|
+
const externalImports = collectExternalImports(
|
|
9756
|
+
result.metafile,
|
|
9757
|
+
tempOutfile,
|
|
9758
|
+
projectRoot
|
|
9759
|
+
);
|
|
9760
|
+
if (externalImports.length > 0) {
|
|
9761
|
+
return fail([`external imports remain: ${externalImports.join(", ")}`]);
|
|
9762
|
+
}
|
|
9763
|
+
const buildOnlyInputs = collectBuildOnlyInputs(
|
|
9764
|
+
projectRoot,
|
|
9765
|
+
result.metafile
|
|
9766
|
+
);
|
|
9767
|
+
if (buildOnlyInputs.length > 0) {
|
|
9768
|
+
return fail([
|
|
9769
|
+
`build-only packages entered server cache bundle: ${buildOnlyInputs.join(", ")}`
|
|
9770
|
+
]);
|
|
9771
|
+
}
|
|
9772
|
+
const configuredRuntimeAssets = [
|
|
9773
|
+
...packageJson.miaodaCache?.runtimeAssets ?? [],
|
|
9774
|
+
...availabilityProbeConfig.legacyCapabilityProbe?.files.length ? [
|
|
9775
|
+
{
|
|
9776
|
+
source: "server/capabilities",
|
|
9777
|
+
path: "server/capabilities"
|
|
9778
|
+
}
|
|
9779
|
+
] : []
|
|
9780
|
+
];
|
|
9781
|
+
const materializedRuntimeAssets = materializeServerRuntimeAssets(
|
|
9782
|
+
projectRoot,
|
|
9783
|
+
result.metafile,
|
|
9784
|
+
tempRoot,
|
|
9785
|
+
configuredRuntimeAssets
|
|
9786
|
+
);
|
|
9787
|
+
const runtimeAssets = materializedRuntimeAssets.assets;
|
|
9788
|
+
const runtimeAssetWarnings = materializedRuntimeAssets.warnings;
|
|
9789
|
+
const dynamicImportWarnings = collectDynamicImportWarnings(
|
|
9790
|
+
projectRoot,
|
|
9791
|
+
result.metafile
|
|
9792
|
+
);
|
|
9793
|
+
for (const warning of [...dynamicImportWarnings, ...runtimeAssetWarnings]) {
|
|
9794
|
+
console.warn(`[server-cache-bundle] WARN ${JSON.stringify(warning)}`);
|
|
9795
|
+
}
|
|
9796
|
+
const availabilityProbe = await runAvailabilityProbe(
|
|
9797
|
+
tempOutfile,
|
|
9798
|
+
runtimeAssets,
|
|
9799
|
+
options.probeTimeoutMs ?? 3e4,
|
|
9800
|
+
availabilityProbeConfig,
|
|
9801
|
+
actionPlugins.length,
|
|
9802
|
+
actionPluginProbe?.key
|
|
9803
|
+
);
|
|
9804
|
+
if (!availabilityProbe.success || availabilityProbe.nodeModulesPresent) {
|
|
9805
|
+
return fail([
|
|
9806
|
+
"isolated node_modules-free availability probe failed",
|
|
9807
|
+
...availabilityProbe.checks.filter((check2) => !check2.success).map(
|
|
9808
|
+
(check2) => `${check2.name}: ${check2.message ?? `HTTP ${check2.status ?? "unavailable"}`}`
|
|
9809
|
+
),
|
|
9810
|
+
...availabilityProbe.stderr ? [availabilityProbe.stderr] : [],
|
|
9811
|
+
...availabilityProbe.stdout ? [availabilityProbe.stdout] : []
|
|
9812
|
+
]);
|
|
9813
|
+
}
|
|
9814
|
+
const bundleSha256 = createHash("sha256").update(fs29.readFileSync(tempOutfile)).digest("hex");
|
|
9815
|
+
const sealedAvailabilityProbe = {
|
|
9816
|
+
success: availabilityProbe.success,
|
|
9817
|
+
nodeModulesPresent: availabilityProbe.nodeModulesPresent,
|
|
9818
|
+
startupMs: availabilityProbe.startupMs,
|
|
9819
|
+
checks: availabilityProbe.checks,
|
|
9820
|
+
...availabilityProbe.stderr ? { stderr: availabilityProbe.stderr } : {}
|
|
9821
|
+
};
|
|
9822
|
+
const metadata = {
|
|
9823
|
+
schemaVersion: 2,
|
|
9824
|
+
entry: path26.relative(projectRoot, entry).split(path26.sep).join("/"),
|
|
9825
|
+
outfile: "server/server.bundle.cjs",
|
|
9826
|
+
nodeVersion: process.version,
|
|
9827
|
+
nodeModuleAbi: process.versions.modules,
|
|
9828
|
+
platform: process.platform,
|
|
9829
|
+
arch: process.arch,
|
|
9830
|
+
bundleBytes: fs29.statSync(tempOutfile).size,
|
|
9831
|
+
bundleSha256,
|
|
9832
|
+
inputFiles: Object.keys(result.metafile.inputs).length,
|
|
9833
|
+
workspaceSourceSha256: workspaceSourceSha256(projectRoot),
|
|
9834
|
+
externalImports,
|
|
9835
|
+
dynamicImportWarnings,
|
|
9836
|
+
runtimeAssetWarnings,
|
|
9837
|
+
actionPlugins: actionPlugins.map(({ name, version }) => ({
|
|
9838
|
+
name,
|
|
9839
|
+
version
|
|
9840
|
+
})),
|
|
9841
|
+
runtimeAssets,
|
|
9842
|
+
availabilityProbe: sealedAvailabilityProbe,
|
|
9843
|
+
consumable: true
|
|
9844
|
+
};
|
|
9845
|
+
fs29.writeFileSync(
|
|
9846
|
+
path26.join(tempRoot, path26.basename(metadataFile)),
|
|
9847
|
+
`${JSON.stringify(metadata, null, 2)}
|
|
9848
|
+
`
|
|
9849
|
+
);
|
|
9850
|
+
fs29.mkdirSync(path26.dirname(serverOutputRoot), { recursive: true });
|
|
9851
|
+
fs29.renameSync(tempRoot, serverOutputRoot);
|
|
9852
|
+
return {
|
|
9853
|
+
built: true,
|
|
9854
|
+
outfile,
|
|
9855
|
+
metadataFile,
|
|
9856
|
+
bundleBytes: metadata.bundleBytes,
|
|
9857
|
+
inputFiles: metadata.inputFiles,
|
|
9858
|
+
externalImports,
|
|
9859
|
+
dynamicImportWarnings,
|
|
9860
|
+
runtimeAssetWarnings,
|
|
9861
|
+
runtimeAssets,
|
|
9862
|
+
actionPlugins: actionPlugins.map(({ name, version }) => ({
|
|
9863
|
+
name,
|
|
9864
|
+
version
|
|
9865
|
+
})),
|
|
9866
|
+
availabilityProbe,
|
|
9867
|
+
reasons: [],
|
|
9868
|
+
elapsedMs: Date.now() - startedAt
|
|
9869
|
+
};
|
|
9870
|
+
} catch (error) {
|
|
9871
|
+
fs29.rmSync(serverOutputRoot, { recursive: true, force: true });
|
|
9872
|
+
return fail([error instanceof Error ? error.message : String(error)]);
|
|
9873
|
+
} finally {
|
|
9874
|
+
fs29.rmSync(tempRoot, { recursive: true, force: true });
|
|
9875
|
+
}
|
|
9876
|
+
}
|
|
9877
|
+
|
|
9878
|
+
// src/commands/build/server-runtime-dependencies.handler.ts
|
|
9879
|
+
import crypto from "crypto";
|
|
9880
|
+
import fs30 from "fs";
|
|
9881
|
+
import path27 from "path";
|
|
9882
|
+
import { createRequire as createRequire4 } from "module";
|
|
9883
|
+
import { nodeFileTrace } from "@vercel/nft";
|
|
9884
|
+
var DEFAULT_COMPILED_ENTRIES2 = [
|
|
9885
|
+
"dist/server/main.js",
|
|
9886
|
+
"dist/main.js"
|
|
9887
|
+
];
|
|
9888
|
+
var DEFAULT_SOURCE_ENTRIES = ["server/main.ts", "src/main.ts"];
|
|
9889
|
+
var TRANSITION_BOOTSTRAP_SPECIFIERS = [
|
|
9890
|
+
"ts-node/register/transpile-only",
|
|
9891
|
+
"tsconfig-paths/register"
|
|
9892
|
+
];
|
|
9893
|
+
var TRANSITION_TOOLCHAIN_TRACE_SPECIFIERS = ["typescript"];
|
|
9894
|
+
var PROJECT_ROOT_TOKEN = "${MIAODA_WORKSPACE_ROOT}";
|
|
9895
|
+
function isPathInside2(root, candidate) {
|
|
9896
|
+
const relative = path27.relative(root, candidate);
|
|
9897
|
+
return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
|
|
9898
|
+
}
|
|
9899
|
+
function sha256(file) {
|
|
9900
|
+
return crypto.createHash("sha256").update(fs30.readFileSync(file)).digest("hex");
|
|
9901
|
+
}
|
|
9902
|
+
function resolveExistingFile(projectRoot, requested, defaults, label) {
|
|
9903
|
+
if (requested) {
|
|
9904
|
+
const candidate = path27.resolve(projectRoot, requested);
|
|
9905
|
+
if (!fs30.existsSync(candidate) || !fs30.statSync(candidate).isFile()) {
|
|
9906
|
+
throw new Error(`${label} missing: ${candidate}`);
|
|
9907
|
+
}
|
|
9908
|
+
return candidate;
|
|
9909
|
+
}
|
|
9910
|
+
const matches = defaults.map((relative) => path27.join(projectRoot, relative)).filter((candidate) => fs30.existsSync(candidate));
|
|
9911
|
+
if (matches.length === 1) return matches[0];
|
|
9912
|
+
if (matches.length > 1) {
|
|
9913
|
+
throw new Error(
|
|
9914
|
+
`${label} is ambiguous; pass it explicitly: ${matches.join(", ")}`
|
|
9915
|
+
);
|
|
9916
|
+
}
|
|
9917
|
+
throw new Error(
|
|
9918
|
+
`${label} missing; checked: ${defaults.map((relative) => path27.join(projectRoot, relative)).join(", ")}`
|
|
9919
|
+
);
|
|
9920
|
+
}
|
|
9921
|
+
function packageLocationFromNodeModulesPath(candidate) {
|
|
9922
|
+
const parts = candidate.split(/[\\/]+/);
|
|
9923
|
+
const nodeModulesIndex = parts.lastIndexOf("node_modules");
|
|
9924
|
+
if (nodeModulesIndex < 0 || nodeModulesIndex + 1 >= parts.length) {
|
|
9925
|
+
return void 0;
|
|
9926
|
+
}
|
|
9927
|
+
const first = parts[nodeModulesIndex + 1];
|
|
9928
|
+
let name;
|
|
9929
|
+
let packageEnd;
|
|
9930
|
+
if (first.startsWith("@")) {
|
|
9931
|
+
const second = parts[nodeModulesIndex + 2];
|
|
9932
|
+
if (!second) return void 0;
|
|
9933
|
+
name = `${first}/${second}`;
|
|
9934
|
+
packageEnd = nodeModulesIndex + 3;
|
|
9935
|
+
} else {
|
|
9936
|
+
name = first;
|
|
9937
|
+
packageEnd = nodeModulesIndex + 2;
|
|
9938
|
+
}
|
|
9939
|
+
return {
|
|
9940
|
+
name,
|
|
9941
|
+
relativeRoot: parts.slice(0, packageEnd).join("/")
|
|
9942
|
+
};
|
|
9943
|
+
}
|
|
9944
|
+
function packageRoot(nodeModulesRoot, packageName) {
|
|
9945
|
+
return path27.join(nodeModulesRoot, ...packageName.split("/"));
|
|
9946
|
+
}
|
|
9947
|
+
function readPackage(nodeModulesRoot, packageName) {
|
|
9948
|
+
const packageFile = path27.join(
|
|
9949
|
+
packageRoot(nodeModulesRoot, packageName),
|
|
9950
|
+
"package.json"
|
|
9951
|
+
);
|
|
9952
|
+
if (!fs30.existsSync(packageFile)) {
|
|
9953
|
+
throw new Error(`runtime package is missing: ${packageName}`);
|
|
9954
|
+
}
|
|
9955
|
+
return JSON.parse(fs30.readFileSync(packageFile, "utf8"));
|
|
9956
|
+
}
|
|
9957
|
+
function parseJsonc(file, projectRequire) {
|
|
9958
|
+
const typescript = projectRequire("typescript");
|
|
9959
|
+
const parsed = typescript.parseConfigFileTextToJson(
|
|
9960
|
+
file,
|
|
9961
|
+
fs30.readFileSync(file, "utf8")
|
|
9962
|
+
);
|
|
9963
|
+
if (parsed.error || !parsed.config) {
|
|
9964
|
+
throw new Error(
|
|
9965
|
+
`tsconfig is invalid: ${file}: ${String(parsed.error?.messageText ?? "")}`
|
|
9966
|
+
);
|
|
9967
|
+
}
|
|
9968
|
+
return parsed.config;
|
|
9969
|
+
}
|
|
9970
|
+
function resolveTsconfigPackageEntries(projectRoot, projectRequire) {
|
|
9971
|
+
const entries = /* @__PURE__ */ new Set();
|
|
9972
|
+
const visited = /* @__PURE__ */ new Set();
|
|
9973
|
+
const initial = ["tsconfig.node.json", "tsconfig.json"].map((relative) => path27.join(projectRoot, relative)).find((file) => fs30.existsSync(file));
|
|
9974
|
+
if (!initial) return [];
|
|
9975
|
+
const visit = (file) => {
|
|
9976
|
+
const resolvedFile = fs30.realpathSync(file);
|
|
9977
|
+
if (visited.has(resolvedFile)) return;
|
|
9978
|
+
visited.add(resolvedFile);
|
|
9979
|
+
const config = parseJsonc(resolvedFile, projectRequire);
|
|
9980
|
+
if (typeof config.extends !== "string" || !config.extends) return;
|
|
9981
|
+
const specifier = config.extends;
|
|
9982
|
+
if (specifier.startsWith(".") || path27.isAbsolute(specifier)) {
|
|
9983
|
+
const candidate = path27.resolve(path27.dirname(resolvedFile), specifier);
|
|
9984
|
+
const configFile = fs30.existsSync(candidate) ? candidate : `${candidate}.json`;
|
|
9985
|
+
if (!fs30.existsSync(configFile)) {
|
|
9986
|
+
throw new Error(`tsconfig extends file is missing: ${specifier}`);
|
|
9987
|
+
}
|
|
9988
|
+
visit(configFile);
|
|
9989
|
+
return;
|
|
9990
|
+
}
|
|
9991
|
+
let entry;
|
|
9992
|
+
try {
|
|
9993
|
+
entry = projectRequire.resolve(specifier);
|
|
9994
|
+
} catch {
|
|
9995
|
+
try {
|
|
9996
|
+
entry = projectRequire.resolve(`${specifier}.json`);
|
|
9997
|
+
} catch {
|
|
9998
|
+
throw new Error(`tsconfig extends package is missing: ${specifier}`);
|
|
9999
|
+
}
|
|
10000
|
+
}
|
|
10001
|
+
entries.add(entry);
|
|
10002
|
+
if (entry.endsWith(".json")) visit(entry);
|
|
10003
|
+
};
|
|
10004
|
+
visit(initial);
|
|
10005
|
+
return [...entries];
|
|
10006
|
+
}
|
|
10007
|
+
function transitionCompilerOptions(projectRoot, projectRequire) {
|
|
10008
|
+
const configFile = ["tsconfig.node.json", "tsconfig.json"].map((relative) => path27.join(projectRoot, relative)).find((file) => fs30.existsSync(file));
|
|
10009
|
+
if (!configFile) throw new Error("server tsconfig is missing");
|
|
10010
|
+
const typescript = projectRequire("typescript");
|
|
10011
|
+
let fatalDiagnostic = "";
|
|
10012
|
+
const parsed = typescript.getParsedCommandLineOfConfigFile(
|
|
10013
|
+
configFile,
|
|
10014
|
+
{},
|
|
10015
|
+
{
|
|
10016
|
+
...typescript.sys,
|
|
10017
|
+
onUnRecoverableConfigFileDiagnostic: (diagnostic) => {
|
|
10018
|
+
fatalDiagnostic = typescript.flattenDiagnosticMessageText(
|
|
10019
|
+
diagnostic.messageText,
|
|
10020
|
+
"\n"
|
|
10021
|
+
);
|
|
10022
|
+
}
|
|
10023
|
+
}
|
|
10024
|
+
);
|
|
10025
|
+
const errors = parsed?.errors.filter((error) => error.category === typescript.DiagnosticCategory.Error).map(
|
|
10026
|
+
(error) => typescript.flattenDiagnosticMessageText(error.messageText, "\n")
|
|
10027
|
+
);
|
|
10028
|
+
if (!parsed || fatalDiagnostic || errors?.length) {
|
|
10029
|
+
throw new Error(
|
|
10030
|
+
`server tsconfig cannot be resolved: ${fatalDiagnostic || errors?.join("; ") || configFile}`
|
|
10031
|
+
);
|
|
10032
|
+
}
|
|
10033
|
+
const tokeniseProjectPaths = (value) => {
|
|
10034
|
+
if (typeof value === "string" && path27.isAbsolute(value)) {
|
|
10035
|
+
if (!isPathInside2(projectRoot, value)) {
|
|
10036
|
+
throw new Error(`server compiler option path escaped project: ${value}`);
|
|
10037
|
+
}
|
|
10038
|
+
const relative = path27.relative(projectRoot, value).split(path27.sep).join("/");
|
|
10039
|
+
return relative ? `${PROJECT_ROOT_TOKEN}/${relative}` : PROJECT_ROOT_TOKEN;
|
|
10040
|
+
}
|
|
10041
|
+
if (Array.isArray(value)) return value.map(tokeniseProjectPaths);
|
|
10042
|
+
if (value && typeof value === "object") {
|
|
10043
|
+
return Object.fromEntries(
|
|
10044
|
+
Object.entries(value).map(([key, entry]) => [
|
|
10045
|
+
key,
|
|
10046
|
+
tokeniseProjectPaths(entry)
|
|
10047
|
+
])
|
|
10048
|
+
);
|
|
10049
|
+
}
|
|
10050
|
+
return value;
|
|
10051
|
+
};
|
|
10052
|
+
return tokeniseProjectPaths(
|
|
10053
|
+
Object.fromEntries(typescript.serializeCompilerOptions(parsed.options))
|
|
10054
|
+
);
|
|
10055
|
+
}
|
|
10056
|
+
function collectDeclaredPluginClosure(nodeModulesRoot, seeds) {
|
|
10057
|
+
const selected = new Set(seeds);
|
|
10058
|
+
const pending = [...selected];
|
|
10059
|
+
while (pending.length > 0) {
|
|
10060
|
+
const packageName = pending.shift();
|
|
10061
|
+
const packageJson = readPackage(nodeModulesRoot, packageName);
|
|
10062
|
+
const declared = {
|
|
10063
|
+
...packageJson.dependencies ?? {},
|
|
10064
|
+
...packageJson.optionalDependencies ?? {},
|
|
10065
|
+
...packageJson.peerDependencies ?? {}
|
|
10066
|
+
};
|
|
10067
|
+
for (const dependencyName of Object.keys(declared)) {
|
|
10068
|
+
if (!fs30.existsSync(packageRoot(nodeModulesRoot, dependencyName))) {
|
|
10069
|
+
const optional = packageJson.peerDependenciesMeta?.[dependencyName]?.optional === true || Object.hasOwn(packageJson.optionalDependencies ?? {}, dependencyName);
|
|
10070
|
+
if (optional) continue;
|
|
10071
|
+
throw new Error(
|
|
10072
|
+
`ActionPlugin runtime dependency ${dependencyName} required by ${packageName} is missing`
|
|
10073
|
+
);
|
|
10074
|
+
}
|
|
10075
|
+
if (!selected.has(dependencyName)) {
|
|
10076
|
+
selected.add(dependencyName);
|
|
10077
|
+
pending.push(dependencyName);
|
|
10078
|
+
}
|
|
10079
|
+
}
|
|
10080
|
+
}
|
|
10081
|
+
return selected;
|
|
10082
|
+
}
|
|
10083
|
+
function copyDereferenced(source, destination) {
|
|
10084
|
+
const stat = fs30.lstatSync(source);
|
|
10085
|
+
if (stat.isSymbolicLink()) {
|
|
10086
|
+
copyDereferenced(fs30.realpathSync(source), destination);
|
|
10087
|
+
return;
|
|
10088
|
+
}
|
|
10089
|
+
if (stat.isDirectory()) {
|
|
10090
|
+
fs30.mkdirSync(destination, { recursive: true });
|
|
10091
|
+
for (const entry of fs30.readdirSync(source)) {
|
|
10092
|
+
copyDereferenced(
|
|
10093
|
+
path27.join(source, entry),
|
|
10094
|
+
path27.join(destination, entry)
|
|
10095
|
+
);
|
|
10096
|
+
}
|
|
10097
|
+
return;
|
|
10098
|
+
}
|
|
10099
|
+
if (!stat.isFile()) {
|
|
10100
|
+
throw new Error(`unsupported runtime dependency file: ${source}`);
|
|
10101
|
+
}
|
|
10102
|
+
fs30.mkdirSync(path27.dirname(destination), { recursive: true });
|
|
10103
|
+
fs30.copyFileSync(source, destination);
|
|
10104
|
+
fs30.chmodSync(destination, stat.mode & 511);
|
|
10105
|
+
}
|
|
10106
|
+
function listRuntimeFiles(nodeModulesRoot) {
|
|
10107
|
+
const files = [];
|
|
10108
|
+
const visit = (directory) => {
|
|
10109
|
+
for (const entry of fs30.readdirSync(directory, { withFileTypes: true })) {
|
|
10110
|
+
const candidate = path27.join(directory, entry.name);
|
|
10111
|
+
if (entry.isSymbolicLink()) {
|
|
10112
|
+
throw new Error(`runtime dependency cache contains symlink: ${candidate}`);
|
|
10113
|
+
}
|
|
10114
|
+
if (entry.isDirectory()) {
|
|
10115
|
+
visit(candidate);
|
|
10116
|
+
} else if (entry.isFile()) {
|
|
10117
|
+
files.push({
|
|
10118
|
+
path: path27.relative(nodeModulesRoot, candidate).split(path27.sep).join("/"),
|
|
10119
|
+
sha256: sha256(candidate),
|
|
10120
|
+
size: fs30.statSync(candidate).size
|
|
10121
|
+
});
|
|
10122
|
+
}
|
|
10123
|
+
}
|
|
10124
|
+
};
|
|
10125
|
+
visit(nodeModulesRoot);
|
|
10126
|
+
return files.sort((left, right) => left.path.localeCompare(right.path));
|
|
10127
|
+
}
|
|
10128
|
+
function stableTreeSha256(files) {
|
|
10129
|
+
return crypto.createHash("sha256").update(JSON.stringify(files)).digest("hex");
|
|
10130
|
+
}
|
|
10131
|
+
function validateOutput(projectRoot, outdir, metadataFile) {
|
|
10132
|
+
const expectedRoot = path27.join(projectRoot, ".miaoda-cache");
|
|
10133
|
+
if (!isPathInside2(expectedRoot, outdir) || path27.basename(outdir) !== "node_modules" || path27.basename(path27.dirname(outdir)) !== "server" || metadataFile !== path27.join(path27.dirname(outdir), "dependencies.json")) {
|
|
10134
|
+
throw new Error(
|
|
10135
|
+
"server runtime dependency output must be a .miaoda-cache/**/server/node_modules directory with adjacent dependencies.json"
|
|
10136
|
+
);
|
|
10137
|
+
}
|
|
10138
|
+
}
|
|
10139
|
+
async function buildServerRuntimeDependencies(options) {
|
|
10140
|
+
const startedAt = Date.now();
|
|
10141
|
+
const projectRoot = fs30.realpathSync(path27.resolve(options.projectRoot));
|
|
10142
|
+
const outdir = path27.resolve(
|
|
10143
|
+
projectRoot,
|
|
10144
|
+
options.outdir ?? ".miaoda-cache/server/node_modules"
|
|
10145
|
+
);
|
|
10146
|
+
const metadataFile = path27.resolve(
|
|
10147
|
+
projectRoot,
|
|
10148
|
+
options.metadataFile ?? path27.join(path27.dirname(outdir), "dependencies.json")
|
|
10149
|
+
);
|
|
10150
|
+
const stagingRoot = path27.join(
|
|
10151
|
+
path27.dirname(outdir),
|
|
10152
|
+
`.dependencies-staging-${process.pid}-${Date.now()}`
|
|
10153
|
+
);
|
|
10154
|
+
const stagingNodeModules = path27.join(stagingRoot, "node_modules");
|
|
10155
|
+
const serverOutputRoot = path27.dirname(outdir);
|
|
10156
|
+
try {
|
|
10157
|
+
validateOutput(projectRoot, outdir, metadataFile);
|
|
10158
|
+
fs30.rmSync(serverOutputRoot, { recursive: true, force: true });
|
|
10159
|
+
fs30.mkdirSync(serverOutputRoot, { recursive: true });
|
|
10160
|
+
const compiledEntry = resolveExistingFile(
|
|
10161
|
+
projectRoot,
|
|
10162
|
+
options.entry,
|
|
10163
|
+
DEFAULT_COMPILED_ENTRIES2,
|
|
10164
|
+
"compiled Nest entry"
|
|
10165
|
+
);
|
|
10166
|
+
const sourceEntry = resolveExistingFile(
|
|
10167
|
+
projectRoot,
|
|
10168
|
+
options.sourceEntry,
|
|
10169
|
+
DEFAULT_SOURCE_ENTRIES,
|
|
10170
|
+
"Nest source entry"
|
|
10171
|
+
);
|
|
10172
|
+
const projectPackageFile = path27.join(projectRoot, "package.json");
|
|
10173
|
+
const projectNodeModules = path27.join(projectRoot, "node_modules");
|
|
10174
|
+
if (!fs30.existsSync(projectPackageFile) || !fs30.existsSync(projectNodeModules)) {
|
|
10175
|
+
throw new Error("project package.json or node_modules is missing");
|
|
10176
|
+
}
|
|
10177
|
+
const projectPackage = JSON.parse(
|
|
10178
|
+
fs30.readFileSync(projectPackageFile, "utf8")
|
|
10179
|
+
);
|
|
10180
|
+
const projectRequire = createRequire4(projectPackageFile);
|
|
10181
|
+
const configuredPlatformRuntimeRoot = process.env.MIAODA_PLATFORM_RUNTIME_ROOT;
|
|
10182
|
+
const platformNodeModules = configuredPlatformRuntimeRoot ? path27.join(
|
|
10183
|
+
fs30.realpathSync(path27.resolve(configuredPlatformRuntimeRoot)),
|
|
10184
|
+
"node_modules"
|
|
10185
|
+
) : void 0;
|
|
10186
|
+
if (platformNodeModules && (!fs30.existsSync(platformNodeModules) || !fs30.statSync(platformNodeModules).isDirectory())) {
|
|
10187
|
+
throw new Error(
|
|
10188
|
+
`platform runtime node_modules is missing: ${platformNodeModules}`
|
|
10189
|
+
);
|
|
10190
|
+
}
|
|
10191
|
+
const traceBase = platformNodeModules ? path27.parse(projectRoot).root : projectRoot;
|
|
10192
|
+
const bootstrapEntries = TRANSITION_BOOTSTRAP_SPECIFIERS.map((specifier) => {
|
|
10193
|
+
try {
|
|
10194
|
+
return projectRequire.resolve(specifier);
|
|
10195
|
+
} catch {
|
|
10196
|
+
throw new Error(`transition bootstrap module is missing: ${specifier}`);
|
|
10197
|
+
}
|
|
10198
|
+
});
|
|
10199
|
+
const toolchainTraceEntries = TRANSITION_TOOLCHAIN_TRACE_SPECIFIERS.map(
|
|
10200
|
+
(specifier) => {
|
|
10201
|
+
try {
|
|
10202
|
+
return projectRequire.resolve(specifier);
|
|
10203
|
+
} catch {
|
|
10204
|
+
throw new Error(`transition toolchain module is missing: ${specifier}`);
|
|
10205
|
+
}
|
|
10206
|
+
}
|
|
10207
|
+
);
|
|
10208
|
+
const actionPluginNames = Object.keys(projectPackage.actionPlugins ?? {});
|
|
10209
|
+
const actionPluginEntries = actionPluginNames.map((name) => {
|
|
10210
|
+
try {
|
|
10211
|
+
return projectRequire.resolve(name);
|
|
10212
|
+
} catch {
|
|
10213
|
+
throw new Error(`ActionPlugin entry is missing: ${name}`);
|
|
10214
|
+
}
|
|
10215
|
+
});
|
|
10216
|
+
const tsconfigPackageEntries = resolveTsconfigPackageEntries(
|
|
10217
|
+
projectRoot,
|
|
10218
|
+
projectRequire
|
|
10219
|
+
);
|
|
10220
|
+
const compilerOptions = transitionCompilerOptions(
|
|
10221
|
+
projectRoot,
|
|
10222
|
+
projectRequire
|
|
10223
|
+
);
|
|
10224
|
+
const trace = await nodeFileTrace(
|
|
10225
|
+
[
|
|
10226
|
+
compiledEntry,
|
|
10227
|
+
...bootstrapEntries,
|
|
10228
|
+
...toolchainTraceEntries,
|
|
10229
|
+
...tsconfigPackageEntries,
|
|
10230
|
+
...actionPluginEntries
|
|
10231
|
+
],
|
|
10232
|
+
{
|
|
10233
|
+
base: traceBase,
|
|
10234
|
+
processCwd: projectRoot,
|
|
10235
|
+
ts: false,
|
|
10236
|
+
conditions: ["node", "development"]
|
|
10237
|
+
}
|
|
10238
|
+
);
|
|
10239
|
+
const tracedFiles = /* @__PURE__ */ new Map();
|
|
10240
|
+
const packageLocations = /* @__PURE__ */ new Map();
|
|
10241
|
+
const addTracedFile = (candidate) => {
|
|
10242
|
+
let source = path27.isAbsolute(candidate) ? candidate : path27.resolve(traceBase, candidate);
|
|
10243
|
+
if (!fs30.existsSync(source)) {
|
|
10244
|
+
return;
|
|
10245
|
+
}
|
|
10246
|
+
const sourceStat = fs30.lstatSync(source);
|
|
10247
|
+
if (sourceStat.isSymbolicLink()) {
|
|
10248
|
+
const realSource = fs30.realpathSync(source);
|
|
10249
|
+
if (fs30.statSync(realSource).isDirectory()) {
|
|
10250
|
+
if (platformNodeModules && isPathInside2(platformNodeModules, realSource)) {
|
|
10251
|
+
return;
|
|
10252
|
+
}
|
|
10253
|
+
throw new Error(`runtime dependency symlink is not trusted: ${source}`);
|
|
10254
|
+
}
|
|
10255
|
+
source = realSource;
|
|
10256
|
+
}
|
|
10257
|
+
const sourceNodeModules = [projectNodeModules, platformNodeModules].filter((root) => Boolean(root)).find((root) => isPathInside2(root, source));
|
|
10258
|
+
if (!sourceNodeModules) {
|
|
10259
|
+
return;
|
|
10260
|
+
}
|
|
10261
|
+
const relativeNodeModulesPath = path27.relative(sourceNodeModules, source);
|
|
10262
|
+
const logicalProjectPath = path27.join("node_modules", relativeNodeModulesPath).split(path27.sep).join("/");
|
|
10263
|
+
const location = packageLocationFromNodeModulesPath(logicalProjectPath);
|
|
10264
|
+
if (!location) return;
|
|
10265
|
+
const sourceRoot = path27.join(
|
|
10266
|
+
sourceNodeModules,
|
|
10267
|
+
...location.relativeRoot.replace(/^node_modules\//, "").split("/")
|
|
10268
|
+
);
|
|
10269
|
+
const destinationRoot = path27.join(
|
|
10270
|
+
stagingNodeModules,
|
|
10271
|
+
...location.relativeRoot.replace(/^node_modules\//, "").split("/")
|
|
10272
|
+
);
|
|
10273
|
+
packageLocations.set(location.relativeRoot, {
|
|
10274
|
+
name: location.name,
|
|
10275
|
+
destinationRoot
|
|
10276
|
+
});
|
|
10277
|
+
const addFile = (file, destination) => {
|
|
10278
|
+
const previous = tracedFiles.get(destination);
|
|
10279
|
+
if (previous && fs30.realpathSync(previous) !== fs30.realpathSync(file) && sha256(previous) !== sha256(file)) {
|
|
10280
|
+
throw new Error(
|
|
10281
|
+
`runtime dependency destination conflict: ${destination}`
|
|
10282
|
+
);
|
|
10283
|
+
}
|
|
10284
|
+
tracedFiles.set(destination, file);
|
|
10285
|
+
};
|
|
10286
|
+
addFile(
|
|
10287
|
+
source,
|
|
10288
|
+
path27.join(stagingNodeModules, relativeNodeModulesPath)
|
|
10289
|
+
);
|
|
10290
|
+
addFile(
|
|
10291
|
+
path27.join(sourceRoot, "package.json"),
|
|
10292
|
+
path27.join(destinationRoot, "package.json")
|
|
10293
|
+
);
|
|
10294
|
+
};
|
|
10295
|
+
for (const file of trace.fileList) {
|
|
10296
|
+
addTracedFile(file);
|
|
10297
|
+
}
|
|
10298
|
+
for (const specifier of TRANSITION_BOOTSTRAP_SPECIFIERS) {
|
|
10299
|
+
addTracedFile(projectRequire.resolve(specifier));
|
|
10300
|
+
}
|
|
10301
|
+
for (const specifier of TRANSITION_TOOLCHAIN_TRACE_SPECIFIERS) {
|
|
10302
|
+
addTracedFile(projectRequire.resolve(specifier));
|
|
10303
|
+
}
|
|
10304
|
+
for (const entry of tsconfigPackageEntries) {
|
|
10305
|
+
addTracedFile(entry);
|
|
10306
|
+
}
|
|
10307
|
+
const pluginClosure = collectDeclaredPluginClosure(
|
|
10308
|
+
projectNodeModules,
|
|
10309
|
+
actionPluginNames
|
|
10310
|
+
);
|
|
10311
|
+
fs30.rmSync(stagingRoot, { recursive: true, force: true });
|
|
10312
|
+
fs30.mkdirSync(stagingNodeModules, { recursive: true });
|
|
10313
|
+
for (const [destination, source] of [...tracedFiles.entries()].sort(
|
|
10314
|
+
([left], [right]) => left.localeCompare(right)
|
|
10315
|
+
)) {
|
|
10316
|
+
if (!fs30.existsSync(source) || !fs30.statSync(source).isFile()) {
|
|
10317
|
+
throw new Error(`traced runtime dependency file is missing: ${source}`);
|
|
10318
|
+
}
|
|
10319
|
+
copyDereferenced(source, destination);
|
|
10320
|
+
}
|
|
10321
|
+
for (const packageName of [...pluginClosure].sort()) {
|
|
10322
|
+
const sourceRoot = packageRoot(projectNodeModules, packageName);
|
|
10323
|
+
const destinationRoot = packageRoot(stagingNodeModules, packageName);
|
|
10324
|
+
packageLocations.set(`node_modules/${packageName}`, {
|
|
10325
|
+
name: packageName,
|
|
10326
|
+
destinationRoot
|
|
10327
|
+
});
|
|
10328
|
+
fs30.rmSync(destinationRoot, { recursive: true, force: true });
|
|
10329
|
+
copyDereferenced(sourceRoot, destinationRoot);
|
|
10330
|
+
}
|
|
10331
|
+
const files = listRuntimeFiles(stagingNodeModules);
|
|
10332
|
+
const packages = [...packageLocations.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([, location]) => ({
|
|
10333
|
+
name: location.name,
|
|
10334
|
+
version: String(
|
|
10335
|
+
JSON.parse(
|
|
10336
|
+
fs30.readFileSync(
|
|
10337
|
+
path27.join(location.destinationRoot, "package.json"),
|
|
10338
|
+
"utf8"
|
|
10339
|
+
)
|
|
10340
|
+
).version ?? ""
|
|
10341
|
+
)
|
|
10342
|
+
}));
|
|
10343
|
+
if (packages.some((pkg2) => !pkg2.version)) {
|
|
10344
|
+
throw new Error("runtime dependency package version is missing");
|
|
10345
|
+
}
|
|
10346
|
+
const actionPlugins = actionPluginNames.sort().map((name) => {
|
|
10347
|
+
const installedVersion = String(
|
|
10348
|
+
readPackage(stagingNodeModules, name).version ?? ""
|
|
10349
|
+
);
|
|
10350
|
+
const declaredVersion = String(projectPackage.actionPlugins[name]);
|
|
10351
|
+
if (!installedVersion || declaredVersion !== installedVersion) {
|
|
10352
|
+
throw new Error(
|
|
10353
|
+
`ActionPlugin version mismatch: ${name} declared=${declaredVersion} installed=${installedVersion}`
|
|
10354
|
+
);
|
|
10355
|
+
}
|
|
10356
|
+
return { name, version: installedVersion };
|
|
10357
|
+
});
|
|
10358
|
+
const metadata = {
|
|
10359
|
+
schemaVersion: 1,
|
|
10360
|
+
sourceEntry: path27.relative(projectRoot, sourceEntry).split(path27.sep).join("/"),
|
|
10361
|
+
compiledEntry: path27.relative(projectRoot, compiledEntry).split(path27.sep).join("/"),
|
|
10362
|
+
nodeVersion: process.version,
|
|
10363
|
+
nodeModuleAbi: process.versions.modules,
|
|
10364
|
+
platform: process.platform,
|
|
10365
|
+
arch: process.arch,
|
|
10366
|
+
bootstrapModules: [...TRANSITION_BOOTSTRAP_SPECIFIERS],
|
|
10367
|
+
transitionCompilerOptions: compilerOptions,
|
|
10368
|
+
packages,
|
|
10369
|
+
actionPlugins,
|
|
10370
|
+
files,
|
|
10371
|
+
treeSha256: stableTreeSha256(files),
|
|
10372
|
+
fileCount: files.length,
|
|
10373
|
+
totalBytes: files.reduce((total, file) => total + file.size, 0)
|
|
10374
|
+
};
|
|
10375
|
+
fs30.writeFileSync(
|
|
10376
|
+
path27.join(stagingRoot, "dependencies.json"),
|
|
10377
|
+
`${JSON.stringify(metadata, null, 2)}
|
|
10378
|
+
`
|
|
10379
|
+
);
|
|
10380
|
+
fs30.rmSync(outdir, { recursive: true, force: true });
|
|
10381
|
+
fs30.rmSync(metadataFile, { force: true });
|
|
10382
|
+
fs30.renameSync(stagingNodeModules, outdir);
|
|
10383
|
+
fs30.renameSync(path27.join(stagingRoot, "dependencies.json"), metadataFile);
|
|
10384
|
+
fs30.rmSync(stagingRoot, { recursive: true, force: true });
|
|
10385
|
+
return {
|
|
10386
|
+
built: true,
|
|
10387
|
+
outdir,
|
|
10388
|
+
metadataFile,
|
|
10389
|
+
packages,
|
|
10390
|
+
actionPlugins,
|
|
10391
|
+
fileCount: metadata.fileCount,
|
|
10392
|
+
totalBytes: metadata.totalBytes,
|
|
10393
|
+
elapsedMs: Date.now() - startedAt,
|
|
10394
|
+
reasons: []
|
|
10395
|
+
};
|
|
10396
|
+
} catch (error) {
|
|
10397
|
+
fs30.rmSync(serverOutputRoot, { recursive: true, force: true });
|
|
10398
|
+
return {
|
|
10399
|
+
built: false,
|
|
10400
|
+
elapsedMs: Date.now() - startedAt,
|
|
10401
|
+
reasons: [error instanceof Error ? error.message : String(error)]
|
|
10402
|
+
};
|
|
10403
|
+
}
|
|
10404
|
+
}
|
|
10405
|
+
|
|
10406
|
+
// src/commands/build/app-runtime-manifest.handler.ts
|
|
10407
|
+
import fs32 from "fs";
|
|
10408
|
+
import path29 from "path";
|
|
10409
|
+
|
|
10410
|
+
// src/client-dependency-graph.ts
|
|
10411
|
+
import crypto2 from "crypto";
|
|
10412
|
+
import fs31 from "fs";
|
|
10413
|
+
import path28 from "path";
|
|
10414
|
+
import { builtinModules as builtinModules2 } from "module";
|
|
10415
|
+
import { Node as Node11, Project as Project4, SyntaxKind as SyntaxKind7 } from "ts-morph";
|
|
10416
|
+
var BUILTIN_MODULES = /* @__PURE__ */ new Set([
|
|
10417
|
+
...builtinModules2,
|
|
10418
|
+
...builtinModules2.map((name) => `node:${name}`)
|
|
10419
|
+
]);
|
|
10420
|
+
var SOURCE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
10421
|
+
var STYLE_EXTENSIONS = [
|
|
10422
|
+
".css",
|
|
10423
|
+
".less",
|
|
10424
|
+
".sass",
|
|
10425
|
+
".scss",
|
|
10426
|
+
".styl",
|
|
10427
|
+
".stylus"
|
|
10428
|
+
];
|
|
10429
|
+
function packageNameFromSpecifier(specifier) {
|
|
10430
|
+
if (!specifier || specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("\0") || specifier.includes("://") || BUILTIN_MODULES.has(specifier)) {
|
|
10431
|
+
return void 0;
|
|
10432
|
+
}
|
|
10433
|
+
const parts = specifier.split("/");
|
|
10434
|
+
return specifier.startsWith("@") ? parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0 : parts[0];
|
|
10435
|
+
}
|
|
10436
|
+
function isStyleSpecifier(specifier) {
|
|
10437
|
+
return STYLE_EXTENSIONS.some(
|
|
10438
|
+
(extension) => new RegExp(`\\${extension}(?:$|\\?)`, "i").test(specifier)
|
|
10439
|
+
);
|
|
10440
|
+
}
|
|
10441
|
+
function resolveLocalFile(specifier, importer, projectRoot, clientRoot) {
|
|
10442
|
+
let candidate;
|
|
10443
|
+
if (specifier.startsWith("@/")) {
|
|
10444
|
+
candidate = path28.join(clientRoot, "src", specifier.slice(2));
|
|
10445
|
+
} else if (specifier.startsWith("@client/")) {
|
|
10446
|
+
candidate = path28.join(clientRoot, specifier.slice("@client/".length));
|
|
10447
|
+
} else if (specifier.startsWith("@shared/")) {
|
|
10448
|
+
candidate = path28.join(
|
|
10449
|
+
projectRoot,
|
|
10450
|
+
"shared",
|
|
10451
|
+
specifier.slice("@shared/".length)
|
|
10452
|
+
);
|
|
10453
|
+
} else if (specifier.startsWith(".") || path28.isAbsolute(specifier)) {
|
|
10454
|
+
candidate = path28.resolve(path28.dirname(importer), specifier);
|
|
10455
|
+
}
|
|
10456
|
+
if (!candidate) return void 0;
|
|
10457
|
+
const projectRelative = path28.relative(projectRoot, path28.resolve(candidate));
|
|
10458
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${path28.sep}`) || path28.isAbsolute(projectRelative)) {
|
|
10459
|
+
throw new Error(
|
|
10460
|
+
`MIAODA_CLIENT_SOURCE_PATH_ESCAPE: ${specifier} from ${path28.relative(
|
|
10461
|
+
projectRoot,
|
|
10462
|
+
importer
|
|
10463
|
+
)}`
|
|
10464
|
+
);
|
|
10465
|
+
}
|
|
10466
|
+
const extensions = [...SOURCE_EXTENSIONS, ...STYLE_EXTENSIONS];
|
|
10467
|
+
const candidates = [
|
|
10468
|
+
candidate,
|
|
10469
|
+
...extensions.map((extension) => `${candidate}${extension}`),
|
|
10470
|
+
...extensions.map((extension) => path28.join(candidate, `index${extension}`))
|
|
10471
|
+
];
|
|
10472
|
+
const resolvedFile = candidates.find((file) => {
|
|
10473
|
+
try {
|
|
10474
|
+
return fs31.statSync(file).isFile();
|
|
10475
|
+
} catch {
|
|
10476
|
+
return false;
|
|
10477
|
+
}
|
|
10478
|
+
});
|
|
10479
|
+
if (!resolvedFile) return void 0;
|
|
10480
|
+
const realProjectRoot = fs31.realpathSync(projectRoot);
|
|
10481
|
+
const realFile = fs31.realpathSync(resolvedFile);
|
|
10482
|
+
const relative = path28.relative(realProjectRoot, realFile);
|
|
10483
|
+
if (relative === ".." || relative.startsWith(`..${path28.sep}`) || path28.isAbsolute(relative)) {
|
|
10484
|
+
throw new Error(`MIAODA_CLIENT_SOURCE_SYMLINK_ESCAPE: ${resolvedFile}`);
|
|
10485
|
+
}
|
|
10486
|
+
return resolvedFile;
|
|
10487
|
+
}
|
|
10488
|
+
function discoverClientSpecifiers(projectRoot, scanAllSourceFiles = false) {
|
|
10489
|
+
const clientRoot = fs31.existsSync(path28.join(projectRoot, "client")) ? path28.join(projectRoot, "client") : projectRoot;
|
|
10490
|
+
if (!fs31.existsSync(path28.join(clientRoot, "src"))) {
|
|
10491
|
+
return { specifiers: [], optimizeDependencies: [] };
|
|
10492
|
+
}
|
|
10493
|
+
const project = new Project4({
|
|
10494
|
+
skipAddingFilesFromTsConfig: true,
|
|
10495
|
+
compilerOptions: { allowJs: true, jsx: 2 }
|
|
10496
|
+
});
|
|
10497
|
+
const specifiers = /* @__PURE__ */ new Set();
|
|
10498
|
+
const optimizeDependencies = /* @__PURE__ */ new Set();
|
|
10499
|
+
const pending = SOURCE_EXTENSIONS.map(
|
|
10500
|
+
(extension) => path28.join(clientRoot, "src", `index${extension}`)
|
|
10501
|
+
).filter((file) => fs31.existsSync(file));
|
|
10502
|
+
if (scanAllSourceFiles) {
|
|
10503
|
+
const visit = (directory) => {
|
|
10504
|
+
for (const entry of fs31.readdirSync(directory, { withFileTypes: true })) {
|
|
10505
|
+
const file = path28.join(directory, entry.name);
|
|
10506
|
+
if (entry.isSymbolicLink()) {
|
|
10507
|
+
throw new Error(`MIAODA_CLIENT_SOURCE_SYMLINK_REJECTED: ${file}`);
|
|
10508
|
+
}
|
|
10509
|
+
if (entry.isDirectory()) visit(file);
|
|
10510
|
+
else if (entry.isFile() && [...SOURCE_EXTENSIONS, ...STYLE_EXTENSIONS].includes(
|
|
10511
|
+
path28.extname(file)
|
|
10512
|
+
)) {
|
|
10513
|
+
pending.push(file);
|
|
10514
|
+
}
|
|
10515
|
+
}
|
|
10516
|
+
};
|
|
10517
|
+
visit(path28.join(clientRoot, "src"));
|
|
10518
|
+
}
|
|
10519
|
+
const visited = /* @__PURE__ */ new Set();
|
|
10520
|
+
const addBare = (specifier, optimize) => {
|
|
10521
|
+
if (!packageNameFromSpecifier(specifier)) return;
|
|
10522
|
+
specifiers.add(specifier);
|
|
10523
|
+
if (optimize) optimizeDependencies.add(specifier);
|
|
10524
|
+
};
|
|
10525
|
+
const traverse = (specifier, importer, optimize = true) => {
|
|
10526
|
+
const dependency = resolveLocalFile(
|
|
10527
|
+
specifier,
|
|
10528
|
+
importer,
|
|
10529
|
+
projectRoot,
|
|
10530
|
+
clientRoot
|
|
10531
|
+
);
|
|
10532
|
+
if (dependency) pending.push(dependency);
|
|
10533
|
+
else addBare(specifier, optimize && !isStyleSpecifier(specifier));
|
|
10534
|
+
};
|
|
10535
|
+
while (pending.length > 0) {
|
|
10536
|
+
const sourcePath = path28.resolve(pending.pop());
|
|
10537
|
+
if (visited.has(sourcePath)) continue;
|
|
10538
|
+
visited.add(sourcePath);
|
|
10539
|
+
if (STYLE_EXTENSIONS.includes(path28.extname(sourcePath))) {
|
|
10540
|
+
const css = fs31.readFileSync(sourcePath, "utf8");
|
|
10541
|
+
for (const match of css.matchAll(
|
|
10542
|
+
/@(import|plugin)\s+(?:url\(\s*)?["']([^"']+)["']/g
|
|
10543
|
+
)) {
|
|
10544
|
+
traverse(match[2], sourcePath, false);
|
|
10545
|
+
}
|
|
10546
|
+
for (const match of css.matchAll(/@source\s+["']([^"']+)["']/g)) {
|
|
10547
|
+
const marker = /(?:^|[\\/])node_modules[\\/]((?:@[^\\/]+[\\/])?[^\\/*?{}]+)/.exec(
|
|
10548
|
+
match[1]
|
|
10549
|
+
);
|
|
10550
|
+
if (marker) addBare(marker[1].replace(/\\/g, "/"), false);
|
|
10551
|
+
}
|
|
10552
|
+
continue;
|
|
10553
|
+
}
|
|
10554
|
+
const sourceFile = project.addSourceFileAtPath(sourcePath);
|
|
10555
|
+
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
10556
|
+
if (declaration.isTypeOnly()) continue;
|
|
10557
|
+
const namedImports = declaration.getNamedImports();
|
|
10558
|
+
const hasRuntimeBinding = Boolean(declaration.getDefaultImport()) || Boolean(declaration.getNamespaceImport()) || namedImports.length === 0 || namedImports.some((specifier) => !specifier.isTypeOnly());
|
|
10559
|
+
if (hasRuntimeBinding) {
|
|
10560
|
+
traverse(declaration.getModuleSpecifierValue(), sourcePath);
|
|
10561
|
+
}
|
|
10562
|
+
}
|
|
10563
|
+
for (const declaration of sourceFile.getExportDeclarations()) {
|
|
10564
|
+
if (declaration.isTypeOnly()) continue;
|
|
10565
|
+
const namedExports = declaration.getNamedExports();
|
|
10566
|
+
const specifier = declaration.getModuleSpecifierValue();
|
|
10567
|
+
if (specifier && (namedExports.length === 0 || namedExports.some((namedExport) => !namedExport.isTypeOnly()))) {
|
|
10568
|
+
traverse(specifier, sourcePath);
|
|
10569
|
+
}
|
|
10570
|
+
}
|
|
10571
|
+
for (const call of sourceFile.getDescendantsOfKind(
|
|
10572
|
+
SyntaxKind7.CallExpression
|
|
10573
|
+
)) {
|
|
10574
|
+
const expression = call.getExpression();
|
|
10575
|
+
const isDynamicImport = expression.getKind() === SyntaxKind7.ImportKeyword;
|
|
10576
|
+
const isRequire = Node11.isIdentifier(expression) && expression.getText() === "require";
|
|
10577
|
+
if (!isDynamicImport && !isRequire) continue;
|
|
10578
|
+
const argument = call.getArguments()[0];
|
|
10579
|
+
if (!argument || !Node11.isStringLiteral(argument)) {
|
|
10580
|
+
throw new Error(
|
|
10581
|
+
`MIAODA_CLIENT_DYNAMIC_DEPENDENCY_UNSUPPORTED: ${path28.relative(
|
|
10582
|
+
projectRoot,
|
|
10583
|
+
sourcePath
|
|
10584
|
+
)}:${call.getStartLineNumber()}`
|
|
10585
|
+
);
|
|
10586
|
+
}
|
|
10587
|
+
traverse(argument.getLiteralValue(), sourcePath);
|
|
10588
|
+
}
|
|
10589
|
+
}
|
|
10590
|
+
return {
|
|
10591
|
+
specifiers: [...specifiers].sort(),
|
|
10592
|
+
optimizeDependencies: [...optimizeDependencies].sort()
|
|
10593
|
+
};
|
|
10594
|
+
}
|
|
10595
|
+
function parentPackagePath(packagePath) {
|
|
10596
|
+
const nestedMarker = packagePath.lastIndexOf("/node_modules/");
|
|
10597
|
+
if (nestedMarker >= 0) return packagePath.slice(0, nestedMarker);
|
|
10598
|
+
return packagePath.startsWith("node_modules/") ? "" : void 0;
|
|
10599
|
+
}
|
|
10600
|
+
function resolveLockedPackagePath(packages, fromPackagePath, packageName) {
|
|
10601
|
+
let current = fromPackagePath;
|
|
10602
|
+
while (current !== void 0) {
|
|
10603
|
+
const candidate = current ? `${current}/node_modules/${packageName}` : `node_modules/${packageName}`;
|
|
10604
|
+
if (packages[candidate]?.version) return candidate;
|
|
10605
|
+
current = current ? parentPackagePath(current) : void 0;
|
|
10606
|
+
}
|
|
10607
|
+
return void 0;
|
|
10608
|
+
}
|
|
10609
|
+
function canonicalize(value) {
|
|
10610
|
+
return JSON.stringify(value);
|
|
10611
|
+
}
|
|
10612
|
+
function clientConfigFiles(projectRoot) {
|
|
10613
|
+
const fixedNames = [
|
|
10614
|
+
"vite.config.ts",
|
|
10615
|
+
"vite.config.mts",
|
|
10616
|
+
"vite.config.js",
|
|
10617
|
+
"vite.config.mjs",
|
|
10618
|
+
"vite.config.cjs",
|
|
10619
|
+
"postcss.config.js",
|
|
10620
|
+
"postcss.config.cjs",
|
|
10621
|
+
"postcss.config.mjs",
|
|
10622
|
+
"tailwind.config.ts",
|
|
10623
|
+
"tailwind.config.js",
|
|
10624
|
+
"tailwind.config.cjs",
|
|
10625
|
+
"tailwind.config.mjs",
|
|
10626
|
+
"tsconfig.json",
|
|
10627
|
+
"tsconfig.app.json",
|
|
10628
|
+
"tsconfig.node.json",
|
|
10629
|
+
".env",
|
|
10630
|
+
".env.development",
|
|
10631
|
+
".env.development.local"
|
|
10632
|
+
];
|
|
10633
|
+
const pending = fixedNames.map((name) => path28.join(projectRoot, name));
|
|
10634
|
+
for (const patchRootName of ["patches", ".yarn/patches"]) {
|
|
10635
|
+
const patchRoot = path28.join(projectRoot, patchRootName);
|
|
10636
|
+
if (!fs31.existsSync(patchRoot)) continue;
|
|
10637
|
+
const visit = (directory) => {
|
|
10638
|
+
for (const entry of fs31.readdirSync(directory, { withFileTypes: true })) {
|
|
10639
|
+
const file = path28.join(directory, entry.name);
|
|
10640
|
+
if (entry.isSymbolicLink()) {
|
|
10641
|
+
throw new Error(`MIAODA_CLIENT_CONFIG_SYMLINK_REJECTED: ${file}`);
|
|
10642
|
+
}
|
|
10643
|
+
if (entry.isDirectory()) visit(file);
|
|
10644
|
+
else if (entry.isFile()) pending.push(file);
|
|
10645
|
+
}
|
|
10646
|
+
};
|
|
10647
|
+
visit(patchRoot);
|
|
10648
|
+
}
|
|
10649
|
+
const visited = /* @__PURE__ */ new Set();
|
|
10650
|
+
const result = [];
|
|
10651
|
+
const resolveRelativeConfig = (specifier, importer) => {
|
|
10652
|
+
if (!specifier.startsWith(".")) return void 0;
|
|
10653
|
+
const candidate = path28.resolve(path28.dirname(importer), specifier);
|
|
10654
|
+
const candidates = [
|
|
10655
|
+
candidate,
|
|
10656
|
+
...[...SOURCE_EXTENSIONS, ".json"].map(
|
|
10657
|
+
(extension) => `${candidate}${extension}`
|
|
10658
|
+
),
|
|
10659
|
+
...[...SOURCE_EXTENSIONS, ".json"].map(
|
|
10660
|
+
(extension) => path28.join(candidate, `index${extension}`)
|
|
10661
|
+
)
|
|
10662
|
+
];
|
|
10663
|
+
return candidates.find((file) => {
|
|
10664
|
+
const relative = path28.relative(projectRoot, file);
|
|
10665
|
+
return relative !== ".." && !relative.startsWith(`..${path28.sep}`) && !path28.isAbsolute(relative) && fs31.existsSync(file) && fs31.statSync(file).isFile();
|
|
10666
|
+
});
|
|
10667
|
+
};
|
|
10668
|
+
while (pending.length > 0) {
|
|
10669
|
+
const file = path28.resolve(pending.pop());
|
|
10670
|
+
if (visited.has(file) || !fs31.existsSync(file) || !fs31.statSync(file).isFile()) {
|
|
10671
|
+
continue;
|
|
10672
|
+
}
|
|
10673
|
+
visited.add(file);
|
|
10674
|
+
const content = fs31.readFileSync(file);
|
|
10675
|
+
result.push({
|
|
10676
|
+
path: path28.relative(projectRoot, file),
|
|
10677
|
+
sha256: crypto2.createHash("sha256").update(content).digest("hex")
|
|
10678
|
+
});
|
|
10679
|
+
if (SOURCE_EXTENSIONS.includes(path28.extname(file))) {
|
|
10680
|
+
const source = content.toString("utf8");
|
|
10681
|
+
for (const match of source.matchAll(
|
|
10682
|
+
/(?:from\s*|import\s*\(|require\s*\()\s*["']([^"']+)["']/g
|
|
10683
|
+
)) {
|
|
10684
|
+
const dependency = resolveRelativeConfig(match[1], file);
|
|
10685
|
+
if (dependency) pending.push(dependency);
|
|
10686
|
+
}
|
|
10687
|
+
} else if (path28.extname(file) === ".json") {
|
|
10688
|
+
try {
|
|
10689
|
+
const json = JSON.parse(content.toString("utf8"));
|
|
10690
|
+
for (const specifier of [
|
|
10691
|
+
json.extends,
|
|
10692
|
+
...(json.references ?? []).map((reference) => reference.path)
|
|
10693
|
+
]) {
|
|
10694
|
+
if (!specifier) continue;
|
|
10695
|
+
const dependency = resolveRelativeConfig(specifier, file);
|
|
10696
|
+
if (dependency) pending.push(dependency);
|
|
10697
|
+
}
|
|
10698
|
+
} catch {
|
|
10699
|
+
}
|
|
10700
|
+
}
|
|
10701
|
+
}
|
|
10702
|
+
return result.sort((left, right) => left.path.localeCompare(right.path));
|
|
10703
|
+
}
|
|
10704
|
+
function clientConfigEnvironment() {
|
|
10705
|
+
const names = [
|
|
10706
|
+
"APP_FLAGS",
|
|
10707
|
+
"ASSETS_CDN_PATH",
|
|
10708
|
+
"BUILD_TOOL",
|
|
10709
|
+
"CLIENT_BASE_PATH",
|
|
10710
|
+
"DISABLE_INSPECTOR",
|
|
10711
|
+
"FORCE_FRAMEWORK_BUILD_LOOSE_MODE",
|
|
10712
|
+
"FORCE_FRAMEWORK_DOMAIN_MAIN",
|
|
10713
|
+
"FORCE_FRAMEWORK_ENVIRONMENT",
|
|
10714
|
+
"MIAODA_APP_ARCH_TYPE",
|
|
10715
|
+
"MIAODA_APP_SOURCE",
|
|
10716
|
+
"MIAODA_APP_TYPE",
|
|
10717
|
+
"MIAODA_FONTS_MIRROR_OFF",
|
|
10718
|
+
"NEED_ROUTES",
|
|
10719
|
+
"STATIC_ASSETS_BASE_URL",
|
|
10720
|
+
"__API_ROUTE_DEFINITIONS__",
|
|
10721
|
+
"__PAGE_ROUTE_DEFINITIONS__"
|
|
10722
|
+
];
|
|
10723
|
+
return Object.fromEntries(
|
|
10724
|
+
names.map((name) => [
|
|
10725
|
+
name,
|
|
10726
|
+
crypto2.createHash("sha256").update(process.env[name] ?? "").digest("hex")
|
|
10727
|
+
])
|
|
10728
|
+
);
|
|
10729
|
+
}
|
|
10730
|
+
function installedDependencyLockFile(projectRoot) {
|
|
10731
|
+
const hiddenLock = path28.join(
|
|
10732
|
+
projectRoot,
|
|
10733
|
+
"node_modules",
|
|
10734
|
+
".package-lock.json"
|
|
10735
|
+
);
|
|
10736
|
+
if (fs31.existsSync(hiddenLock)) {
|
|
10737
|
+
if (fs31.lstatSync(hiddenLock).isSymbolicLink() || !fs31.statSync(hiddenLock).isFile()) {
|
|
10738
|
+
throw new Error("MIAODA_NPM_HIDDEN_PACKAGE_LOCK_INVALID");
|
|
10739
|
+
}
|
|
10740
|
+
return hiddenLock;
|
|
10741
|
+
}
|
|
10742
|
+
return path28.join(projectRoot, "package-lock.json");
|
|
10743
|
+
}
|
|
10744
|
+
function buildClientDependencyGraph(options) {
|
|
10745
|
+
const projectRoot = path28.resolve(options.projectRoot);
|
|
10746
|
+
const packageLockFile = installedDependencyLockFile(projectRoot);
|
|
10747
|
+
const lock = JSON.parse(
|
|
10748
|
+
fs31.readFileSync(packageLockFile, "utf8")
|
|
10749
|
+
);
|
|
10750
|
+
if (!lock.packages || (lock.lockfileVersion ?? 0) < 2) {
|
|
10751
|
+
throw new Error("MIAODA_NPM_PACKAGE_LOCK_V2_REQUIRED");
|
|
10752
|
+
}
|
|
10753
|
+
const discovery = discoverClientSpecifiers(
|
|
10754
|
+
projectRoot,
|
|
10755
|
+
options.includeAllProductionDependencies === true
|
|
10756
|
+
);
|
|
10757
|
+
if (options.includeAllProductionDependencies) {
|
|
10758
|
+
const packageJson = JSON.parse(
|
|
10759
|
+
fs31.readFileSync(path28.join(projectRoot, "package.json"), "utf8")
|
|
10760
|
+
);
|
|
10761
|
+
for (const specifier of Object.keys(packageJson.dependencies ?? {})) {
|
|
10762
|
+
if (!lock.packages[`node_modules/${specifier}`]?.version) continue;
|
|
10763
|
+
if (!discovery.specifiers.includes(specifier)) {
|
|
10764
|
+
discovery.specifiers.push(specifier);
|
|
10765
|
+
}
|
|
10766
|
+
}
|
|
10767
|
+
}
|
|
10768
|
+
const implicitSpecifiers = [
|
|
10769
|
+
"react",
|
|
10770
|
+
"react-dom",
|
|
10771
|
+
"react/jsx-runtime",
|
|
10772
|
+
"react/jsx-dev-runtime",
|
|
10773
|
+
"clsx",
|
|
10774
|
+
"echarts",
|
|
10775
|
+
"echarts-for-react",
|
|
10776
|
+
"@lark-apaas/client-toolkit/runtime",
|
|
10777
|
+
...process.env.DISABLE_INSPECTOR === "true" ? [] : ["@lark-apaas/miaoda-inspector"]
|
|
10778
|
+
];
|
|
10779
|
+
for (const specifier of implicitSpecifiers) {
|
|
10780
|
+
const packageName = packageNameFromSpecifier(specifier);
|
|
10781
|
+
if (lock.packages[`node_modules/${packageName}`]?.version && !discovery.specifiers.includes(specifier)) {
|
|
10782
|
+
discovery.specifiers.push(specifier);
|
|
10783
|
+
discovery.optimizeDependencies.push(specifier);
|
|
10784
|
+
}
|
|
10785
|
+
}
|
|
10786
|
+
discovery.specifiers.sort();
|
|
10787
|
+
discovery.optimizeDependencies.sort();
|
|
10788
|
+
const entries = discovery.specifiers.map((specifier) => {
|
|
10789
|
+
const packageName = packageNameFromSpecifier(specifier);
|
|
10790
|
+
const packagePath = resolveLockedPackagePath(
|
|
10791
|
+
lock.packages,
|
|
10792
|
+
"",
|
|
10793
|
+
packageName
|
|
10794
|
+
);
|
|
10795
|
+
if (!packagePath) {
|
|
10796
|
+
throw new Error(`MIAODA_CLIENT_DEPENDENCY_LOCK_MISSING: ${specifier}`);
|
|
10797
|
+
}
|
|
10798
|
+
return { specifier, packagePath };
|
|
10799
|
+
});
|
|
10800
|
+
const pending = [...new Set(entries.map((entry) => entry.packagePath))];
|
|
10801
|
+
const graphPackages = /* @__PURE__ */ new Map();
|
|
10802
|
+
while (pending.length > 0) {
|
|
10803
|
+
const packagePath = pending.pop();
|
|
10804
|
+
if (graphPackages.has(packagePath)) continue;
|
|
10805
|
+
const lockedPackage = lock.packages[packagePath];
|
|
10806
|
+
if (!lockedPackage?.version) {
|
|
10807
|
+
throw new Error(`MIAODA_CLIENT_DEPENDENCY_LOCK_MISSING: ${packagePath}`);
|
|
10808
|
+
}
|
|
10809
|
+
const edges = {};
|
|
10810
|
+
const addEdge = (name, required) => {
|
|
10811
|
+
const resolvedPath = resolveLockedPackagePath(
|
|
10812
|
+
lock.packages,
|
|
10813
|
+
packagePath,
|
|
10814
|
+
name
|
|
10815
|
+
);
|
|
10816
|
+
if (!resolvedPath) {
|
|
10817
|
+
if (required) {
|
|
10818
|
+
throw new Error(
|
|
10819
|
+
`MIAODA_CLIENT_DEPENDENCY_EDGE_MISSING: ${packagePath} -> ${name}`
|
|
10820
|
+
);
|
|
10821
|
+
}
|
|
10822
|
+
return;
|
|
10823
|
+
}
|
|
10824
|
+
edges[name] = resolvedPath;
|
|
10825
|
+
pending.push(resolvedPath);
|
|
10826
|
+
};
|
|
10827
|
+
for (const name of Object.keys(lockedPackage.dependencies ?? {}).sort()) {
|
|
10828
|
+
addEdge(name, true);
|
|
10829
|
+
}
|
|
10830
|
+
for (const name of Object.keys(
|
|
10831
|
+
lockedPackage.optionalDependencies ?? {}
|
|
10832
|
+
).sort()) {
|
|
10833
|
+
addEdge(name, false);
|
|
10834
|
+
}
|
|
10835
|
+
for (const name of Object.keys(
|
|
10836
|
+
lockedPackage.peerDependencies ?? {}
|
|
10837
|
+
).sort()) {
|
|
10838
|
+
addEdge(
|
|
10839
|
+
name,
|
|
10840
|
+
lockedPackage.peerDependenciesMeta?.[name]?.optional !== true
|
|
10841
|
+
);
|
|
10842
|
+
}
|
|
10843
|
+
graphPackages.set(packagePath, {
|
|
10844
|
+
path: packagePath,
|
|
10845
|
+
version: lockedPackage.version,
|
|
10846
|
+
integrity: lockedPackage.integrity ?? null,
|
|
10847
|
+
edges: Object.fromEntries(
|
|
10848
|
+
Object.entries(edges).sort(
|
|
10849
|
+
([left], [right]) => left.localeCompare(right)
|
|
10850
|
+
)
|
|
10851
|
+
)
|
|
10852
|
+
});
|
|
10853
|
+
}
|
|
10854
|
+
const graph = {
|
|
10855
|
+
schemaVersion: 1,
|
|
10856
|
+
algorithm: "npm-installed-client-closure-v2",
|
|
10857
|
+
runtimeAbiHash: options.runtimeAbiHash,
|
|
10858
|
+
resolveConditions: ["browser", "development", "module", "import"],
|
|
10859
|
+
configFiles: clientConfigFiles(projectRoot),
|
|
10860
|
+
configEnvironment: clientConfigEnvironment(),
|
|
10861
|
+
entries,
|
|
10862
|
+
packages: [...graphPackages.values()].sort(
|
|
10863
|
+
(left, right) => left.path.localeCompare(right.path)
|
|
10864
|
+
)
|
|
10865
|
+
};
|
|
10866
|
+
return {
|
|
10867
|
+
graph,
|
|
10868
|
+
hash: crypto2.createHash("sha256").update(canonicalize(graph)).digest("hex"),
|
|
10869
|
+
optimizeDependencies: discovery.optimizeDependencies
|
|
10870
|
+
};
|
|
10871
|
+
}
|
|
10872
|
+
|
|
10873
|
+
// src/commands/build/app-runtime-manifest.handler.ts
|
|
10874
|
+
var VITE_PRESETS = [
|
|
10875
|
+
"@lark-apaas/coding-preset-vite-react",
|
|
10876
|
+
"@lark-apaas/coding-vite-preset",
|
|
10877
|
+
"@lark-apaas/fullstack-vite-preset"
|
|
10878
|
+
];
|
|
10879
|
+
function detectApplicationRuntime(projectRoot, packageJson) {
|
|
10880
|
+
const features = packageJson?.mclaw?.features;
|
|
10881
|
+
const declaredPackages = {
|
|
10882
|
+
...packageJson?.dependencies ?? {},
|
|
10883
|
+
...packageJson?.devDependencies ?? {}
|
|
10884
|
+
};
|
|
10885
|
+
const usesCodingVitePreset = VITE_PRESETS.slice(0, 2).some(
|
|
10886
|
+
(name) => declaredPackages[name] !== void 0
|
|
10887
|
+
);
|
|
10888
|
+
const hasServerRuntime = packageJson?.scripts?.["dev:server"] !== void 0 || declaredPackages["@nestjs/core"] !== void 0 || fs32.existsSync(path29.join(projectRoot, "server", "main.ts")) || fs32.existsSync(path29.join(projectRoot, "server", "src", "main.ts"));
|
|
10889
|
+
const hasClientOnlyMetadata = Array.isArray(features) && features.includes("client") && !features.includes("server");
|
|
10890
|
+
const applicationKind = !hasServerRuntime && (hasClientOnlyMetadata || usesCodingVitePreset) ? "frontend-only" : "fullstack";
|
|
10891
|
+
const vitePreset = VITE_PRESETS.find((name) => declaredPackages[name] !== void 0) ?? "@lark-apaas/fullstack-vite-preset";
|
|
10892
|
+
const entryCandidates = [
|
|
10893
|
+
"client/src/index.tsx",
|
|
10894
|
+
"client/src/main.tsx",
|
|
10895
|
+
"src/index.tsx",
|
|
10896
|
+
"src/main.tsx"
|
|
10897
|
+
];
|
|
10898
|
+
const clientEntry = entryCandidates.find(
|
|
10899
|
+
(relativePath) => fs32.existsSync(path29.join(projectRoot, relativePath))
|
|
10900
|
+
);
|
|
10901
|
+
if (!clientEntry) {
|
|
10902
|
+
throw new Error("client entry missing");
|
|
10903
|
+
}
|
|
10904
|
+
return {
|
|
10905
|
+
applicationKind,
|
|
10906
|
+
vitePreset,
|
|
10907
|
+
clientRoot: clientEntry.startsWith("client/") ? "client" : ".",
|
|
10908
|
+
clientEntry
|
|
10909
|
+
};
|
|
10910
|
+
}
|
|
10911
|
+
function buildAppRuntimeManifest(options) {
|
|
10912
|
+
const projectRoot = path29.resolve(options.projectRoot);
|
|
10913
|
+
const outfile = path29.resolve(
|
|
10914
|
+
projectRoot,
|
|
10915
|
+
options.outfile ?? ".miaoda-cache/app-runtime.json"
|
|
10916
|
+
);
|
|
10917
|
+
const runtimeManifestFile = path29.isAbsolute(options.runtimeManifestFile) ? options.runtimeManifestFile : path29.resolve(projectRoot, options.runtimeManifestFile);
|
|
10918
|
+
const requiredFiles = [
|
|
10919
|
+
path29.join(projectRoot, "package.json"),
|
|
10920
|
+
path29.join(projectRoot, "package-lock.json"),
|
|
10921
|
+
runtimeManifestFile
|
|
10922
|
+
];
|
|
10923
|
+
fs32.rmSync(outfile, { force: true });
|
|
10924
|
+
const missing = requiredFiles.filter((file) => !fs32.existsSync(file));
|
|
10925
|
+
if (missing.length > 0) {
|
|
10926
|
+
return {
|
|
10927
|
+
built: false,
|
|
10928
|
+
reasons: missing.map((file) => `input missing: ${file}`)
|
|
10929
|
+
};
|
|
10930
|
+
}
|
|
10931
|
+
try {
|
|
10932
|
+
const packageJson = JSON.parse(
|
|
10933
|
+
fs32.readFileSync(path29.join(projectRoot, "package.json"), "utf8")
|
|
10934
|
+
);
|
|
10935
|
+
const runtime = JSON.parse(
|
|
10936
|
+
fs32.readFileSync(runtimeManifestFile, "utf8")
|
|
10937
|
+
);
|
|
10938
|
+
if (runtime.schemaVersion !== 1 || !runtime.runtimeAbiHash) {
|
|
10939
|
+
return {
|
|
10940
|
+
built: false,
|
|
10941
|
+
reasons: ["unsupported platform runtime manifest"]
|
|
10942
|
+
};
|
|
10943
|
+
}
|
|
10944
|
+
const applicationRuntime = detectApplicationRuntime(
|
|
10945
|
+
projectRoot,
|
|
10946
|
+
packageJson
|
|
10947
|
+
);
|
|
10948
|
+
const client = buildClientDependencyGraph({
|
|
10949
|
+
projectRoot,
|
|
10950
|
+
runtimeAbiHash: runtime.runtimeAbiHash,
|
|
10951
|
+
includeAllProductionDependencies: applicationRuntime.applicationKind === "frontend-only"
|
|
10952
|
+
});
|
|
10953
|
+
const manifest = {
|
|
10954
|
+
schemaVersion: 1,
|
|
10955
|
+
runtimeAbiHash: runtime.runtimeAbiHash,
|
|
10956
|
+
...applicationRuntime,
|
|
10957
|
+
clientDependencyGraphHash: client.hash,
|
|
10958
|
+
clientDependencyGraph: client.graph,
|
|
10959
|
+
optimizeDependencies: client.optimizeDependencies
|
|
10960
|
+
};
|
|
10961
|
+
fs32.mkdirSync(path29.dirname(outfile), { recursive: true });
|
|
10962
|
+
const temporaryFile = `${outfile}.${process.pid}.${Date.now()}.tmp`;
|
|
10963
|
+
fs32.writeFileSync(temporaryFile, `${JSON.stringify(manifest, null, 2)}
|
|
10964
|
+
`);
|
|
10965
|
+
fs32.renameSync(temporaryFile, outfile);
|
|
10966
|
+
return {
|
|
10967
|
+
built: true,
|
|
10968
|
+
outfile,
|
|
10969
|
+
runtimeAbiHash: runtime.runtimeAbiHash,
|
|
10970
|
+
...applicationRuntime,
|
|
10971
|
+
clientDependencyGraphHash: client.hash,
|
|
10972
|
+
clientDependencyGraph: client.graph,
|
|
10973
|
+
optimizeDependencies: client.optimizeDependencies,
|
|
10974
|
+
reasons: []
|
|
10975
|
+
};
|
|
10976
|
+
} catch (error) {
|
|
10977
|
+
fs32.rmSync(outfile, { force: true });
|
|
10978
|
+
return {
|
|
10979
|
+
built: false,
|
|
10980
|
+
reasons: [error instanceof Error ? error.message : String(error)]
|
|
10981
|
+
};
|
|
10982
|
+
}
|
|
10983
|
+
}
|
|
10984
|
+
|
|
10985
|
+
// src/commands/build/cache-generation.handler.ts
|
|
10986
|
+
import crypto3 from "crypto";
|
|
10987
|
+
import fs33 from "fs";
|
|
10988
|
+
import path30 from "path";
|
|
10989
|
+
function sha2562(file) {
|
|
10990
|
+
return crypto3.createHash("sha256").update(fs33.readFileSync(file)).digest("hex");
|
|
10991
|
+
}
|
|
10992
|
+
function listRegularFiles(root) {
|
|
10993
|
+
const files = [];
|
|
10994
|
+
const visit = (directory) => {
|
|
10995
|
+
for (const entry of fs33.readdirSync(directory, { withFileTypes: true })) {
|
|
10996
|
+
const file = path30.join(directory, entry.name);
|
|
10997
|
+
if (entry.isSymbolicLink()) {
|
|
10998
|
+
throw new Error(`vite cache symlink is not supported: ${file}`);
|
|
10999
|
+
}
|
|
11000
|
+
if (entry.isDirectory()) {
|
|
11001
|
+
visit(file);
|
|
11002
|
+
} else if (entry.isFile()) {
|
|
11003
|
+
files.push(file);
|
|
11004
|
+
}
|
|
11005
|
+
}
|
|
11006
|
+
};
|
|
11007
|
+
visit(root);
|
|
11008
|
+
return files.sort();
|
|
11009
|
+
}
|
|
11010
|
+
var WORKSPACE_SOURCE_ROOTS = ["client", "server", "shared", "src"];
|
|
11011
|
+
var WORKSPACE_SOURCE_FILES = [
|
|
11012
|
+
".env",
|
|
11013
|
+
".env.development",
|
|
11014
|
+
".env.development.local",
|
|
11015
|
+
"drizzle.config.ts",
|
|
11016
|
+
"nest-cli.json",
|
|
11017
|
+
"postcss.config.js",
|
|
11018
|
+
"postcss.config.cjs",
|
|
11019
|
+
"postcss.config.mjs",
|
|
11020
|
+
"tailwind.config.ts",
|
|
11021
|
+
"tailwind.config.js",
|
|
11022
|
+
"tailwind.config.cjs",
|
|
11023
|
+
"tailwind.config.mjs",
|
|
11024
|
+
"tsconfig.json",
|
|
11025
|
+
"tsconfig.app.json",
|
|
11026
|
+
"tsconfig.node.json",
|
|
11027
|
+
"vite.config.ts",
|
|
11028
|
+
"vite.config.mts",
|
|
11029
|
+
"vite.config.js",
|
|
11030
|
+
"vite.config.mjs",
|
|
11031
|
+
"vite.config.cjs"
|
|
11032
|
+
];
|
|
11033
|
+
function listWorkspaceSourceFiles(projectRoot) {
|
|
11034
|
+
const files = WORKSPACE_SOURCE_ROOTS.flatMap((relativeRoot) => {
|
|
11035
|
+
const root = path30.join(projectRoot, relativeRoot);
|
|
11036
|
+
return fs33.existsSync(root) ? listRegularFiles(root) : [];
|
|
11037
|
+
});
|
|
11038
|
+
for (const relativeFile of WORKSPACE_SOURCE_FILES) {
|
|
11039
|
+
const file = path30.join(projectRoot, relativeFile);
|
|
11040
|
+
if (!fs33.existsSync(file)) continue;
|
|
11041
|
+
if (fs33.lstatSync(file).isSymbolicLink() || !fs33.statSync(file).isFile()) {
|
|
11042
|
+
throw new Error(`workspace source file is invalid: ${file}`);
|
|
11043
|
+
}
|
|
11044
|
+
files.push(file);
|
|
11045
|
+
}
|
|
11046
|
+
return [...new Set(files)].sort().map((file) => ({
|
|
11047
|
+
path: path30.relative(projectRoot, file).split(path30.sep).join("/"),
|
|
11048
|
+
sha256: sha2562(file),
|
|
11049
|
+
size: fs33.statSync(file).size
|
|
11050
|
+
}));
|
|
11051
|
+
}
|
|
11052
|
+
function canonicalJson(value) {
|
|
11053
|
+
if (Array.isArray(value)) return value.map(canonicalJson);
|
|
11054
|
+
if (value && typeof value === "object") {
|
|
11055
|
+
return Object.fromEntries(
|
|
11056
|
+
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, canonicalJson(child)])
|
|
11057
|
+
);
|
|
11058
|
+
}
|
|
11059
|
+
return value;
|
|
11060
|
+
}
|
|
11061
|
+
function workspaceBuildInputs(projectRoot) {
|
|
11062
|
+
const packageJsonFile = path30.join(projectRoot, "package.json");
|
|
11063
|
+
const packageJson = fs33.existsSync(packageJsonFile) ? JSON.parse(fs33.readFileSync(packageJsonFile, "utf8")) : {};
|
|
11064
|
+
return {
|
|
11065
|
+
// Dependency versions deliberately remain governed by the recursive
|
|
11066
|
+
// client graph and bundled server artifact. Only package.json fields that
|
|
11067
|
+
// directly change bundle construction belong in this source binding.
|
|
11068
|
+
actionPlugins: canonicalJson(packageJson.actionPlugins ?? {})
|
|
11069
|
+
};
|
|
11070
|
+
}
|
|
11071
|
+
function packageNameFromOptimizerId(id) {
|
|
11072
|
+
const specifier = id.split(" > ").at(-1) ?? id;
|
|
11073
|
+
if (!specifier || specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("\0") || specifier.includes("://")) {
|
|
11074
|
+
return void 0;
|
|
11075
|
+
}
|
|
11076
|
+
const parts = specifier.split("/");
|
|
11077
|
+
return specifier.startsWith("@") ? parts.length >= 2 ? `${parts[0]}/${parts[1]}` : void 0 : parts[0];
|
|
11078
|
+
}
|
|
11079
|
+
function isPathInside3(root, candidate) {
|
|
11080
|
+
const relative = path30.relative(root, candidate);
|
|
11081
|
+
return relative === "" || !relative.startsWith("..") && !path30.isAbsolute(relative);
|
|
11082
|
+
}
|
|
11083
|
+
function isCanonicalRelativeAssetPath(candidate) {
|
|
11084
|
+
return typeof candidate === "string" && candidate.length > 0 && candidate === path30.posix.normalize(candidate) && candidate !== "." && !candidate.startsWith("../") && !path30.posix.isAbsolute(candidate) && !candidate.includes("\\");
|
|
11085
|
+
}
|
|
11086
|
+
function optimizerEntryUsesRuntimePackage(options) {
|
|
11087
|
+
const variants = options.runtime.packages?.[options.packageName];
|
|
11088
|
+
if (!Array.isArray(variants) || variants.length === 0) return false;
|
|
11089
|
+
if (typeof options.entry?.src !== "string" || !options.entry.src)
|
|
11090
|
+
return false;
|
|
11091
|
+
const source = path30.isAbsolute(options.entry.src) ? options.entry.src : path30.resolve(options.projectRoot, options.entry.src);
|
|
11092
|
+
if (!fs33.existsSync(source)) return false;
|
|
11093
|
+
const realSource = fs33.realpathSync(source);
|
|
11094
|
+
const runtimeRoot = path30.dirname(path30.resolve(options.runtimeManifestFile));
|
|
11095
|
+
return variants.some((variant) => {
|
|
11096
|
+
if (typeof variant.relativePath !== "string" || !variant.relativePath) {
|
|
11097
|
+
return false;
|
|
11098
|
+
}
|
|
11099
|
+
const packageRoot2 = path30.resolve(runtimeRoot, variant.relativePath);
|
|
11100
|
+
if (!isPathInside3(runtimeRoot, packageRoot2) || !fs33.existsSync(packageRoot2)) {
|
|
11101
|
+
return false;
|
|
11102
|
+
}
|
|
11103
|
+
return isPathInside3(fs33.realpathSync(packageRoot2), realSource);
|
|
11104
|
+
});
|
|
11105
|
+
}
|
|
11106
|
+
var REQUIRED_SERVER_PROBE_CHECKS = [
|
|
11107
|
+
"isolated-node-modules",
|
|
11108
|
+
"runtime-assets",
|
|
11109
|
+
"http-readiness",
|
|
11110
|
+
"business-api",
|
|
11111
|
+
"process-alive",
|
|
11112
|
+
"module-resolution"
|
|
11113
|
+
];
|
|
11114
|
+
function serverMetadataIsConsumable(serverMetadata) {
|
|
11115
|
+
const warningsAreValid = Array.isArray(serverMetadata?.dynamicImportWarnings) && serverMetadata.dynamicImportWarnings.every(
|
|
11116
|
+
(warning) => typeof warning?.kind === "string" && typeof warning?.source === "string" && /^[a-f0-9]{16}$/.test(warning?.expressionHash ?? "") && typeof warning?.message === "string"
|
|
11117
|
+
);
|
|
11118
|
+
const runtimeAssetWarningsAreValid = Array.isArray(serverMetadata?.runtimeAssetWarnings) && serverMetadata.runtimeAssetWarnings.every(
|
|
11119
|
+
(warning) => typeof warning?.kind === "string" && typeof warning?.source === "string" && /^[a-f0-9]{16}$/.test(warning?.expressionHash ?? "") && typeof warning?.message === "string"
|
|
11120
|
+
);
|
|
11121
|
+
const actionPluginsAreValid = Array.isArray(serverMetadata?.actionPlugins) && serverMetadata.actionPlugins.every(
|
|
11122
|
+
(plugin) => typeof plugin?.name === "string" && plugin.name.length > 0 && typeof plugin?.version === "string" && plugin.version.length > 0
|
|
11123
|
+
);
|
|
11124
|
+
const checks = serverMetadata?.availabilityProbe?.checks;
|
|
11125
|
+
const checkNames = Array.isArray(checks) ? checks.map((check2) => check2?.name) : [];
|
|
11126
|
+
const checksAreValid = Array.isArray(checks) && checks.every(
|
|
11127
|
+
(check2) => typeof check2?.name === "string" && check2?.success === true
|
|
11128
|
+
) && new Set(checkNames).size === checkNames.length && REQUIRED_SERVER_PROBE_CHECKS.every((name) => checkNames.includes(name)) && (serverMetadata.actionPlugins?.length === 0 || checkNames.includes("action-plugin-registry"));
|
|
11129
|
+
return serverMetadata?.schemaVersion === 2 && serverMetadata?.consumable === true && serverMetadata?.availabilityProbe?.success === true && serverMetadata?.availabilityProbe?.nodeModulesPresent === false && checksAreValid && warningsAreValid && runtimeAssetWarningsAreValid && actionPluginsAreValid && Array.isArray(serverMetadata?.runtimeAssets) && Array.isArray(serverMetadata?.externalImports) && serverMetadata.externalImports.length === 0;
|
|
11130
|
+
}
|
|
11131
|
+
function stableServerMetadataIdentity(serverMetadata) {
|
|
11132
|
+
const availabilityProbe = serverMetadata?.availabilityProbe ?? {};
|
|
11133
|
+
const checks = Array.isArray(availabilityProbe.checks) ? availabilityProbe.checks.map((check2) => {
|
|
11134
|
+
const { elapsedMs: _elapsedMs, ...stableCheck } = check2;
|
|
11135
|
+
return stableCheck;
|
|
11136
|
+
}) : availabilityProbe.checks;
|
|
11137
|
+
const {
|
|
11138
|
+
startupMs: _startupMs,
|
|
11139
|
+
stdout: _stdout,
|
|
11140
|
+
stderr: _stderr,
|
|
11141
|
+
...stableProbe
|
|
11142
|
+
} = availabilityProbe;
|
|
11143
|
+
return canonicalJson({
|
|
11144
|
+
...serverMetadata,
|
|
11145
|
+
availabilityProbe: { ...stableProbe, checks }
|
|
11146
|
+
});
|
|
11147
|
+
}
|
|
11148
|
+
function serverDependenciesAreConsumable(serverDependencies) {
|
|
11149
|
+
if (serverDependencies?.schemaVersion !== 1 || typeof serverDependencies?.sourceEntry !== "string" || serverDependencies.sourceEntry.length === 0 || typeof serverDependencies?.compiledEntry !== "string" || serverDependencies.compiledEntry.length === 0 || !Array.isArray(serverDependencies?.bootstrapModules) || serverDependencies.bootstrapModules.length === 0 || !Array.isArray(serverDependencies?.packages) || serverDependencies.packages.length === 0 || !Array.isArray(serverDependencies?.actionPlugins) || !Array.isArray(serverDependencies?.files) || serverDependencies.files.length === 0 || !/^[a-f0-9]{64}$/.test(serverDependencies?.treeSha256 ?? "") || serverDependencies.fileCount !== serverDependencies.files.length || !Number.isSafeInteger(serverDependencies.totalBytes) || serverDependencies.totalBytes <= 0) {
|
|
11150
|
+
return false;
|
|
11151
|
+
}
|
|
11152
|
+
const packageRecordsAreValid = (packages) => packages.every(
|
|
11153
|
+
(pkg2) => typeof pkg2?.name === "string" && pkg2.name.length > 0 && typeof pkg2?.version === "string" && pkg2.version.length > 0
|
|
11154
|
+
);
|
|
11155
|
+
const paths = /* @__PURE__ */ new Set();
|
|
11156
|
+
const filesAreValid = serverDependencies.files.every((file) => {
|
|
11157
|
+
if (!isCanonicalRelativeAssetPath(file?.path) || !/^[a-f0-9]{64}$/.test(file?.sha256 ?? "") || !Number.isSafeInteger(file?.size) || file.size < 0 || paths.has(file.path)) {
|
|
11158
|
+
return false;
|
|
11159
|
+
}
|
|
11160
|
+
paths.add(file.path);
|
|
11161
|
+
return true;
|
|
11162
|
+
});
|
|
11163
|
+
const expectedTreeSha256 = crypto3.createHash("sha256").update(JSON.stringify(serverDependencies.files)).digest("hex");
|
|
11164
|
+
return packageRecordsAreValid(serverDependencies.packages) && packageRecordsAreValid(serverDependencies.actionPlugins) && filesAreValid && expectedTreeSha256 === serverDependencies.treeSha256 && serverDependencies.files.reduce(
|
|
11165
|
+
(total, file) => total + file.size,
|
|
11166
|
+
0
|
|
11167
|
+
) === serverDependencies.totalBytes;
|
|
11168
|
+
}
|
|
11169
|
+
function sealCacheGeneration(options) {
|
|
11170
|
+
const projectRoot = path30.resolve(options.projectRoot);
|
|
11171
|
+
const cacheRoot = path30.resolve(
|
|
11172
|
+
projectRoot,
|
|
11173
|
+
options.cacheRoot ?? ".miaoda-cache"
|
|
11174
|
+
);
|
|
11175
|
+
const outfile = path30.resolve(
|
|
11176
|
+
projectRoot,
|
|
11177
|
+
options.outfile ?? path30.join(cacheRoot, "generation.json")
|
|
11178
|
+
);
|
|
11179
|
+
const runtimeManifestFile = path30.isAbsolute(options.runtimeManifestFile) ? options.runtimeManifestFile : path30.resolve(projectRoot, options.runtimeManifestFile);
|
|
11180
|
+
const files = {
|
|
11181
|
+
serverBundle: path30.join(cacheRoot, "server", "server.bundle.cjs"),
|
|
11182
|
+
serverMetadata: path30.join(
|
|
11183
|
+
cacheRoot,
|
|
11184
|
+
"server",
|
|
11185
|
+
"server.bundle.cjs.meta.json"
|
|
11186
|
+
),
|
|
11187
|
+
serverDependencies: path30.join(
|
|
11188
|
+
cacheRoot,
|
|
11189
|
+
"server",
|
|
11190
|
+
"dependencies.json"
|
|
11191
|
+
),
|
|
11192
|
+
appRuntime: path30.join(cacheRoot, "app-runtime.json"),
|
|
11193
|
+
viteMetadata: path30.join(cacheRoot, "vite", "deps", "_metadata.json")
|
|
11194
|
+
};
|
|
11195
|
+
const viteRoot = path30.join(cacheRoot, "vite");
|
|
11196
|
+
fs33.rmSync(outfile, { force: true });
|
|
11197
|
+
const baseInputs = [
|
|
11198
|
+
runtimeManifestFile,
|
|
11199
|
+
files.appRuntime,
|
|
11200
|
+
files.viteMetadata
|
|
11201
|
+
];
|
|
11202
|
+
const missingBaseInputs = baseInputs.filter((file) => !fs33.existsSync(file));
|
|
11203
|
+
if (missingBaseInputs.length > 0) {
|
|
11204
|
+
return {
|
|
11205
|
+
sealed: false,
|
|
11206
|
+
reasons: missingBaseInputs.map(
|
|
11207
|
+
(file) => `cache generation input missing: ${file}`
|
|
11208
|
+
)
|
|
11209
|
+
};
|
|
11210
|
+
}
|
|
11211
|
+
let applicationKind;
|
|
11212
|
+
try {
|
|
11213
|
+
const appRuntime = JSON.parse(fs33.readFileSync(files.appRuntime, "utf8"));
|
|
11214
|
+
applicationKind = appRuntime.applicationKind === "frontend-only" ? "frontend-only" : "fullstack";
|
|
11215
|
+
} catch (error) {
|
|
11216
|
+
return {
|
|
11217
|
+
sealed: false,
|
|
11218
|
+
reasons: [error instanceof Error ? error.message : String(error)]
|
|
11219
|
+
};
|
|
11220
|
+
}
|
|
11221
|
+
const hasServerDependencies = fs33.existsSync(files.serverDependencies);
|
|
11222
|
+
const serverFiles = hasServerDependencies ? [files.serverDependencies, path30.join(cacheRoot, "server", "node_modules")] : [files.serverBundle, files.serverMetadata];
|
|
11223
|
+
const missing = (applicationKind === "fullstack" ? serverFiles : []).filter(
|
|
11224
|
+
(file) => !fs33.existsSync(file)
|
|
11225
|
+
);
|
|
11226
|
+
if (missing.length > 0) {
|
|
11227
|
+
return {
|
|
11228
|
+
sealed: false,
|
|
11229
|
+
reasons: missing.map((file) => `cache generation input missing: ${file}`)
|
|
11230
|
+
};
|
|
11231
|
+
}
|
|
11232
|
+
try {
|
|
11233
|
+
const runtime = JSON.parse(fs33.readFileSync(runtimeManifestFile, "utf8"));
|
|
11234
|
+
const appRuntime = JSON.parse(fs33.readFileSync(files.appRuntime, "utf8"));
|
|
11235
|
+
const viteMetadata = JSON.parse(
|
|
11236
|
+
fs33.readFileSync(files.viteMetadata, "utf8")
|
|
11237
|
+
);
|
|
11238
|
+
const serverMetadata = applicationKind === "fullstack" && !hasServerDependencies ? JSON.parse(fs33.readFileSync(files.serverMetadata, "utf8")) : void 0;
|
|
11239
|
+
const serverDependencies = applicationKind === "fullstack" && hasServerDependencies ? JSON.parse(fs33.readFileSync(files.serverDependencies, "utf8")) : void 0;
|
|
11240
|
+
const reasons = [];
|
|
11241
|
+
const serverRuntimeAssetFiles = [];
|
|
11242
|
+
if (runtime.schemaVersion !== 1 || !runtime.runtimeAbiHash) {
|
|
11243
|
+
reasons.push("unsupported platform runtime manifest");
|
|
11244
|
+
}
|
|
11245
|
+
if (appRuntime.schemaVersion !== 1 || appRuntime.runtimeAbiHash !== runtime.runtimeAbiHash) {
|
|
11246
|
+
reasons.push("application/runtime ABI mismatch");
|
|
11247
|
+
}
|
|
11248
|
+
if (!/^[a-f0-9]{64}$/.test(appRuntime.clientDependencyGraphHash ?? "") || appRuntime.clientDependencyGraph?.schemaVersion !== 1 || appRuntime.clientDependencyGraph?.runtimeAbiHash !== runtime.runtimeAbiHash) {
|
|
11249
|
+
reasons.push("application client dependency graph is invalid");
|
|
11250
|
+
}
|
|
11251
|
+
if (applicationKind === "fullstack" && hasServerDependencies && !serverDependenciesAreConsumable(serverDependencies)) {
|
|
11252
|
+
reasons.push("server runtime dependency metadata is not consumable");
|
|
11253
|
+
}
|
|
11254
|
+
if (applicationKind === "fullstack" && !hasServerDependencies && !serverMetadataIsConsumable(serverMetadata)) {
|
|
11255
|
+
reasons.push("server cache metadata is not consumable");
|
|
11256
|
+
}
|
|
11257
|
+
if (applicationKind === "fullstack" && !hasServerDependencies && sha2562(files.serverBundle) !== serverMetadata.bundleSha256) {
|
|
11258
|
+
reasons.push("server bundle SHA-256 mismatch");
|
|
11259
|
+
}
|
|
11260
|
+
if (applicationKind === "fullstack" && !hasServerDependencies && !Array.isArray(serverMetadata.runtimeAssets)) {
|
|
11261
|
+
reasons.push("server runtime asset manifest is missing");
|
|
11262
|
+
} else if (applicationKind === "fullstack" && !hasServerDependencies) {
|
|
11263
|
+
const runtimeAssetPaths = /* @__PURE__ */ new Set();
|
|
11264
|
+
for (const asset of serverMetadata.runtimeAssets) {
|
|
11265
|
+
if (!isCanonicalRelativeAssetPath(asset?.path)) {
|
|
11266
|
+
reasons.push(`server runtime asset path is invalid: ${asset?.path}`);
|
|
11267
|
+
continue;
|
|
11268
|
+
}
|
|
11269
|
+
if (runtimeAssetPaths.has(asset.path)) {
|
|
11270
|
+
reasons.push(
|
|
11271
|
+
`server runtime asset path is duplicated: ${asset.path}`
|
|
11272
|
+
);
|
|
11273
|
+
continue;
|
|
11274
|
+
}
|
|
11275
|
+
runtimeAssetPaths.add(asset.path);
|
|
11276
|
+
const file = path30.join(cacheRoot, "server", ...asset.path.split("/"));
|
|
11277
|
+
if (!fs33.existsSync(file) || !fs33.statSync(file).isFile()) {
|
|
11278
|
+
reasons.push(`server runtime asset is missing: ${asset.path}`);
|
|
11279
|
+
continue;
|
|
11280
|
+
}
|
|
11281
|
+
const actualSha256 = sha2562(file);
|
|
11282
|
+
const actualSize = fs33.statSync(file).size;
|
|
11283
|
+
if (asset.sha256 !== actualSha256 || asset.size !== actualSize) {
|
|
11284
|
+
reasons.push(
|
|
11285
|
+
`server runtime asset integrity mismatch: ${asset.path}`
|
|
11286
|
+
);
|
|
11287
|
+
continue;
|
|
11288
|
+
}
|
|
11289
|
+
serverRuntimeAssetFiles.push({
|
|
11290
|
+
key: `serverRuntimeAsset:${asset.path}`,
|
|
11291
|
+
file,
|
|
11292
|
+
path: asset.path
|
|
11293
|
+
});
|
|
11294
|
+
}
|
|
11295
|
+
}
|
|
11296
|
+
if (applicationKind === "fullstack" && hasServerDependencies) {
|
|
11297
|
+
const nodeModulesRoot = path30.join(cacheRoot, "server", "node_modules");
|
|
11298
|
+
const actualFiles = listRegularFiles(nodeModulesRoot).map((file) => ({
|
|
11299
|
+
path: path30.relative(nodeModulesRoot, file).split(path30.sep).join("/"),
|
|
11300
|
+
sha256: sha2562(file),
|
|
11301
|
+
size: fs33.statSync(file).size
|
|
11302
|
+
})).sort((left, right) => left.path.localeCompare(right.path));
|
|
11303
|
+
if (JSON.stringify(actualFiles) !== JSON.stringify(serverDependencies.files)) {
|
|
11304
|
+
reasons.push("server runtime dependency file set or integrity mismatch");
|
|
11305
|
+
}
|
|
11306
|
+
const currentActionPlugins = workspaceBuildInputs(projectRoot).actionPlugins;
|
|
11307
|
+
const cachedActionPlugins = Object.fromEntries(
|
|
11308
|
+
serverDependencies.actionPlugins.map(
|
|
11309
|
+
(plugin) => [
|
|
11310
|
+
plugin.name,
|
|
11311
|
+
plugin.version
|
|
11312
|
+
]
|
|
11313
|
+
)
|
|
11314
|
+
);
|
|
11315
|
+
if (JSON.stringify(currentActionPlugins) !== JSON.stringify(canonicalJson(cachedActionPlugins))) {
|
|
11316
|
+
reasons.push("server runtime ActionPlugin dependency mismatch");
|
|
11317
|
+
}
|
|
11318
|
+
}
|
|
11319
|
+
const optimizedDependencies = new Set(
|
|
11320
|
+
Object.keys(viteMetadata.optimized ?? {})
|
|
11321
|
+
);
|
|
11322
|
+
const missingViteDependencies = Array.from(
|
|
11323
|
+
new Set(appRuntime.optimizeDependencies ?? [])
|
|
11324
|
+
).filter((specifier) => !optimizedDependencies.has(specifier));
|
|
11325
|
+
if (missingViteDependencies.length > 0) {
|
|
11326
|
+
reasons.push(
|
|
11327
|
+
`vite cache dependency coverage missing: ${missingViteDependencies.join(", ")}`
|
|
11328
|
+
);
|
|
11329
|
+
}
|
|
11330
|
+
const graphPackageNames = new Set(
|
|
11331
|
+
(appRuntime.clientDependencyGraph?.entries ?? []).map(
|
|
11332
|
+
(entry) => packageNameFromOptimizerId(entry.specifier ?? "")
|
|
11333
|
+
).filter(Boolean)
|
|
11334
|
+
);
|
|
11335
|
+
const optimizerEntries = [
|
|
11336
|
+
...Object.entries(viteMetadata.optimized ?? {}),
|
|
11337
|
+
...Object.entries(viteMetadata.discovered ?? {})
|
|
11338
|
+
];
|
|
11339
|
+
const uncoveredOptimizerPackages = Array.from(
|
|
11340
|
+
new Set(
|
|
11341
|
+
optimizerEntries.flatMap(([id, entry]) => {
|
|
11342
|
+
const name = packageNameFromOptimizerId(id);
|
|
11343
|
+
if (!name || graphPackageNames.has(name)) return [];
|
|
11344
|
+
return optimizerEntryUsesRuntimePackage({
|
|
11345
|
+
projectRoot,
|
|
11346
|
+
runtimeManifestFile,
|
|
11347
|
+
runtime,
|
|
11348
|
+
packageName: name,
|
|
11349
|
+
entry
|
|
11350
|
+
}) ? [] : [name];
|
|
11351
|
+
})
|
|
11352
|
+
)
|
|
11353
|
+
).sort();
|
|
11354
|
+
if (uncoveredOptimizerPackages.length > 0) {
|
|
11355
|
+
reasons.push(
|
|
11356
|
+
`vite optimizer graph/toolchain coverage missing: ${uncoveredOptimizerPackages.join(", ")}`
|
|
11357
|
+
);
|
|
11358
|
+
}
|
|
11359
|
+
if (reasons.length > 0) return { sealed: false, reasons };
|
|
11360
|
+
const artifactFiles = {
|
|
11361
|
+
appRuntime: files.appRuntime,
|
|
11362
|
+
viteMetadata: files.viteMetadata,
|
|
11363
|
+
...applicationKind === "fullstack" ? hasServerDependencies ? { serverDependencies: files.serverDependencies } : {
|
|
11364
|
+
serverBundle: files.serverBundle,
|
|
11365
|
+
serverMetadata: files.serverMetadata
|
|
11366
|
+
} : {}
|
|
11367
|
+
};
|
|
11368
|
+
const artifacts = Object.fromEntries([
|
|
11369
|
+
...Object.entries(artifactFiles).map(([name, file]) => [
|
|
11370
|
+
name,
|
|
11371
|
+
{
|
|
11372
|
+
path: path30.relative(cacheRoot, file),
|
|
11373
|
+
sha256: sha2562(file),
|
|
11374
|
+
size: fs33.statSync(file).size
|
|
11375
|
+
}
|
|
11376
|
+
]),
|
|
11377
|
+
...serverRuntimeAssetFiles.map((asset) => [
|
|
11378
|
+
asset.key,
|
|
11379
|
+
{
|
|
11380
|
+
path: path30.posix.join("server", asset.path),
|
|
11381
|
+
sha256: sha2562(asset.file),
|
|
11382
|
+
size: fs33.statSync(asset.file).size
|
|
11383
|
+
}
|
|
11384
|
+
])
|
|
11385
|
+
]);
|
|
11386
|
+
const viteFiles = listRegularFiles(viteRoot).map((file) => ({
|
|
11387
|
+
path: path30.relative(cacheRoot, file),
|
|
11388
|
+
sha256: sha2562(file),
|
|
11389
|
+
size: fs33.statSync(file).size
|
|
11390
|
+
}));
|
|
11391
|
+
if (viteFiles.length === 0) {
|
|
11392
|
+
return { sealed: false, reasons: ["vite cache is empty"] };
|
|
11393
|
+
}
|
|
11394
|
+
const stableMetadata = applicationKind === "fullstack" && !hasServerDependencies ? JSON.stringify(stableServerMetadataIdentity(serverMetadata)) : void 0;
|
|
11395
|
+
const serverMetadataIdentity = stableMetadata ? {
|
|
11396
|
+
sha256: crypto3.createHash("sha256").update(stableMetadata).digest("hex"),
|
|
11397
|
+
size: Buffer.byteLength(stableMetadata)
|
|
11398
|
+
} : void 0;
|
|
11399
|
+
const serverDependencyFiles = applicationKind === "fullstack" && hasServerDependencies ? listRegularFiles(path30.join(cacheRoot, "server")).map((file) => ({
|
|
11400
|
+
path: path30.relative(cacheRoot, file).split(path30.sep).join("/"),
|
|
11401
|
+
sha256: sha2562(file),
|
|
11402
|
+
size: fs33.statSync(file).size
|
|
11403
|
+
})) : void 0;
|
|
11404
|
+
const identity = {
|
|
11405
|
+
schemaVersion: hasServerDependencies ? 4 : 3,
|
|
11406
|
+
runtimeAbiHash: runtime.runtimeAbiHash,
|
|
11407
|
+
applicationKind,
|
|
11408
|
+
...applicationKind === "fullstack" ? {
|
|
11409
|
+
serverRuntime: {
|
|
11410
|
+
nodeVersion: (serverDependencies ?? serverMetadata).nodeVersion,
|
|
11411
|
+
nodeModuleAbi: (serverDependencies ?? serverMetadata).nodeModuleAbi,
|
|
11412
|
+
platform: (serverDependencies ?? serverMetadata).platform,
|
|
11413
|
+
arch: (serverDependencies ?? serverMetadata).arch
|
|
11414
|
+
},
|
|
11415
|
+
...hasServerDependencies ? {
|
|
11416
|
+
serverRuntimeMode: "workspace-source-dependencies",
|
|
11417
|
+
serverFiles: serverDependencyFiles
|
|
11418
|
+
} : {}
|
|
11419
|
+
} : {},
|
|
11420
|
+
artifacts,
|
|
11421
|
+
...serverMetadataIdentity ? { serverMetadataIdentity } : {},
|
|
11422
|
+
viteFiles,
|
|
11423
|
+
...hasServerDependencies ? {} : { sourceFiles: listWorkspaceSourceFiles(projectRoot) },
|
|
11424
|
+
workspaceBuildInputs: workspaceBuildInputs(projectRoot)
|
|
11425
|
+
};
|
|
11426
|
+
const generationIdentity = serverMetadataIdentity ? {
|
|
11427
|
+
...identity,
|
|
11428
|
+
artifacts: {
|
|
11429
|
+
...identity.artifacts,
|
|
11430
|
+
serverMetadata: {
|
|
11431
|
+
...identity.artifacts.serverMetadata,
|
|
11432
|
+
...serverMetadataIdentity
|
|
11433
|
+
}
|
|
11434
|
+
}
|
|
11435
|
+
} : identity;
|
|
11436
|
+
const generationId = crypto3.createHash("sha256").update(JSON.stringify(generationIdentity)).digest("hex");
|
|
11437
|
+
fs33.mkdirSync(path30.dirname(outfile), { recursive: true });
|
|
11438
|
+
const tempFile = `${outfile}.${process.pid}.${Date.now()}.tmp`;
|
|
11439
|
+
fs33.writeFileSync(
|
|
11440
|
+
tempFile,
|
|
11441
|
+
`${JSON.stringify({ ...identity, generationId }, null, 2)}
|
|
11442
|
+
`
|
|
11443
|
+
);
|
|
11444
|
+
fs33.renameSync(tempFile, outfile);
|
|
11445
|
+
return { sealed: true, outfile, generationId, reasons: [] };
|
|
11446
|
+
} catch (error) {
|
|
11447
|
+
fs33.rmSync(outfile, { force: true });
|
|
11448
|
+
return {
|
|
11449
|
+
sealed: false,
|
|
11450
|
+
reasons: [error instanceof Error ? error.message : String(error)]
|
|
11451
|
+
};
|
|
11452
|
+
}
|
|
11453
|
+
}
|
|
11454
|
+
|
|
11455
|
+
// src/commands/build/index.ts
|
|
11456
|
+
var getTokenCommand = {
|
|
11457
|
+
name: "get-token",
|
|
11458
|
+
description: "Get artifact upload credential (STI token)",
|
|
11459
|
+
register(program) {
|
|
11460
|
+
program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").requiredOption("--scene <scene>", "Build scene (pipeline, static)").option("--commit-id <id>", "Git commit ID (required for pipeline scene)").action(
|
|
11461
|
+
async (options) => {
|
|
11462
|
+
await getToken(options);
|
|
11463
|
+
}
|
|
11464
|
+
);
|
|
11465
|
+
}
|
|
11466
|
+
};
|
|
11467
|
+
var uploadStaticCommand = {
|
|
11468
|
+
name: "upload-static",
|
|
11469
|
+
description: "Upload shared/static files to TOS",
|
|
11470
|
+
register(program) {
|
|
11471
|
+
program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").option(
|
|
11472
|
+
"--static-dir <dir>",
|
|
11473
|
+
"Static files directory",
|
|
11474
|
+
UPLOAD_STATIC_DEFAULTS.staticDir
|
|
11475
|
+
).option(
|
|
11476
|
+
"--tosutil-path <path>",
|
|
11477
|
+
"Path to tosutil binary",
|
|
11478
|
+
UPLOAD_STATIC_DEFAULTS.tosutilPath
|
|
11479
|
+
).option(
|
|
11480
|
+
"--endpoint <endpoint>",
|
|
11481
|
+
"TOS endpoint",
|
|
11482
|
+
UPLOAD_STATIC_DEFAULTS.endpoint
|
|
11483
|
+
).option("--region <region>", "TOS region", UPLOAD_STATIC_DEFAULTS.region).action(async (options) => {
|
|
11484
|
+
await uploadStatic(options);
|
|
11485
|
+
});
|
|
11486
|
+
}
|
|
11487
|
+
};
|
|
11488
|
+
var preUploadStaticCommand = {
|
|
11489
|
+
name: "pre-upload-static",
|
|
11490
|
+
description: "Get TOS upload info and output as env vars for build.sh eval",
|
|
11491
|
+
register(program) {
|
|
11492
|
+
program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").action(async (options) => {
|
|
11493
|
+
await preUploadStatic(options);
|
|
11494
|
+
});
|
|
11495
|
+
}
|
|
11496
|
+
};
|
|
11497
|
+
var serverCacheBundleCommand = {
|
|
11498
|
+
name: "server-cache-bundle",
|
|
11499
|
+
description: "Build and probe a node_modules-free single-file NestJS cache bundle",
|
|
11500
|
+
register(program) {
|
|
11501
|
+
program.command(this.name).description(this.description).option("--project-root <dir>", "Application project root", process.cwd()).option(
|
|
11502
|
+
"--entry <file>",
|
|
11503
|
+
"Compiled Nest entry (auto-detects dist/server/main.js or dist/main.js)"
|
|
11504
|
+
).option(
|
|
11505
|
+
"--outfile <file>",
|
|
11506
|
+
"Output bundle",
|
|
11507
|
+
".miaoda-cache/server/server.bundle.cjs"
|
|
11508
|
+
).option("--metadata-file <file>", "Output metadata file").action(
|
|
11509
|
+
async (options) => {
|
|
11510
|
+
const result = await buildServerCacheBundle(options);
|
|
11511
|
+
console.log(JSON.stringify(result));
|
|
11512
|
+
if (!result.built) process.exitCode = 2;
|
|
11513
|
+
}
|
|
11514
|
+
);
|
|
11515
|
+
}
|
|
11516
|
+
};
|
|
11517
|
+
var serverRuntimeDependenciesCommand = {
|
|
11518
|
+
name: "server-runtime-dependencies",
|
|
11519
|
+
description: "Build the automatically traced npm dependency cache used by transition Nest",
|
|
11520
|
+
register(program) {
|
|
11521
|
+
program.command(this.name).description(this.description).option("--project-root <dir>", "Application project root", process.cwd()).option(
|
|
11522
|
+
"--entry <file>",
|
|
11523
|
+
"Compiled Nest entry (auto-detects dist/server/main.js or dist/main.js)"
|
|
11524
|
+
).option(
|
|
11525
|
+
"--source-entry <file>",
|
|
11526
|
+
"Workspace Nest source entry (auto-detects server/main.ts or src/main.ts)"
|
|
11527
|
+
).option(
|
|
11528
|
+
"--outdir <dir>",
|
|
11529
|
+
"Output node_modules directory",
|
|
11530
|
+
".miaoda-cache/server/node_modules"
|
|
11531
|
+
).option("--metadata-file <file>", "Output dependency metadata file").action(
|
|
11532
|
+
async (options) => {
|
|
11533
|
+
const result = await buildServerRuntimeDependencies(options);
|
|
11534
|
+
console.log(JSON.stringify(result));
|
|
11535
|
+
if (!result.built) process.exitCode = 2;
|
|
11536
|
+
}
|
|
11537
|
+
);
|
|
11538
|
+
}
|
|
11539
|
+
};
|
|
11540
|
+
var appRuntimeManifestCommand = {
|
|
11541
|
+
name: "app-runtime-manifest",
|
|
11542
|
+
description: "Freeze the browser dependency closure used by cache-only Vite",
|
|
11543
|
+
register(program) {
|
|
11544
|
+
program.command(this.name).description(this.description).option("--project-root <dir>", "Application project root", process.cwd()).requiredOption(
|
|
11545
|
+
"--runtime-manifest-file <file>",
|
|
11546
|
+
"Image platform runtime manifest"
|
|
11547
|
+
).option("--outfile <file>", "Application runtime manifest output").action(
|
|
11548
|
+
(options) => {
|
|
11549
|
+
const result = buildAppRuntimeManifest(options);
|
|
11550
|
+
console.log(JSON.stringify(result));
|
|
11551
|
+
if (!result.built) process.exitCode = 2;
|
|
11552
|
+
}
|
|
11553
|
+
);
|
|
11554
|
+
}
|
|
11555
|
+
};
|
|
11556
|
+
var cacheGenerationCommand = {
|
|
11557
|
+
name: "cache-generation",
|
|
11558
|
+
description: "Seal Vite, Nest and runtime manifests into one immutable cache generation",
|
|
11559
|
+
register(program) {
|
|
11560
|
+
program.command(this.name).description(this.description).option("--project-root <dir>", "Application project root", process.cwd()).requiredOption(
|
|
11561
|
+
"--runtime-manifest-file <file>",
|
|
11562
|
+
"Image platform runtime manifest"
|
|
11563
|
+
).option("--cache-root <dir>", "Cache root", ".miaoda-cache").option("--outfile <file>", "Generation manifest output").action(
|
|
11564
|
+
(options) => {
|
|
11565
|
+
const result = sealCacheGeneration(options);
|
|
11566
|
+
console.log(JSON.stringify(result));
|
|
11567
|
+
if (!result.sealed) process.exitCode = 2;
|
|
11568
|
+
}
|
|
11569
|
+
);
|
|
11570
|
+
}
|
|
11571
|
+
};
|
|
11572
|
+
var buildCommandGroup = {
|
|
11573
|
+
name: "build",
|
|
11574
|
+
description: "Build related commands",
|
|
11575
|
+
commands: [
|
|
11576
|
+
getTokenCommand,
|
|
11577
|
+
uploadStaticCommand,
|
|
11578
|
+
preUploadStaticCommand,
|
|
11579
|
+
serverCacheBundleCommand,
|
|
11580
|
+
serverRuntimeDependenciesCommand,
|
|
11581
|
+
appRuntimeManifestCommand,
|
|
11582
|
+
cacheGenerationCommand
|
|
11583
|
+
]
|
|
11584
|
+
};
|
|
11585
|
+
|
|
11586
|
+
// src/commands/index.ts
|
|
11587
|
+
var commands = [
|
|
11588
|
+
genDbSchemaCommand,
|
|
11589
|
+
syncCommand,
|
|
11590
|
+
upgradeCommand,
|
|
11591
|
+
actionPluginCommandGroup,
|
|
11592
|
+
capabilityCommandGroup,
|
|
11593
|
+
componentCommandGroup,
|
|
11594
|
+
migrationCommand,
|
|
11595
|
+
readLogsCommand,
|
|
11596
|
+
buildCommandGroup
|
|
11597
|
+
];
|
|
11598
|
+
|
|
11599
|
+
// src/utils/workspace-env.ts
|
|
11600
|
+
import fs34 from "fs";
|
|
11601
|
+
import path31 from "path";
|
|
11602
|
+
import { config as dotenvConfig } from "dotenv";
|
|
11603
|
+
function loadWorkspaceEnv(cwd = process.cwd(), targetEnv = process.env) {
|
|
11604
|
+
if (targetEnv.FULLSTACK_CLI_SKIP_DOTENV === "1") {
|
|
11605
|
+
return;
|
|
11606
|
+
}
|
|
11607
|
+
for (const filename of [".env.local", ".env"]) {
|
|
11608
|
+
const envPath = path31.join(cwd, filename);
|
|
11609
|
+
if (fs34.existsSync(envPath)) {
|
|
11610
|
+
dotenvConfig({ path: envPath, processEnv: targetEnv });
|
|
11611
|
+
}
|
|
11612
|
+
}
|
|
11613
|
+
}
|
|
11614
|
+
|
|
11615
|
+
// src/index.ts
|
|
11616
|
+
loadWorkspaceEnv();
|
|
11617
|
+
var __dirname = path32.dirname(fileURLToPath5(import.meta.url));
|
|
11618
|
+
var pkg = JSON.parse(fs35.readFileSync(path32.join(__dirname, "../package.json"), "utf-8"));
|
|
8280
11619
|
var cli = new FullstackCLI(pkg.version);
|
|
8281
11620
|
cli.useAll(commands);
|
|
8282
11621
|
cli.run();
|