@nextclaw/app-runtime 0.12.2 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -4
- package/dist/index.js +4 -1
- package/dist/package.js +1 -1
- package/dist/services/app-artifact-validation.service.d.ts +4 -0
- package/dist/services/app-artifact-validation.service.d.ts.map +1 -1
- package/dist/services/app-artifact-validation.service.js +16 -2
- package/dist/services/app-artifact-validation.service.js.map +1 -1
- package/dist/services/app-bundle.service.d.ts +4 -0
- package/dist/services/app-bundle.service.d.ts.map +1 -1
- package/dist/services/app-bundle.service.js +26 -4
- package/dist/services/app-bundle.service.js.map +1 -1
- package/dist/services/app-installation-filesystem.service.js +21 -3
- package/dist/services/app-installation-filesystem.service.js.map +1 -1
- package/dist/services/app-installation-lifecycle.service.js +1 -0
- package/dist/services/app-installation-lifecycle.service.js.map +1 -1
- package/dist/services/app-installation.service.d.ts +1 -0
- package/dist/services/app-installation.service.d.ts.map +1 -1
- package/dist/services/app-installation.service.js +12 -13
- package/dist/services/app-installation.service.js.map +1 -1
- package/dist/services/app-manifest.service.d.ts +3 -0
- package/dist/services/app-manifest.service.d.ts.map +1 -1
- package/dist/services/app-manifest.service.js +6 -0
- package/dist/services/app-manifest.service.js.map +1 -1
- package/dist/services/app-platform-target.service.d.ts +45 -0
- package/dist/services/app-platform-target.service.d.ts.map +1 -0
- package/dist/services/app-platform-target.service.js +176 -0
- package/dist/services/app-platform-target.service.js.map +1 -0
- package/dist/services/app-publish-artifact.service.d.ts +26 -0
- package/dist/services/app-publish-artifact.service.d.ts.map +1 -0
- package/dist/services/app-publish-artifact.service.js +55 -0
- package/dist/services/app-publish-artifact.service.js.map +1 -0
- package/dist/services/app-publish-validation.service.d.ts +15 -1
- package/dist/services/app-publish-validation.service.d.ts.map +1 -1
- package/dist/services/app-publish-validation.service.js +39 -1
- package/dist/services/app-publish-validation.service.js.map +1 -1
- package/dist/services/app-publish.service.d.ts +6 -1
- package/dist/services/app-publish.service.d.ts.map +1 -1
- package/dist/services/app-publish.service.js +43 -11
- package/dist/services/app-publish.service.js.map +1 -1
- package/dist/services/app-registry.service.d.ts +2 -0
- package/dist/services/app-registry.service.d.ts.map +1 -1
- package/dist/services/app-registry.service.js +4 -0
- package/dist/services/app-registry.service.js.map +1 -1
- package/dist/services/app-remote-registry-client.service.d.ts +7 -1
- package/dist/services/app-remote-registry-client.service.d.ts.map +1 -1
- package/dist/services/app-remote-registry-client.service.js +74 -7
- package/dist/services/app-remote-registry-client.service.js.map +1 -1
- package/dist/services/app-service-launch.service.d.ts +19 -0
- package/dist/services/app-service-launch.service.d.ts.map +1 -0
- package/dist/services/app-service-launch.service.js +54 -0
- package/dist/services/app-service-launch.service.js.map +1 -0
- package/dist/types/app-bundle.types.d.ts +3 -0
- package/dist/types/app-bundle.types.d.ts.map +1 -1
- package/dist/types/app-installation.types.d.ts +3 -1
- package/dist/types/app-installation.types.d.ts.map +1 -1
- package/dist/types/app-manifest.types.d.ts +32 -1
- package/dist/types/app-manifest.types.d.ts.map +1 -1
- package/dist/types/app-manifest.types.js.map +1 -1
- package/dist/types/app-publish.types.d.ts +26 -7
- package/dist/types/app-publish.types.d.ts.map +1 -1
- package/dist/types/app-publish.types.js.map +1 -1
- package/dist/types/app-registry.types.d.ts +2 -1
- package/dist/types/app-registry.types.d.ts.map +1 -1
- package/dist/types/app-remote-registry.types.d.ts +12 -2
- package/dist/types/app-remote-registry.types.d.ts.map +1 -1
- package/dist/types/app-remote-registry.types.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-platform-target.service.d.ts","names":[],"sources":["../../src/services/app-platform-target.service.ts"],"mappings":";;;KAOK,iBAAA;EACH,MAAA,EAAQ,iBAAA;AAAA;AAAA,KAGL,gBAAA,mBAAmC,iBAAA;EACtC,OAAA;EACA,SAAA,EAAW,SAAA;AAAA;AAAA,KAGR,+BAAA;EACH,QAAA,GAAW,MAAA,CAAO,QAAA;EAClB,IAAA;EACA,QAAA;AAAA;AAAA,cAGW,wBAAA;EAAA,iBACM,QAAA;EAAA,iBACA,IAAA;EAAA,iBACA,QAAA;cAEL,OAAA,GAAS,+BAAA;EAMrB,mBAAA,GACE,YAAA,EAAc,0BAAA,iBACb,0BAAA;EAEH,iBAAA,GAAqB,eAAA,cAA2B,0BAAA;EA6BhD,mBAAA,GAAuB,SAAA,WAAoB,SAAA,cAAuB,iBAAA;EAQlE,cAAA,GAAkB,SAAA,aAAoB,iBAAA;EAetC,WAAA,GAAe,MAAA,EAAQ,iBAAA;EASvB,cAAA,QAAqB,uBAAA;EAoBrB,cAAA,qBAAoC,iBAAA,EAClC,SAAA,WAAoB,SAAA,IACpB,UAAA,GAAY,uBAAA,KACX,SAAA;EAWH,6BAAA,qBAAmD,iBAAA,EACjD,QAAA,WAAmB,gBAAA,CAAiB,SAAA,KACpC,UAAA,GAAY,uBAAA,KACX,gBAAA,CAAiB,SAAA;EAIpB,oBAAA,GAAwB,MAAA;IACtB,QAAA,WAAmB,iBAAA;IACnB,MAAA,WAAiB,iBAAA;IACjB,WAAA;EAAA;EAAA,QAoBM,iBAAA;EAAA,QA8BA,gBAAA;EAAA,QAUA,cAAA;EAAA,QAaA,gBAAA;EAAA,QAUA,oBAAA;EAUR,eAAA,GAAmB,IAAA,UAAc,KAAA;EAAA,QA2BzB,YAAA;EAAA,QAeA,YAAA;AAAA"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
//#region src/services/app-platform-target.service.ts
|
|
2
|
+
var AppPlatformTargetService = class {
|
|
3
|
+
platform;
|
|
4
|
+
arch;
|
|
5
|
+
linuxAbi;
|
|
6
|
+
constructor(options = {}) {
|
|
7
|
+
this.platform = options.platform;
|
|
8
|
+
this.arch = options.arch;
|
|
9
|
+
this.linuxAbi = options.linuxAbi;
|
|
10
|
+
}
|
|
11
|
+
resolveDistribution = (distribution) => distribution ?? { mode: "universal" };
|
|
12
|
+
parseDistribution = (rawDistribution) => {
|
|
13
|
+
if (rawDistribution === void 0) return;
|
|
14
|
+
const candidate = this.assertObject(rawDistribution, "distribution");
|
|
15
|
+
if (candidate.mode === "universal") {
|
|
16
|
+
if (candidate.targets !== void 0) throw new Error("distribution.mode=universal 不能声明 targets。");
|
|
17
|
+
return { mode: "universal" };
|
|
18
|
+
}
|
|
19
|
+
if (candidate.mode !== "targeted") throw new Error("distribution.mode 只支持 universal 或 targeted。");
|
|
20
|
+
if (!Array.isArray(candidate.targets) || candidate.targets.length === 0) throw new Error("distribution.mode=targeted 必须声明至少一个 target。");
|
|
21
|
+
const targets = candidate.targets.map((target, index) => this.parseNativeTarget(target, `distribution.targets[${index}]`));
|
|
22
|
+
const targetKeys = targets.map(this.toTargetKey);
|
|
23
|
+
const duplicate = targetKeys.find((targetKey, index) => targetKeys.indexOf(targetKey) !== index);
|
|
24
|
+
if (duplicate) throw new Error(`distribution.targets 包含重复 target:${duplicate}`);
|
|
25
|
+
return {
|
|
26
|
+
mode: "targeted",
|
|
27
|
+
targets
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
parseArtifactTarget = (rawTarget, fieldName = "target") => {
|
|
31
|
+
const candidate = this.assertObject(rawTarget, fieldName);
|
|
32
|
+
if (candidate.kind === "universal") return { kind: "universal" };
|
|
33
|
+
return this.parseNativeTarget(candidate, fieldName);
|
|
34
|
+
};
|
|
35
|
+
parseTargetKey = (targetKey) => {
|
|
36
|
+
const normalized = targetKey.trim();
|
|
37
|
+
if (normalized === "universal") return { kind: "universal" };
|
|
38
|
+
const [os, arch, abi, ...extra] = normalized.split("-");
|
|
39
|
+
if (extra.length > 0 || !os || !arch) throw new Error(`非法 App target key:${targetKey}`);
|
|
40
|
+
return this.parseNativeTarget({
|
|
41
|
+
kind: "native",
|
|
42
|
+
os,
|
|
43
|
+
arch,
|
|
44
|
+
...abi ? { abi } : {}
|
|
45
|
+
}, "target");
|
|
46
|
+
};
|
|
47
|
+
toTargetKey = (target) => {
|
|
48
|
+
if (target.kind === "universal") return "universal";
|
|
49
|
+
return [
|
|
50
|
+
target.os,
|
|
51
|
+
target.arch,
|
|
52
|
+
"abi" in target ? target.abi : void 0
|
|
53
|
+
].filter(Boolean).join("-");
|
|
54
|
+
};
|
|
55
|
+
readHostTarget = () => {
|
|
56
|
+
const platform = this.readHostPlatform();
|
|
57
|
+
const arch = this.readArchitecture(this.readHostArchitecture(), "host architecture");
|
|
58
|
+
if (platform === "darwin") return {
|
|
59
|
+
kind: "native",
|
|
60
|
+
os: "darwin",
|
|
61
|
+
arch
|
|
62
|
+
};
|
|
63
|
+
if (platform === "linux") return {
|
|
64
|
+
kind: "native",
|
|
65
|
+
os: "linux",
|
|
66
|
+
arch,
|
|
67
|
+
abi: this.linuxAbi ?? this.detectLinuxAbi()
|
|
68
|
+
};
|
|
69
|
+
if (platform === "win32") return {
|
|
70
|
+
kind: "native",
|
|
71
|
+
os: "win32",
|
|
72
|
+
arch,
|
|
73
|
+
abi: "msvc"
|
|
74
|
+
};
|
|
75
|
+
throw new Error(`当前平台不支持原生 App artifact:${platform}-${arch}`);
|
|
76
|
+
};
|
|
77
|
+
selectArtifact = (artifacts, hostTarget = this.readHostTarget()) => {
|
|
78
|
+
const universal = artifacts.find((artifact) => artifact.target.kind === "universal");
|
|
79
|
+
if (universal) return universal;
|
|
80
|
+
const hostTargetKey = this.toTargetKey(hostTarget);
|
|
81
|
+
return artifacts.find((artifact) => this.toTargetKey(artifact.target) === hostTargetKey);
|
|
82
|
+
};
|
|
83
|
+
selectLatestCompatibleVersion = (versions, hostTarget = this.readHostTarget()) => versions.filter((version) => this.selectArtifact(version.artifacts, hostTarget)).sort((left, right) => this.compareVersions(right.version, left.version))[0];
|
|
84
|
+
assertExactTargetSet = (params) => {
|
|
85
|
+
const declared = [...new Set(params.declared.map(this.toTargetKey))].sort();
|
|
86
|
+
const actual = [...new Set(params.actual.map(this.toTargetKey))].sort();
|
|
87
|
+
if (declared.length !== params.declared.length || actual.length !== params.actual.length) throw new Error("App target 集合不能包含重复项。");
|
|
88
|
+
if (declared.length !== actual.length || declared.some((targetKey, index) => targetKey !== actual[index])) throw new Error(`声明 targets 与${params.actualLabel ?? "实际 artifacts"} 不一致:声明 [${declared.join(", ")}], 实际 [${actual.join(", ")}].`);
|
|
89
|
+
};
|
|
90
|
+
parseNativeTarget = (rawTarget, fieldName) => {
|
|
91
|
+
const candidate = this.assertObject(rawTarget, fieldName);
|
|
92
|
+
if (candidate.kind !== "native") throw new Error(`${fieldName}.kind 必须是 native。`);
|
|
93
|
+
const arch = this.readArchitecture(candidate.arch, `${fieldName}.arch`);
|
|
94
|
+
if (candidate.os === "darwin") {
|
|
95
|
+
if (candidate.abi !== void 0) throw new Error(`${fieldName} 的 darwin target 不能声明 abi。`);
|
|
96
|
+
return {
|
|
97
|
+
kind: "native",
|
|
98
|
+
os: "darwin",
|
|
99
|
+
arch
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (candidate.os === "linux") {
|
|
103
|
+
if (candidate.abi !== "gnu" && candidate.abi !== "musl") throw new Error(`${fieldName} 的 linux target 必须声明 gnu 或 musl abi。`);
|
|
104
|
+
return {
|
|
105
|
+
kind: "native",
|
|
106
|
+
os: "linux",
|
|
107
|
+
arch,
|
|
108
|
+
abi: candidate.abi
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (candidate.os === "win32") {
|
|
112
|
+
if (candidate.abi !== "msvc") throw new Error(`${fieldName} 的 win32 target 必须声明 msvc abi。`);
|
|
113
|
+
return {
|
|
114
|
+
kind: "native",
|
|
115
|
+
os: "win32",
|
|
116
|
+
arch,
|
|
117
|
+
abi: "msvc"
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`${fieldName}.os 只支持 darwin、linux 或 win32。`);
|
|
121
|
+
};
|
|
122
|
+
readArchitecture = (value, fieldName) => {
|
|
123
|
+
if (value !== "x64" && value !== "arm64") throw new Error(`${fieldName} 只支持 x64 或 arm64。`);
|
|
124
|
+
return value;
|
|
125
|
+
};
|
|
126
|
+
detectLinuxAbi = () => {
|
|
127
|
+
if (typeof process === "undefined") throw new Error("当前环境无法自动检测 Linux ABI,请显式提供 linuxAbi。");
|
|
128
|
+
const report = process.report?.getReport();
|
|
129
|
+
return typeof report?.header?.glibcVersionRuntime === "string" && report.header.glibcVersionRuntime.trim() ? "gnu" : "musl";
|
|
130
|
+
};
|
|
131
|
+
readHostPlatform = () => {
|
|
132
|
+
if (this.platform) return this.platform;
|
|
133
|
+
if (typeof process === "undefined") throw new Error("当前环境无法自动检测宿主平台,请显式提供 platform。");
|
|
134
|
+
return process.platform;
|
|
135
|
+
};
|
|
136
|
+
readHostArchitecture = () => {
|
|
137
|
+
if (this.arch) return this.arch;
|
|
138
|
+
if (typeof process === "undefined") throw new Error("当前环境无法自动检测宿主架构,请显式提供 arch。");
|
|
139
|
+
return process.arch;
|
|
140
|
+
};
|
|
141
|
+
compareVersions = (left, right) => {
|
|
142
|
+
const leftParts = this.parseVersion(left);
|
|
143
|
+
const rightParts = this.parseVersion(right);
|
|
144
|
+
if (leftParts && rightParts) {
|
|
145
|
+
for (let index = 0; index < 3; index += 1) {
|
|
146
|
+
const difference = (leftParts.numbers[index] ?? 0) - (rightParts.numbers[index] ?? 0);
|
|
147
|
+
if (difference !== 0) return difference;
|
|
148
|
+
}
|
|
149
|
+
if (leftParts.prerelease === rightParts.prerelease) return 0;
|
|
150
|
+
if (!leftParts.prerelease) return 1;
|
|
151
|
+
if (!rightParts.prerelease) return -1;
|
|
152
|
+
return leftParts.prerelease.localeCompare(rightParts.prerelease, void 0, { numeric: true });
|
|
153
|
+
}
|
|
154
|
+
return left.localeCompare(right, void 0, { numeric: true });
|
|
155
|
+
};
|
|
156
|
+
parseVersion = (version) => {
|
|
157
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(version);
|
|
158
|
+
if (!match) return;
|
|
159
|
+
return {
|
|
160
|
+
numbers: [
|
|
161
|
+
Number(match[1]),
|
|
162
|
+
Number(match[2]),
|
|
163
|
+
Number(match[3])
|
|
164
|
+
],
|
|
165
|
+
prerelease: match[4]
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
assertObject = (value, fieldName) => {
|
|
169
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${fieldName} 必须是对象。`);
|
|
170
|
+
return value;
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
//#endregion
|
|
174
|
+
export { AppPlatformTargetService };
|
|
175
|
+
|
|
176
|
+
//# sourceMappingURL=app-platform-target.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-platform-target.service.js","names":[],"sources":["../../src/services/app-platform-target.service.ts"],"sourcesContent":["import type {\n AppArtifactArchitecture,\n AppArtifactTarget,\n AppDistributionDeclaration,\n AppNativeArtifactTarget,\n} from \"#app-runtime/types/app-manifest.types.js\";\n\ntype AppTargetArtifact = {\n target: AppArtifactTarget;\n};\n\ntype AppTargetVersion<TArtifact extends AppTargetArtifact> = {\n version: string;\n artifacts: TArtifact[];\n};\n\ntype AppPlatformTargetServiceOptions = {\n platform?: NodeJS.Platform;\n arch?: string;\n linuxAbi?: \"gnu\" | \"musl\";\n};\n\nexport class AppPlatformTargetService {\n private readonly platform?: NodeJS.Platform;\n private readonly arch?: string;\n private readonly linuxAbi?: \"gnu\" | \"musl\";\n\n constructor(options: AppPlatformTargetServiceOptions = {}) {\n this.platform = options.platform;\n this.arch = options.arch;\n this.linuxAbi = options.linuxAbi;\n }\n\n resolveDistribution = (\n distribution: AppDistributionDeclaration | undefined,\n ): AppDistributionDeclaration => distribution ?? { mode: \"universal\" };\n\n parseDistribution = (rawDistribution: unknown): AppDistributionDeclaration | undefined => {\n if (rawDistribution === undefined) {\n return undefined;\n }\n const candidate = this.assertObject(rawDistribution, \"distribution\");\n if (candidate.mode === \"universal\") {\n if (candidate.targets !== undefined) {\n throw new Error(\"distribution.mode=universal 不能声明 targets。\");\n }\n return { mode: \"universal\" };\n }\n if (candidate.mode !== \"targeted\") {\n throw new Error(\"distribution.mode 只支持 universal 或 targeted。\");\n }\n if (!Array.isArray(candidate.targets) || candidate.targets.length === 0) {\n throw new Error(\"distribution.mode=targeted 必须声明至少一个 target。\");\n }\n const targets = candidate.targets.map((target, index) =>\n this.parseNativeTarget(target, `distribution.targets[${index}]`));\n const targetKeys = targets.map(this.toTargetKey);\n const duplicate = targetKeys.find(\n (targetKey, index) => targetKeys.indexOf(targetKey) !== index,\n );\n if (duplicate) {\n throw new Error(`distribution.targets 包含重复 target:${duplicate}`);\n }\n return { mode: \"targeted\", targets };\n };\n\n parseArtifactTarget = (rawTarget: unknown, fieldName = \"target\"): AppArtifactTarget => {\n const candidate = this.assertObject(rawTarget, fieldName);\n if (candidate.kind === \"universal\") {\n return { kind: \"universal\" };\n }\n return this.parseNativeTarget(candidate, fieldName);\n };\n\n parseTargetKey = (targetKey: string): AppArtifactTarget => {\n const normalized = targetKey.trim();\n if (normalized === \"universal\") {\n return { kind: \"universal\" };\n }\n const [os, arch, abi, ...extra] = normalized.split(\"-\");\n if (extra.length > 0 || !os || !arch) {\n throw new Error(`非法 App target key:${targetKey}`);\n }\n return this.parseNativeTarget(\n { kind: \"native\", os, arch, ...(abi ? { abi } : {}) },\n \"target\",\n );\n };\n\n toTargetKey = (target: AppArtifactTarget): string => {\n if (target.kind === \"universal\") {\n return \"universal\";\n }\n return [target.os, target.arch, \"abi\" in target ? target.abi : undefined]\n .filter(Boolean)\n .join(\"-\");\n };\n\n readHostTarget = (): AppNativeArtifactTarget => {\n const platform = this.readHostPlatform();\n const arch = this.readArchitecture(this.readHostArchitecture(), \"host architecture\");\n if (platform === \"darwin\") {\n return { kind: \"native\", os: \"darwin\", arch };\n }\n if (platform === \"linux\") {\n return {\n kind: \"native\",\n os: \"linux\",\n arch,\n abi: this.linuxAbi ?? this.detectLinuxAbi(),\n };\n }\n if (platform === \"win32\") {\n return { kind: \"native\", os: \"win32\", arch, abi: \"msvc\" };\n }\n throw new Error(`当前平台不支持原生 App artifact:${platform}-${arch}`);\n };\n\n selectArtifact = <TArtifact extends AppTargetArtifact>(\n artifacts: readonly TArtifact[],\n hostTarget: AppNativeArtifactTarget = this.readHostTarget(),\n ): TArtifact | undefined => {\n const universal = artifacts.find((artifact) => artifact.target.kind === \"universal\");\n if (universal) {\n return universal;\n }\n const hostTargetKey = this.toTargetKey(hostTarget);\n return artifacts.find(\n (artifact) => this.toTargetKey(artifact.target) === hostTargetKey,\n );\n };\n\n selectLatestCompatibleVersion = <TArtifact extends AppTargetArtifact>(\n versions: readonly AppTargetVersion<TArtifact>[],\n hostTarget: AppNativeArtifactTarget = this.readHostTarget(),\n ): AppTargetVersion<TArtifact> | undefined => versions\n .filter((version) => this.selectArtifact(version.artifacts, hostTarget))\n .sort((left, right) => this.compareVersions(right.version, left.version))[0];\n\n assertExactTargetSet = (params: {\n declared: readonly AppArtifactTarget[];\n actual: readonly AppArtifactTarget[];\n actualLabel?: string;\n }): void => {\n const declared = [...new Set(params.declared.map(this.toTargetKey))].sort();\n const actual = [...new Set(params.actual.map(this.toTargetKey))].sort();\n if (\n declared.length !== params.declared.length ||\n actual.length !== params.actual.length\n ) {\n throw new Error(\"App target 集合不能包含重复项。\");\n }\n if (\n declared.length !== actual.length ||\n declared.some((targetKey, index) => targetKey !== actual[index])\n ) {\n throw new Error(\n `声明 targets 与${params.actualLabel ?? \"实际 artifacts\"} 不一致:声明 [${declared.join(\", \")}], 实际 [${actual.join(\", \")}].`,\n );\n }\n };\n\n private parseNativeTarget = (\n rawTarget: unknown,\n fieldName: string,\n ): AppNativeArtifactTarget => {\n const candidate = this.assertObject(rawTarget, fieldName);\n if (candidate.kind !== \"native\") {\n throw new Error(`${fieldName}.kind 必须是 native。`);\n }\n const arch = this.readArchitecture(candidate.arch, `${fieldName}.arch`);\n if (candidate.os === \"darwin\") {\n if (candidate.abi !== undefined) {\n throw new Error(`${fieldName} 的 darwin target 不能声明 abi。`);\n }\n return { kind: \"native\", os: \"darwin\", arch };\n }\n if (candidate.os === \"linux\") {\n if (candidate.abi !== \"gnu\" && candidate.abi !== \"musl\") {\n throw new Error(`${fieldName} 的 linux target 必须声明 gnu 或 musl abi。`);\n }\n return { kind: \"native\", os: \"linux\", arch, abi: candidate.abi };\n }\n if (candidate.os === \"win32\") {\n if (candidate.abi !== \"msvc\") {\n throw new Error(`${fieldName} 的 win32 target 必须声明 msvc abi。`);\n }\n return { kind: \"native\", os: \"win32\", arch, abi: \"msvc\" };\n }\n throw new Error(`${fieldName}.os 只支持 darwin、linux 或 win32。`);\n };\n\n private readArchitecture = (\n value: unknown,\n fieldName: string,\n ): AppArtifactArchitecture => {\n if (value !== \"x64\" && value !== \"arm64\") {\n throw new Error(`${fieldName} 只支持 x64 或 arm64。`);\n }\n return value;\n };\n\n private detectLinuxAbi = (): \"gnu\" | \"musl\" => {\n if (typeof process === \"undefined\") {\n throw new Error(\"当前环境无法自动检测 Linux ABI,请显式提供 linuxAbi。\");\n }\n const report = process.report?.getReport() as {\n header?: { glibcVersionRuntime?: unknown };\n } | undefined;\n return typeof report?.header?.glibcVersionRuntime === \"string\" &&\n report.header.glibcVersionRuntime.trim()\n ? \"gnu\"\n : \"musl\";\n };\n\n private readHostPlatform = (): NodeJS.Platform => {\n if (this.platform) {\n return this.platform;\n }\n if (typeof process === \"undefined\") {\n throw new Error(\"当前环境无法自动检测宿主平台,请显式提供 platform。\");\n }\n return process.platform;\n };\n\n private readHostArchitecture = (): string => {\n if (this.arch) {\n return this.arch;\n }\n if (typeof process === \"undefined\") {\n throw new Error(\"当前环境无法自动检测宿主架构,请显式提供 arch。\");\n }\n return process.arch;\n };\n\n compareVersions = (left: string, right: string): number => {\n const leftParts = this.parseVersion(left);\n const rightParts = this.parseVersion(right);\n if (leftParts && rightParts) {\n for (let index = 0; index < 3; index += 1) {\n const difference = (leftParts.numbers[index] ?? 0) -\n (rightParts.numbers[index] ?? 0);\n if (difference !== 0) {\n return difference;\n }\n }\n if (leftParts.prerelease === rightParts.prerelease) {\n return 0;\n }\n if (!leftParts.prerelease) {\n return 1;\n }\n if (!rightParts.prerelease) {\n return -1;\n }\n return leftParts.prerelease.localeCompare(rightParts.prerelease, undefined, {\n numeric: true,\n });\n }\n return left.localeCompare(right, undefined, { numeric: true });\n };\n\n private parseVersion = (\n version: string,\n ): { numbers: [number, number, number]; prerelease?: string } | undefined => {\n const match = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+[0-9A-Za-z.-]+)?$/.exec(\n version,\n );\n if (!match) {\n return undefined;\n }\n return {\n numbers: [Number(match[1]), Number(match[2]), Number(match[3])],\n prerelease: match[4],\n };\n };\n\n private assertObject = (\n value: unknown,\n fieldName: string,\n ): Record<string, unknown> => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`${fieldName} 必须是对象。`);\n }\n return value as Record<string, unknown>;\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AppArtifactTarget, AppComponentManifest } from "../types/app-manifest.types.js";
|
|
2
|
+
import { AppArtifactValidationService } from "./app-artifact-validation.service.js";
|
|
3
|
+
import { AppPlatformTargetService } from "./app-platform-target.service.js";
|
|
4
|
+
|
|
5
|
+
//#region src/services/app-publish-artifact.service.d.ts
|
|
6
|
+
type AppPreparedPublishArtifact = {
|
|
7
|
+
target: AppArtifactTarget;
|
|
8
|
+
targetKey: string;
|
|
9
|
+
bundlePath: string;
|
|
10
|
+
bytes: Buffer;
|
|
11
|
+
sha256: string;
|
|
12
|
+
sizeBytes: number;
|
|
13
|
+
filePaths: string[];
|
|
14
|
+
};
|
|
15
|
+
declare class AppPublishArtifactService {
|
|
16
|
+
private readonly artifactValidationService;
|
|
17
|
+
private readonly platformTargetService;
|
|
18
|
+
constructor(artifactValidationService?: AppArtifactValidationService, platformTargetService?: AppPlatformTargetService);
|
|
19
|
+
collect: (params: {
|
|
20
|
+
manifest: AppComponentManifest;
|
|
21
|
+
artifactsDirectory: string;
|
|
22
|
+
}) => Promise<AppPreparedPublishArtifact[]>;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { AppPreparedPublishArtifact, AppPublishArtifactService };
|
|
26
|
+
//# sourceMappingURL=app-publish-artifact.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-publish-artifact.service.d.ts","names":[],"sources":["../../src/services/app-publish-artifact.service.ts"],"mappings":";;;;;KASY,0BAAA;EACV,MAAA,EAAQ,iBAAA;EACR,SAAA;EACA,UAAA;EACA,KAAA,EAAO,MAAA;EACP,MAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,cAGW,yBAAA;EAAA,iBAEQ,yBAAA;EAAA,iBACA,qBAAA;cADA,yBAAA,GAAyB,4BAAA,EACzB,qBAAA,GAAqB,wBAAA;EAGxC,OAAA,GAAiB,MAAA;IACf,QAAA,EAAU,oBAAA;IACV,kBAAA;EAAA,MACE,OAAA,CAAQ,0BAAA;AAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AppPlatformTargetService } from "./app-platform-target.service.js";
|
|
2
|
+
import { AppArtifactValidationService } from "./app-artifact-validation.service.js";
|
|
3
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
//#region src/services/app-publish-artifact.service.ts
|
|
6
|
+
var AppPublishArtifactService = class {
|
|
7
|
+
constructor(artifactValidationService = new AppArtifactValidationService(), platformTargetService = new AppPlatformTargetService()) {
|
|
8
|
+
this.artifactValidationService = artifactValidationService;
|
|
9
|
+
this.platformTargetService = platformTargetService;
|
|
10
|
+
}
|
|
11
|
+
collect = async (params) => {
|
|
12
|
+
const distribution = this.platformTargetService.resolveDistribution(params.manifest.distribution);
|
|
13
|
+
if (distribution.mode !== "targeted") throw new Error("只有 targeted App 才能使用 --artifacts 发布平台产物。");
|
|
14
|
+
const artifactsDirectory = path.resolve(params.artifactsDirectory);
|
|
15
|
+
const entries = (await readdir(artifactsDirectory, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".napp")).sort((left, right) => left.name.localeCompare(right.name));
|
|
16
|
+
if (entries.length === 0) throw new Error(`artifacts 目录中没有 .napp 文件:${artifactsDirectory}`);
|
|
17
|
+
const artifacts = await Promise.all(entries.map(async (entry) => {
|
|
18
|
+
const targetKey = entry.name.slice(0, -5);
|
|
19
|
+
const target = this.platformTargetService.parseTargetKey(targetKey);
|
|
20
|
+
if (target.kind !== "native") throw new Error("targeted App 的 artifacts 不能包含 universal.napp。");
|
|
21
|
+
const bundlePath = path.join(artifactsDirectory, entry.name);
|
|
22
|
+
const bytes = Buffer.from(await readFile(bundlePath));
|
|
23
|
+
const validation = await this.artifactValidationService.validate({
|
|
24
|
+
bytes,
|
|
25
|
+
expected: {
|
|
26
|
+
appId: params.manifest.id,
|
|
27
|
+
name: params.manifest.name,
|
|
28
|
+
version: params.manifest.version,
|
|
29
|
+
distributionMode: "bundle",
|
|
30
|
+
manifest: params.manifest,
|
|
31
|
+
target
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
target,
|
|
36
|
+
targetKey,
|
|
37
|
+
bundlePath,
|
|
38
|
+
bytes,
|
|
39
|
+
sha256: validation.artifactSha256,
|
|
40
|
+
sizeBytes: bytes.byteLength,
|
|
41
|
+
filePaths: Object.keys(validation.archive).sort((left, right) => left.localeCompare(right))
|
|
42
|
+
};
|
|
43
|
+
}));
|
|
44
|
+
this.platformTargetService.assertExactTargetSet({
|
|
45
|
+
declared: distribution.targets,
|
|
46
|
+
actual: artifacts.map((artifact) => artifact.target),
|
|
47
|
+
actualLabel: "上传 artifacts"
|
|
48
|
+
});
|
|
49
|
+
return artifacts;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
export { AppPublishArtifactService };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=app-publish-artifact.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-publish-artifact.service.js","names":[],"sources":["../../src/services/app-publish-artifact.service.ts"],"sourcesContent":["import { readFile, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { AppArtifactValidationService } from \"./app-artifact-validation.service.js\";\nimport { AppPlatformTargetService } from \"./app-platform-target.service.js\";\nimport type {\n AppArtifactTarget,\n AppComponentManifest,\n} from \"#app-runtime/types/app-manifest.types.js\";\n\nexport type AppPreparedPublishArtifact = {\n target: AppArtifactTarget;\n targetKey: string;\n bundlePath: string;\n bytes: Buffer;\n sha256: string;\n sizeBytes: number;\n filePaths: string[];\n};\n\nexport class AppPublishArtifactService {\n constructor(\n private readonly artifactValidationService = new AppArtifactValidationService(),\n private readonly platformTargetService = new AppPlatformTargetService(),\n ) {}\n\n collect = async (params: {\n manifest: AppComponentManifest;\n artifactsDirectory: string;\n }): Promise<AppPreparedPublishArtifact[]> => {\n const distribution = this.platformTargetService.resolveDistribution(\n params.manifest.distribution,\n );\n if (distribution.mode !== \"targeted\") {\n throw new Error(\"只有 targeted App 才能使用 --artifacts 发布平台产物。\");\n }\n const artifactsDirectory = path.resolve(params.artifactsDirectory);\n const entries = (await readdir(artifactsDirectory, { withFileTypes: true }))\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".napp\"))\n .sort((left, right) => left.name.localeCompare(right.name));\n if (entries.length === 0) {\n throw new Error(`artifacts 目录中没有 .napp 文件:${artifactsDirectory}`);\n }\n\n const artifacts = await Promise.all(entries.map(async (entry) => {\n const targetKey = entry.name.slice(0, -\".napp\".length);\n const target = this.platformTargetService.parseTargetKey(targetKey);\n if (target.kind !== \"native\") {\n throw new Error(\"targeted App 的 artifacts 不能包含 universal.napp。\");\n }\n const bundlePath = path.join(artifactsDirectory, entry.name);\n const bytes = Buffer.from(await readFile(bundlePath));\n const validation = await this.artifactValidationService.validate({\n bytes,\n expected: {\n appId: params.manifest.id,\n name: params.manifest.name,\n version: params.manifest.version,\n distributionMode: \"bundle\",\n manifest: params.manifest,\n target,\n },\n });\n return {\n target,\n targetKey,\n bundlePath,\n bytes,\n sha256: validation.artifactSha256,\n sizeBytes: bytes.byteLength,\n filePaths: Object.keys(validation.archive).sort((left, right) =>\n left.localeCompare(right),\n ),\n };\n }));\n\n this.platformTargetService.assertExactTargetSet({\n declared: distribution.targets,\n actual: artifacts.map((artifact) => artifact.target),\n actualLabel: \"上传 artifacts\",\n });\n return artifacts;\n };\n}\n"],"mappings":";;;;;AAmBA,IAAa,4BAAb,MAAuC;CACrC,YACE,4BAA6C,IAAI,8BAA8B,EAC/E,wBAAyC,IAAI,0BAA0B,EACvE;AAFiB,OAAA,4BAAA;AACA,OAAA,wBAAA;;CAGnB,UAAU,OAAO,WAG4B;EAC3C,MAAM,eAAe,KAAK,sBAAsB,oBAC9C,OAAO,SAAS,aACjB;AACD,MAAI,aAAa,SAAS,WACxB,OAAM,IAAI,MAAM,2CAA2C;EAE7D,MAAM,qBAAqB,KAAK,QAAQ,OAAO,mBAAmB;EAClE,MAAM,WAAW,MAAM,QAAQ,oBAAoB,EAAE,eAAe,MAAM,CAAC,EACxE,QAAQ,UAAU,MAAM,QAAQ,IAAI,MAAM,KAAK,SAAS,QAAQ,CAAC,CACjE,MAAM,MAAM,UAAU,KAAK,KAAK,cAAc,MAAM,KAAK,CAAC;AAC7D,MAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,4BAA4B,qBAAqB;EAGnE,MAAM,YAAY,MAAM,QAAQ,IAAI,QAAQ,IAAI,OAAO,UAAU;GAC/D,MAAM,YAAY,MAAM,KAAK,MAAM,GAAG,GAAgB;GACtD,MAAM,SAAS,KAAK,sBAAsB,eAAe,UAAU;AACnE,OAAI,OAAO,SAAS,SAClB,OAAM,IAAI,MAAM,gDAAgD;GAElE,MAAM,aAAa,KAAK,KAAK,oBAAoB,MAAM,KAAK;GAC5D,MAAM,QAAQ,OAAO,KAAK,MAAM,SAAS,WAAW,CAAC;GACrD,MAAM,aAAa,MAAM,KAAK,0BAA0B,SAAS;IAC/D;IACA,UAAU;KACR,OAAO,OAAO,SAAS;KACvB,MAAM,OAAO,SAAS;KACtB,SAAS,OAAO,SAAS;KACzB,kBAAkB;KAClB,UAAU,OAAO;KACjB;KACD;IACF,CAAC;AACF,UAAO;IACL;IACA;IACA;IACA;IACA,QAAQ,WAAW;IACnB,WAAW,MAAM;IACjB,WAAW,OAAO,KAAK,WAAW,QAAQ,CAAC,MAAM,MAAM,UACrD,KAAK,cAAc,MAAM,CAC1B;IACF;IACD,CAAC;AAEH,OAAK,sBAAsB,qBAAqB;GAC9C,UAAU,aAAa;GACvB,QAAQ,UAAU,KAAK,aAAa,SAAS,OAAO;GACpD,aAAa;GACd,CAAC;AACF,SAAO"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { AppArtifactTarget } from "../types/app-manifest.types.js";
|
|
1
2
|
import { AppDistributionMode } from "../types/app-bundle.types.js";
|
|
3
|
+
import { AppPlatformTargetService } from "./app-platform-target.service.js";
|
|
2
4
|
import { AppManifestService } from "./app-manifest.service.js";
|
|
3
5
|
import { AppBundleService } from "./app-bundle.service.js";
|
|
4
6
|
import { AppMarketplaceMetadataService } from "./app-marketplace-metadata.service.js";
|
|
7
|
+
import { AppPublishArtifactService } from "./app-publish-artifact.service.js";
|
|
5
8
|
|
|
6
9
|
//#region src/services/app-publish-validation.service.d.ts
|
|
7
10
|
type AppPublishValidationWarningCode = "main-entry-large" | "bundle-large";
|
|
@@ -23,17 +26,28 @@ type AppPublishValidationResult = {
|
|
|
23
26
|
componentCount?: number;
|
|
24
27
|
bundleSizeBytes: number;
|
|
25
28
|
bundleFilePaths: string[];
|
|
29
|
+
artifacts?: Array<{
|
|
30
|
+
target: AppArtifactTarget;
|
|
31
|
+
targetKey: string;
|
|
32
|
+
path: string;
|
|
33
|
+
sha256: string;
|
|
34
|
+
sizeBytes: number;
|
|
35
|
+
filePaths: string[];
|
|
36
|
+
}>;
|
|
26
37
|
warnings: AppPublishValidationWarning[];
|
|
27
38
|
};
|
|
28
39
|
declare class AppPublishValidationService {
|
|
29
40
|
private readonly manifestService;
|
|
30
41
|
private readonly metadataService;
|
|
31
42
|
private readonly bundleService;
|
|
32
|
-
|
|
43
|
+
private readonly publishArtifactService;
|
|
44
|
+
private readonly platformTargetService;
|
|
45
|
+
constructor(manifestService?: AppManifestService, metadataService?: AppMarketplaceMetadataService, bundleService?: AppBundleService, publishArtifactService?: AppPublishArtifactService, platformTargetService?: AppPlatformTargetService);
|
|
33
46
|
validate: (params: {
|
|
34
47
|
appDirectory: string;
|
|
35
48
|
metadataPath?: string;
|
|
36
49
|
mode?: AppDistributionMode;
|
|
50
|
+
artifactsDirectory?: string;
|
|
37
51
|
}) => Promise<AppPublishValidationResult>;
|
|
38
52
|
private buildWarnings;
|
|
39
53
|
private formatBytes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-publish-validation.service.d.ts","names":[],"sources":["../../src/services/app-publish-validation.service.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-publish-validation.service.d.ts","names":[],"sources":["../../src/services/app-publish-validation.service.ts"],"mappings":";;;;;;;;;KAmBY,+BAAA;AAAA,KAIA,2BAAA;EACV,IAAA,EAAM,+BAAA;EACN,OAAA;AAAA;AAAA,KAGU,0BAAA;EACV,EAAA;EACA,YAAA;EACA,YAAA;EACA,KAAA;EACA,OAAA;EACA,gBAAA,EAAkB,mBAAA;EAClB,OAAA;EACA,QAAA;EACA,aAAA;EACA,kBAAA;EACA,cAAA;EACA,eAAA;EACA,eAAA;EACA,SAAA,GAAY,KAAA;IACV,MAAA,EAAQ,iBAAA;IACR,SAAA;IACA,IAAA;IACA,MAAA;IACA,SAAA;IACA,SAAA;EAAA;EAEF,QAAA,EAAU,2BAAA;AAAA;AAAA,cAGC,2BAAA;EAAA,iBAEQ,eAAA;EAAA,iBACA,eAAA;EAAA,iBACA,aAAA;EAAA,iBACA,sBAAA;EAAA,iBACA,qBAAA;cAJA,eAAA,GAAiB,kBAAA,EACjB,eAAA,GAAiB,6BAAA,EACjB,aAAA,GAAe,gBAAA,EACf,sBAAA,GAAwB,yBAAA,EACxB,qBAAA,GAAuB,wBAAA;EAG1C,QAAA,GAAkB,MAAA;IAChB,YAAA;IACA,YAAA;IACA,IAAA,GAAO,mBAAA;IACP,kBAAA;EAAA,MACE,OAAA,CAAQ,0BAAA;EAAA,QAuGJ,aAAA;EAAA,QAqBA,WAAA;AAAA"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { AppPlatformTargetService } from "./app-platform-target.service.js";
|
|
1
2
|
import { AppManifestService } from "./app-manifest.service.js";
|
|
2
3
|
import { isAppComponentManifestBundle, isAppStandaloneManifestBundle } from "../types/app-manifest.types.js";
|
|
3
4
|
import { AppBundleService } from "./app-bundle.service.js";
|
|
4
5
|
import { AppMarketplaceMetadataService } from "./app-marketplace-metadata.service.js";
|
|
6
|
+
import { AppPublishArtifactService } from "./app-publish-artifact.service.js";
|
|
5
7
|
import { mkdtemp, rm, stat } from "node:fs/promises";
|
|
6
8
|
import path from "node:path";
|
|
7
9
|
import { tmpdir } from "node:os";
|
|
@@ -9,10 +11,12 @@ import { tmpdir } from "node:os";
|
|
|
9
11
|
const MAIN_ENTRY_WARN_BYTES = 10 * 1024 * 1024;
|
|
10
12
|
const BUNDLE_WARN_BYTES = 5 * 1024 * 1024;
|
|
11
13
|
var AppPublishValidationService = class {
|
|
12
|
-
constructor(manifestService = new AppManifestService(), metadataService = new AppMarketplaceMetadataService(), bundleService = new AppBundleService()) {
|
|
14
|
+
constructor(manifestService = new AppManifestService(), metadataService = new AppMarketplaceMetadataService(), bundleService = new AppBundleService(), publishArtifactService = new AppPublishArtifactService(), platformTargetService = new AppPlatformTargetService()) {
|
|
13
15
|
this.manifestService = manifestService;
|
|
14
16
|
this.metadataService = metadataService;
|
|
15
17
|
this.bundleService = bundleService;
|
|
18
|
+
this.publishArtifactService = publishArtifactService;
|
|
19
|
+
this.platformTargetService = platformTargetService;
|
|
16
20
|
}
|
|
17
21
|
validate = async (params) => {
|
|
18
22
|
const { appDirectory: inputAppDirectory, metadataPath: inputMetadataPath, mode } = params;
|
|
@@ -25,6 +29,40 @@ var AppPublishValidationService = class {
|
|
|
25
29
|
manifest: bundle.manifest,
|
|
26
30
|
metadataPath
|
|
27
31
|
});
|
|
32
|
+
if ((bundle.manifest.schemaVersion === 2 ? this.platformTargetService.resolveDistribution(bundle.manifest.distribution) : { mode: "universal" }).mode === "targeted") {
|
|
33
|
+
if (!params.artifactsDirectory?.trim()) throw new Error("targeted App 发布校验需要通过 --artifacts 指定平台 artifact 目录。");
|
|
34
|
+
if (!isAppComponentManifestBundle(bundle)) throw new Error("只有 schema v2 component App 支持 targeted artifacts。");
|
|
35
|
+
const artifacts = await this.publishArtifactService.collect({
|
|
36
|
+
manifest: bundle.manifest,
|
|
37
|
+
artifactsDirectory: params.artifactsDirectory
|
|
38
|
+
});
|
|
39
|
+
const bundleSizeBytes = artifacts.reduce((total, artifact) => total + artifact.sizeBytes, 0);
|
|
40
|
+
const warnings = artifacts.flatMap((artifact) => this.buildWarnings({ bundleSizeBytes: artifact.sizeBytes }).map((warning) => ({
|
|
41
|
+
...warning,
|
|
42
|
+
message: `${artifact.targetKey}: ${warning.message}`
|
|
43
|
+
})));
|
|
44
|
+
return {
|
|
45
|
+
ok: true,
|
|
46
|
+
appDirectory,
|
|
47
|
+
metadataPath,
|
|
48
|
+
appId: bundle.manifest.id,
|
|
49
|
+
version: bundle.manifest.version,
|
|
50
|
+
distributionMode,
|
|
51
|
+
profile: "components",
|
|
52
|
+
componentCount: bundle.components.length,
|
|
53
|
+
bundleSizeBytes,
|
|
54
|
+
bundleFilePaths: [],
|
|
55
|
+
artifacts: artifacts.map((artifact) => ({
|
|
56
|
+
target: artifact.target,
|
|
57
|
+
targetKey: artifact.targetKey,
|
|
58
|
+
path: artifact.bundlePath,
|
|
59
|
+
sha256: artifact.sha256,
|
|
60
|
+
sizeBytes: artifact.sizeBytes,
|
|
61
|
+
filePaths: artifact.filePaths
|
|
62
|
+
})),
|
|
63
|
+
warnings
|
|
64
|
+
};
|
|
65
|
+
}
|
|
28
66
|
const tempDirectory = await mkdtemp(path.join(tmpdir(), "napp-validate-publish-"));
|
|
29
67
|
try {
|
|
30
68
|
const packResult = await this.bundleService.packAppDirectory({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-publish-validation.service.js","names":[],"sources":["../../src/services/app-publish-validation.service.ts"],"sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { AppBundleService } from \"#app-runtime/services/app-bundle.service.js\";\nimport type { AppDistributionMode } from \"#app-runtime/types/app-bundle.types.js\";\nimport { AppManifestService } from \"#app-runtime/services/app-manifest.service.js\";\nimport {\n isAppComponentManifestBundle,\n isAppStandaloneManifestBundle,\n} from \"#app-runtime/types/app-manifest.types.js\";\nimport { AppMarketplaceMetadataService } from \"./app-marketplace-metadata.service.js\";\n\nconst MAIN_ENTRY_WARN_BYTES = 10 * 1024 * 1024;\nconst BUNDLE_WARN_BYTES = 5 * 1024 * 1024;\n\nexport type AppPublishValidationWarningCode =\n | \"main-entry-large\"\n | \"bundle-large\";\n\nexport type AppPublishValidationWarning = {\n code: AppPublishValidationWarningCode;\n message: string;\n};\n\nexport type AppPublishValidationResult = {\n ok: boolean;\n appDirectory: string;\n metadataPath: string;\n appId: string;\n version: string;\n distributionMode: AppDistributionMode;\n profile: \"standalone\" | \"components\";\n mainKind?: string;\n mainEntryPath?: string;\n mainEntrySizeBytes?: number;\n componentCount?: number;\n bundleSizeBytes: number;\n bundleFilePaths: string[];\n warnings: AppPublishValidationWarning[];\n};\n\nexport class AppPublishValidationService {\n constructor(\n private readonly manifestService: AppManifestService = new AppManifestService(),\n private readonly metadataService: AppMarketplaceMetadataService = new AppMarketplaceMetadataService(),\n private readonly bundleService: AppBundleService = new AppBundleService(),\n ) {}\n\n validate = async (params: {\n appDirectory: string;\n metadataPath?: string;\n mode?: AppDistributionMode;\n }): Promise<AppPublishValidationResult> => {\n const {\n appDirectory: inputAppDirectory,\n metadataPath: inputMetadataPath,\n mode,\n } = params;\n const appDirectory = path.resolve(inputAppDirectory);\n const bundle = await this.manifestService.load(appDirectory);\n const distributionMode = mode ??\n (bundle.manifest.schemaVersion === 2 ? \"bundle\" : \"source\");\n const metadataPath = inputMetadataPath\n ? path.resolve(inputMetadataPath)\n : path.join(appDirectory, \"marketplace.json\");\n await this.metadataService.load({\n appDirectory,\n manifest: bundle.manifest,\n metadataPath,\n });\n\n const tempDirectory = await mkdtemp(path.join(tmpdir(), \"napp-validate-publish-\"));\n try {\n const packResult = await this.bundleService.packAppDirectory({\n appDirectory,\n outputPath: path.join(tempDirectory, `${bundle.manifest.id}-${bundle.manifest.version}.napp`),\n mode: distributionMode,\n });\n const standaloneBundle = isAppStandaloneManifestBundle(bundle) ? bundle : undefined;\n const mainEntryStats = standaloneBundle\n ? await stat(standaloneBundle.mainEntryPath)\n : undefined;\n const warnings = this.buildWarnings({\n mainEntrySizeBytes: mainEntryStats?.size,\n bundleSizeBytes: packResult.sizeBytes,\n });\n return {\n ok: true,\n appDirectory,\n metadataPath,\n appId: bundle.manifest.id,\n version: bundle.manifest.version,\n distributionMode,\n profile: standaloneBundle ? \"standalone\" : \"components\",\n mainKind: standaloneBundle?.manifest.main.kind,\n mainEntryPath: standaloneBundle?.mainEntryPath,\n mainEntrySizeBytes: mainEntryStats?.size,\n componentCount: isAppComponentManifestBundle(bundle)\n ? bundle.components.length\n : undefined,\n bundleSizeBytes: packResult.sizeBytes,\n bundleFilePaths: packResult.filePaths,\n warnings,\n };\n } finally {\n await rm(tempDirectory, { recursive: true, force: true });\n }\n };\n\n private buildWarnings = (params: {\n mainEntrySizeBytes?: number;\n bundleSizeBytes: number;\n }): AppPublishValidationWarning[] => {\n const { bundleSizeBytes, mainEntrySizeBytes } = params;\n const warnings: AppPublishValidationWarning[] = [];\n if (mainEntrySizeBytes !== undefined && mainEntrySizeBytes > MAIN_ENTRY_WARN_BYTES) {\n warnings.push({\n code: \"main-entry-large\",\n message: `main entry is ${this.formatBytes(mainEntrySizeBytes)}, which is larger than the ${this.formatBytes(MAIN_ENTRY_WARN_BYTES)} warning threshold.`,\n });\n }\n if (bundleSizeBytes > BUNDLE_WARN_BYTES) {\n warnings.push({\n code: \"bundle-large\",\n message: `packed .napp is ${this.formatBytes(bundleSizeBytes)}, which is larger than the ${this.formatBytes(BUNDLE_WARN_BYTES)} warning threshold.`,\n });\n }\n return warnings;\n };\n\n private formatBytes = (value: number): string => {\n if (value < 1024) {\n return `${value} B`;\n }\n if (value < 1024 * 1024) {\n return `${(value / 1024).toFixed(1)} KB`;\n }\n return `${(value / (1024 * 1024)).toFixed(1)} MB`;\n };\n}\n"],"mappings":";;;;;;;;AAaA,MAAM,wBAAwB,KAAK,OAAO;AAC1C,MAAM,oBAAoB,IAAI,OAAO;AA4BrC,IAAa,8BAAb,MAAyC;CACvC,YACE,kBAAuD,IAAI,oBAAoB,EAC/E,kBAAkE,IAAI,+BAA+B,EACrG,gBAAmD,IAAI,kBAAkB,EACzE;AAHiB,OAAA,kBAAA;AACA,OAAA,kBAAA;AACA,OAAA,gBAAA;;CAGnB,WAAW,OAAO,WAIyB;EACzC,MAAM,EACJ,cAAc,mBACd,cAAc,mBACd,SACE;EACJ,MAAM,eAAe,KAAK,QAAQ,kBAAkB;EACpD,MAAM,SAAS,MAAM,KAAK,gBAAgB,KAAK,aAAa;EAC5D,MAAM,mBAAmB,SACtB,OAAO,SAAS,kBAAkB,IAAI,WAAW;EACpD,MAAM,eAAe,oBACjB,KAAK,QAAQ,kBAAkB,GAC/B,KAAK,KAAK,cAAc,mBAAmB;AAC/C,QAAM,KAAK,gBAAgB,KAAK;GAC9B;GACA,UAAU,OAAO;GACjB;GACD,CAAC;EAEF,MAAM,gBAAgB,MAAM,QAAQ,KAAK,KAAK,QAAQ,EAAE,yBAAyB,CAAC;AAClF,MAAI;GACF,MAAM,aAAa,MAAM,KAAK,cAAc,iBAAiB;IAC3D;IACA,YAAY,KAAK,KAAK,eAAe,GAAG,OAAO,SAAS,GAAG,GAAG,OAAO,SAAS,QAAQ,OAAO;IAC7F,MAAM;IACP,CAAC;GACF,MAAM,mBAAmB,8BAA8B,OAAO,GAAG,SAAS,KAAA;GAC1E,MAAM,iBAAiB,mBACnB,MAAM,KAAK,iBAAiB,cAAc,GAC1C,KAAA;GACJ,MAAM,WAAW,KAAK,cAAc;IAClC,oBAAoB,gBAAgB;IACpC,iBAAiB,WAAW;IAC7B,CAAC;AACF,UAAO;IACL,IAAI;IACJ;IACA;IACA,OAAO,OAAO,SAAS;IACvB,SAAS,OAAO,SAAS;IACzB;IACA,SAAS,mBAAmB,eAAe;IAC3C,UAAU,kBAAkB,SAAS,KAAK;IAC1C,eAAe,kBAAkB;IACjC,oBAAoB,gBAAgB;IACpC,gBAAgB,6BAA6B,OAAO,GAChD,OAAO,WAAW,SAClB,KAAA;IACJ,iBAAiB,WAAW;IAC5B,iBAAiB,WAAW;IAC5B;IACD;YACO;AACR,SAAM,GAAG,eAAe;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;;;CAI7D,iBAAyB,WAGY;EACnC,MAAM,EAAE,iBAAiB,uBAAuB;EAChD,MAAM,WAA0C,EAAE;AAClD,MAAI,uBAAuB,KAAA,KAAa,qBAAqB,sBAC3D,UAAS,KAAK;GACZ,MAAM;GACN,SAAS,iBAAiB,KAAK,YAAY,mBAAmB,CAAC,6BAA6B,KAAK,YAAY,sBAAsB,CAAC;GACrI,CAAC;AAEJ,MAAI,kBAAkB,kBACpB,UAAS,KAAK;GACZ,MAAM;GACN,SAAS,mBAAmB,KAAK,YAAY,gBAAgB,CAAC,6BAA6B,KAAK,YAAY,kBAAkB,CAAC;GAChI,CAAC;AAEJ,SAAO;;CAGT,eAAuB,UAA0B;AAC/C,MAAI,QAAQ,KACV,QAAO,GAAG,MAAM;AAElB,MAAI,QAAQ,OAAO,KACjB,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAEtC,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"app-publish-validation.service.js","names":[],"sources":["../../src/services/app-publish-validation.service.ts"],"sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { AppBundleService } from \"#app-runtime/services/app-bundle.service.js\";\nimport type { AppDistributionMode } from \"#app-runtime/types/app-bundle.types.js\";\nimport { AppManifestService } from \"#app-runtime/services/app-manifest.service.js\";\nimport type { AppArtifactTarget } from \"#app-runtime/types/app-manifest.types.js\";\nimport {\n isAppComponentManifestBundle,\n isAppStandaloneManifestBundle,\n} from \"#app-runtime/types/app-manifest.types.js\";\nimport { AppMarketplaceMetadataService } from \"./app-marketplace-metadata.service.js\";\nimport { AppPlatformTargetService } from \"./app-platform-target.service.js\";\nimport { AppPublishArtifactService } from \"./app-publish-artifact.service.js\";\n\nconst MAIN_ENTRY_WARN_BYTES = 10 * 1024 * 1024;\nconst BUNDLE_WARN_BYTES = 5 * 1024 * 1024;\n\nexport type AppPublishValidationWarningCode =\n | \"main-entry-large\"\n | \"bundle-large\";\n\nexport type AppPublishValidationWarning = {\n code: AppPublishValidationWarningCode;\n message: string;\n};\n\nexport type AppPublishValidationResult = {\n ok: boolean;\n appDirectory: string;\n metadataPath: string;\n appId: string;\n version: string;\n distributionMode: AppDistributionMode;\n profile: \"standalone\" | \"components\";\n mainKind?: string;\n mainEntryPath?: string;\n mainEntrySizeBytes?: number;\n componentCount?: number;\n bundleSizeBytes: number;\n bundleFilePaths: string[];\n artifacts?: Array<{\n target: AppArtifactTarget;\n targetKey: string;\n path: string;\n sha256: string;\n sizeBytes: number;\n filePaths: string[];\n }>;\n warnings: AppPublishValidationWarning[];\n};\n\nexport class AppPublishValidationService {\n constructor(\n private readonly manifestService: AppManifestService = new AppManifestService(),\n private readonly metadataService: AppMarketplaceMetadataService = new AppMarketplaceMetadataService(),\n private readonly bundleService: AppBundleService = new AppBundleService(),\n private readonly publishArtifactService: AppPublishArtifactService = new AppPublishArtifactService(),\n private readonly platformTargetService: AppPlatformTargetService = new AppPlatformTargetService(),\n ) {}\n\n validate = async (params: {\n appDirectory: string;\n metadataPath?: string;\n mode?: AppDistributionMode;\n artifactsDirectory?: string;\n }): Promise<AppPublishValidationResult> => {\n const {\n appDirectory: inputAppDirectory,\n metadataPath: inputMetadataPath,\n mode,\n } = params;\n const appDirectory = path.resolve(inputAppDirectory);\n const bundle = await this.manifestService.load(appDirectory);\n const distributionMode = mode ??\n (bundle.manifest.schemaVersion === 2 ? \"bundle\" : \"source\");\n const metadataPath = inputMetadataPath\n ? path.resolve(inputMetadataPath)\n : path.join(appDirectory, \"marketplace.json\");\n await this.metadataService.load({\n appDirectory,\n manifest: bundle.manifest,\n metadataPath,\n });\n const distribution = bundle.manifest.schemaVersion === 2\n ? this.platformTargetService.resolveDistribution(bundle.manifest.distribution)\n : { mode: \"universal\" as const };\n if (distribution.mode === \"targeted\") {\n if (!params.artifactsDirectory?.trim()) {\n throw new Error(\"targeted App 发布校验需要通过 --artifacts 指定平台 artifact 目录。\");\n }\n if (!isAppComponentManifestBundle(bundle)) {\n throw new Error(\"只有 schema v2 component App 支持 targeted artifacts。\");\n }\n const artifacts = await this.publishArtifactService.collect({\n manifest: bundle.manifest,\n artifactsDirectory: params.artifactsDirectory,\n });\n const bundleSizeBytes = artifacts.reduce(\n (total, artifact) => total + artifact.sizeBytes,\n 0,\n );\n const warnings = artifacts.flatMap((artifact) =>\n this.buildWarnings({ bundleSizeBytes: artifact.sizeBytes }).map((warning) => ({\n ...warning,\n message: `${artifact.targetKey}: ${warning.message}`,\n })),\n );\n return {\n ok: true,\n appDirectory,\n metadataPath,\n appId: bundle.manifest.id,\n version: bundle.manifest.version,\n distributionMode,\n profile: \"components\",\n componentCount: bundle.components.length,\n bundleSizeBytes,\n bundleFilePaths: [],\n artifacts: artifacts.map((artifact) => ({\n target: artifact.target,\n targetKey: artifact.targetKey,\n path: artifact.bundlePath,\n sha256: artifact.sha256,\n sizeBytes: artifact.sizeBytes,\n filePaths: artifact.filePaths,\n })),\n warnings,\n };\n }\n\n const tempDirectory = await mkdtemp(path.join(tmpdir(), \"napp-validate-publish-\"));\n try {\n const packResult = await this.bundleService.packAppDirectory({\n appDirectory,\n outputPath: path.join(tempDirectory, `${bundle.manifest.id}-${bundle.manifest.version}.napp`),\n mode: distributionMode,\n });\n const standaloneBundle = isAppStandaloneManifestBundle(bundle) ? bundle : undefined;\n const mainEntryStats = standaloneBundle\n ? await stat(standaloneBundle.mainEntryPath)\n : undefined;\n const warnings = this.buildWarnings({\n mainEntrySizeBytes: mainEntryStats?.size,\n bundleSizeBytes: packResult.sizeBytes,\n });\n return {\n ok: true,\n appDirectory,\n metadataPath,\n appId: bundle.manifest.id,\n version: bundle.manifest.version,\n distributionMode,\n profile: standaloneBundle ? \"standalone\" : \"components\",\n mainKind: standaloneBundle?.manifest.main.kind,\n mainEntryPath: standaloneBundle?.mainEntryPath,\n mainEntrySizeBytes: mainEntryStats?.size,\n componentCount: isAppComponentManifestBundle(bundle)\n ? bundle.components.length\n : undefined,\n bundleSizeBytes: packResult.sizeBytes,\n bundleFilePaths: packResult.filePaths,\n warnings,\n };\n } finally {\n await rm(tempDirectory, { recursive: true, force: true });\n }\n };\n\n private buildWarnings = (params: {\n mainEntrySizeBytes?: number;\n bundleSizeBytes: number;\n }): AppPublishValidationWarning[] => {\n const { bundleSizeBytes, mainEntrySizeBytes } = params;\n const warnings: AppPublishValidationWarning[] = [];\n if (mainEntrySizeBytes !== undefined && mainEntrySizeBytes > MAIN_ENTRY_WARN_BYTES) {\n warnings.push({\n code: \"main-entry-large\",\n message: `main entry is ${this.formatBytes(mainEntrySizeBytes)}, which is larger than the ${this.formatBytes(MAIN_ENTRY_WARN_BYTES)} warning threshold.`,\n });\n }\n if (bundleSizeBytes > BUNDLE_WARN_BYTES) {\n warnings.push({\n code: \"bundle-large\",\n message: `packed .napp is ${this.formatBytes(bundleSizeBytes)}, which is larger than the ${this.formatBytes(BUNDLE_WARN_BYTES)} warning threshold.`,\n });\n }\n return warnings;\n };\n\n private formatBytes = (value: number): string => {\n if (value < 1024) {\n return `${value} B`;\n }\n if (value < 1024 * 1024) {\n return `${(value / 1024).toFixed(1)} KB`;\n }\n return `${(value / (1024 * 1024)).toFixed(1)} MB`;\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { AppDistributionMode } from "../types/app-bundle.types.js";
|
|
2
|
+
import { AppPlatformTargetService } from "./app-platform-target.service.js";
|
|
2
3
|
import { AppManifestService } from "./app-manifest.service.js";
|
|
3
4
|
import { AppBundleService } from "./app-bundle.service.js";
|
|
4
5
|
import { AppPublishResult } from "../types/app-publish.types.js";
|
|
5
6
|
import { AppMarketplaceClientService } from "./app-marketplace-client.service.js";
|
|
6
7
|
import { AppMarketplaceMetadataService } from "./app-marketplace-metadata.service.js";
|
|
8
|
+
import { AppPublishArtifactService } from "./app-publish-artifact.service.js";
|
|
7
9
|
import { PlatformAuthStateService } from "./platform-auth-state.service.js";
|
|
8
10
|
|
|
9
11
|
//#region src/services/app-publish.service.d.ts
|
|
@@ -13,7 +15,9 @@ declare class AppPublishService {
|
|
|
13
15
|
private readonly metadataService;
|
|
14
16
|
private readonly marketplaceClient;
|
|
15
17
|
private readonly authStateService;
|
|
16
|
-
|
|
18
|
+
private readonly publishArtifactService;
|
|
19
|
+
private readonly platformTargetService;
|
|
20
|
+
constructor(manifestService?: AppManifestService, bundleService?: AppBundleService, metadataService?: AppMarketplaceMetadataService, marketplaceClient?: AppMarketplaceClientService, authStateService?: PlatformAuthStateService, publishArtifactService?: AppPublishArtifactService, platformTargetService?: AppPlatformTargetService);
|
|
17
21
|
publish: (params: {
|
|
18
22
|
appDirectory: string;
|
|
19
23
|
metadataPath?: string;
|
|
@@ -21,6 +25,7 @@ declare class AppPublishService {
|
|
|
21
25
|
apiBaseUrl?: string;
|
|
22
26
|
token?: string;
|
|
23
27
|
mode?: AppDistributionMode;
|
|
28
|
+
artifactsDirectory?: string;
|
|
24
29
|
}) => Promise<AppPublishResult>;
|
|
25
30
|
private resolvePublishActor;
|
|
26
31
|
private fetchCurrentPlatformUser;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-publish.service.d.ts","names":[],"sources":["../../src/services/app-publish.service.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-publish.service.d.ts","names":[],"sources":["../../src/services/app-publish.service.ts"],"mappings":";;;;;;;;;;;cAoBa,iBAAA;EAAA,iBAEQ,eAAA;EAAA,iBACA,aAAA;EAAA,iBACA,eAAA;EAAA,iBACA,iBAAA;EAAA,iBACA,gBAAA;EAAA,iBACA,sBAAA;EAAA,iBACA,qBAAA;cANA,eAAA,GAAiB,kBAAA,EACjB,aAAA,GAAe,gBAAA,EACf,eAAA,GAAiB,6BAAA,EACjB,iBAAA,GAAmB,2BAAA,EACnB,gBAAA,GAAkB,wBAAA,EAClB,sBAAA,GAAwB,yBAAA,EACxB,qBAAA,GAAuB,wBAAA;EAG1C,OAAA,GAAiB,MAAA;IACf,YAAA;IACA,YAAA;IACA,gBAAA;IACA,UAAA;IACA,KAAA;IACA,IAAA,GAAO,mBAAA;IACP,kBAAA;EAAA,MACE,OAAA,CAAQ,gBAAA;EAAA,QA8HJ,mBAAA;EAAA,QA6CA,wBAAA;EAAA,QA6CA,sBAAA;EAAA,QAOA,kBAAA;EAAA,QAkBA,sBAAA;AAAA"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { AppPlatformTargetService } from "./app-platform-target.service.js";
|
|
1
2
|
import { AppManifestService } from "./app-manifest.service.js";
|
|
2
3
|
import { AppBundleService } from "./app-bundle.service.js";
|
|
3
4
|
import { AppMarketplaceClientService } from "./app-marketplace-client.service.js";
|
|
4
5
|
import { AppMarketplaceMetadataService } from "./app-marketplace-metadata.service.js";
|
|
6
|
+
import { AppPublishArtifactService } from "./app-publish-artifact.service.js";
|
|
5
7
|
import { PlatformAuthStateService } from "./platform-auth-state.service.js";
|
|
6
8
|
import { createHash } from "node:crypto";
|
|
7
9
|
import { readFile } from "node:fs/promises";
|
|
@@ -9,12 +11,14 @@ import path from "node:path";
|
|
|
9
11
|
//#region src/services/app-publish.service.ts
|
|
10
12
|
const DEFAULT_PLATFORM_API_BASE = "https://ai-gateway-api.nextclaw.io";
|
|
11
13
|
var AppPublishService = class {
|
|
12
|
-
constructor(manifestService = new AppManifestService(), bundleService = new AppBundleService(), metadataService = new AppMarketplaceMetadataService(), marketplaceClient = new AppMarketplaceClientService(), authStateService = new PlatformAuthStateService()) {
|
|
14
|
+
constructor(manifestService = new AppManifestService(), bundleService = new AppBundleService(), metadataService = new AppMarketplaceMetadataService(), marketplaceClient = new AppMarketplaceClientService(), authStateService = new PlatformAuthStateService(), publishArtifactService = new AppPublishArtifactService(), platformTargetService = new AppPlatformTargetService()) {
|
|
13
15
|
this.manifestService = manifestService;
|
|
14
16
|
this.bundleService = bundleService;
|
|
15
17
|
this.metadataService = metadataService;
|
|
16
18
|
this.marketplaceClient = marketplaceClient;
|
|
17
19
|
this.authStateService = authStateService;
|
|
20
|
+
this.publishArtifactService = publishArtifactService;
|
|
21
|
+
this.platformTargetService = platformTargetService;
|
|
18
22
|
}
|
|
19
23
|
publish = async (params) => {
|
|
20
24
|
const { appDirectory: inputAppDirectory, metadataPath, bundleOutputPath, apiBaseUrl, token } = params;
|
|
@@ -31,20 +35,27 @@ var AppPublishService = class {
|
|
|
31
35
|
explicitToken: token,
|
|
32
36
|
appId: manifestBundle.manifest.id
|
|
33
37
|
});
|
|
34
|
-
const
|
|
38
|
+
const componentManifest = manifestBundle.manifest.schemaVersion === 2 ? manifestBundle.manifest : void 0;
|
|
39
|
+
const distribution = componentManifest ? this.platformTargetService.resolveDistribution(componentManifest.distribution) : { mode: "universal" };
|
|
40
|
+
if (distribution.mode === "targeted" && !params.artifactsDirectory?.trim()) throw new Error("targeted App 发布需要通过 --artifacts 指定平台 artifact 目录。");
|
|
41
|
+
const preparedArtifacts = distribution.mode === "targeted" && componentManifest ? await this.publishArtifactService.collect({
|
|
42
|
+
manifest: componentManifest,
|
|
43
|
+
artifactsDirectory: params.artifactsDirectory
|
|
44
|
+
}) : [];
|
|
45
|
+
const bundle = distribution.mode === "universal" ? await this.bundleService.packAppDirectory({
|
|
35
46
|
appDirectory,
|
|
36
47
|
outputPath: bundleOutputPath,
|
|
37
48
|
mode: distributionMode
|
|
38
|
-
});
|
|
39
|
-
const bundleBytes = Buffer.from(await readFile(bundle.bundlePath));
|
|
40
|
-
const bundleSha256 = createHash("sha256").update(bundleBytes).digest("hex");
|
|
49
|
+
}) : void 0;
|
|
50
|
+
const bundleBytes = bundle ? Buffer.from(await readFile(bundle.bundlePath)) : void 0;
|
|
51
|
+
const bundleSha256 = bundleBytes ? createHash("sha256").update(bundleBytes).digest("hex") : void 0;
|
|
41
52
|
const publishFiles = await this.metadataService.collectPublishFiles({
|
|
42
53
|
appDirectory,
|
|
43
54
|
iconPath: manifestBundle.manifest.icon,
|
|
44
55
|
metadataPath,
|
|
45
56
|
visuals: metadata.visuals
|
|
46
57
|
});
|
|
47
|
-
const
|
|
58
|
+
const payloadBase = {
|
|
48
59
|
slug: metadata.slug,
|
|
49
60
|
appId: manifestBundle.manifest.id,
|
|
50
61
|
name: manifestBundle.manifest.name,
|
|
@@ -63,13 +74,24 @@ var AppPublishService = class {
|
|
|
63
74
|
distributionMode,
|
|
64
75
|
manifest: manifestBundle.manifest,
|
|
65
76
|
permissions: manifestBundle.manifest.schemaVersion === 1 ? manifestBundle.manifest.permissions ?? {} : this.manifestService.resolvePlatformSecurity(manifestBundle.manifest).permissions,
|
|
66
|
-
bundleBase64: bundleBytes.toString("base64"),
|
|
67
|
-
bundleSha256,
|
|
68
77
|
files: publishFiles.map((file) => ({
|
|
69
78
|
path: file.path,
|
|
70
79
|
contentBase64: file.bytes.toString("base64")
|
|
71
80
|
}))
|
|
72
81
|
};
|
|
82
|
+
const payload = bundleBytes && bundleSha256 ? {
|
|
83
|
+
...payloadBase,
|
|
84
|
+
bundleBase64: bundleBytes.toString("base64"),
|
|
85
|
+
bundleSha256
|
|
86
|
+
} : {
|
|
87
|
+
...payloadBase,
|
|
88
|
+
artifacts: preparedArtifacts.map((artifact) => ({
|
|
89
|
+
target: artifact.target,
|
|
90
|
+
bundleBase64: artifact.bytes.toString("base64"),
|
|
91
|
+
bundleSha256: artifact.sha256,
|
|
92
|
+
sizeBytes: artifact.sizeBytes
|
|
93
|
+
}))
|
|
94
|
+
};
|
|
73
95
|
return {
|
|
74
96
|
...await this.marketplaceClient.publish({
|
|
75
97
|
payload,
|
|
@@ -77,9 +99,19 @@ var AppPublishService = class {
|
|
|
77
99
|
token: actor.token
|
|
78
100
|
}),
|
|
79
101
|
distribution: {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
102
|
+
mode: distributionMode,
|
|
103
|
+
...bundle && bundleSha256 ? {
|
|
104
|
+
path: bundle.bundlePath,
|
|
105
|
+
sha256: bundleSha256
|
|
106
|
+
} : {
|
|
107
|
+
path: path.resolve(params.artifactsDirectory),
|
|
108
|
+
artifacts: preparedArtifacts.map((artifact) => ({
|
|
109
|
+
target: artifact.target,
|
|
110
|
+
path: artifact.bundlePath,
|
|
111
|
+
sha256: artifact.sha256,
|
|
112
|
+
sizeBytes: artifact.sizeBytes
|
|
113
|
+
}))
|
|
114
|
+
}
|
|
83
115
|
}
|
|
84
116
|
};
|
|
85
117
|
};
|