alemonjs 2.1.88 → 2.1.90
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/bin/README.md +10 -2
- package/bin/alemonc.js +1 -2
- package/bin/publish.js +99 -43
- package/lib/application/runtime/cbp/connects/client.js +11 -1
- package/lib/application/runtime/client-runtime.d.ts +2 -0
- package/lib/application/runtime/client-runtime.js +14 -36
- package/lib/application/runtime/load-modules/load.d.ts +2 -2
- package/lib/application/runtime/load-modules/load.js +8 -8
- package/lib/application/runtime/load-modules/loadChild.d.ts +1 -1
- package/lib/application/runtime/load-modules/loadChild.js +3 -3
- package/lib/client.d.ts +1 -1
- package/lib/client.js +91 -1
- package/lib/core/index.d.ts +3 -0
- package/lib/core/index.js +2 -0
- package/lib/core/process/index.d.ts +1 -0
- package/lib/core/process/index.js +2 -2
- package/lib/core/process/ipc-bridge.js +12 -0
- package/lib/core/process/module.d.ts +3 -0
- package/lib/core/process/module.js +338 -101
- package/lib/core/process/platform.d.ts +3 -0
- package/lib/core/process/platform.js +391 -165
- package/lib/core/process/types.d.ts +22 -0
- package/lib/core/process/types.js +1 -0
- package/lib/global.d.ts +3 -0
- package/lib/index.js +2 -0
- package/lib/main.d.ts +1 -0
- package/lib/main.js +2 -0
- package/lib/platform/cbp-platform.js +11 -1
- package/lib/platform/define-platform.js +3 -0
- package/lib/platform-bootstrap.d.ts +1 -0
- package/lib/platform-bootstrap.js +85 -0
- package/package.json +2 -2
package/bin/README.md
CHANGED
|
@@ -105,19 +105,27 @@ alemonc version update
|
|
|
105
105
|
```sh
|
|
106
106
|
alemonc publish
|
|
107
107
|
alemonc publish patch
|
|
108
|
+
alemonc publish prepatch --preid beta
|
|
109
|
+
alemonc publish v1.0.33-rc.0
|
|
108
110
|
alemonc publish --dry-run
|
|
109
111
|
```
|
|
110
112
|
|
|
111
113
|
行为说明:
|
|
112
114
|
|
|
113
115
|
- 默认会查询 git tag 历史作为版本基线
|
|
116
|
+
- 版本格式严格为:
|
|
117
|
+
- 正式版:`v1.0.33`
|
|
118
|
+
- 预发布版:`v1.0.33-alpha.0`、`v1.0.33-beta.0`、`v1.0.33-rc.0`、`v1.0.33-next.0`
|
|
119
|
+
- `package.json.version` 保存为不带 `v` 的形式,如 `1.0.33`、`1.0.33-beta.0`
|
|
114
120
|
- 不传参数时:
|
|
115
121
|
- 如果本地版本高于最新 tag,直接发布本地版本
|
|
116
122
|
- 否则自动按最新 tag `patch +1`
|
|
117
123
|
- 传 `patch/minor/major/prepatch/preminor/premajor/prerelease` 时会自动递增
|
|
118
|
-
-
|
|
124
|
+
- 传具体版本号时可写 `v1.0.33` 或 `1.0.33`
|
|
125
|
+
- `--preid` 仅允许 `alpha`、`beta`、`rc`、`next`
|
|
119
126
|
- 默认先执行 `npm run build`
|
|
120
|
-
-
|
|
127
|
+
- 默认发布内容是 `lib/`、`package.json`、`README.md`
|
|
128
|
+
- 如果项目配置了 `.npmignore` 或 `package.json.files`,则切换为 npm 文件选择规则
|
|
121
129
|
- 最终把产物提交到 git `release` 分支,并推送对应 tag
|
|
122
130
|
- 默认要求 git 工作区干净,发布成功后会自动提交源码中的 `package.json` 版本变更
|
|
123
131
|
|
package/bin/alemonc.js
CHANGED
|
@@ -78,8 +78,7 @@ program
|
|
|
78
78
|
program
|
|
79
79
|
.command('publish [release]')
|
|
80
80
|
.description('智能发布当前包到 git release 仓库,支持 patch/minor/major 或直接指定版本号')
|
|
81
|
-
.option('--
|
|
82
|
-
.option('--preid <preid>', '预发布标识,默认 beta', 'beta')
|
|
81
|
+
.option('--preid <preid>', '预发布标识,仅允许 alpha/beta/rc/next', 'beta')
|
|
83
82
|
.option('--branch <branch>', '发布目标分支,默认 release')
|
|
84
83
|
.option('--dry-run', '只执行检查和打包,不真正发布')
|
|
85
84
|
.option('--skip-build', '跳过构建')
|
package/bin/publish.js
CHANGED
|
@@ -5,7 +5,10 @@ import os from 'os';
|
|
|
5
5
|
import { execSync, spawnSync } from 'child_process';
|
|
6
6
|
|
|
7
7
|
const RELEASE_TYPES = new Set(['patch', 'minor', 'major', 'prepatch', 'preminor', 'premajor', 'prerelease']);
|
|
8
|
-
const
|
|
8
|
+
const PRERELEASE_IDS = new Set(['alpha', 'beta', 'rc', 'next']);
|
|
9
|
+
const SEMVER_RE = /^\d+\.\d+\.\d+(?:-(alpha|beta|rc|next)\.\d+)?$/;
|
|
10
|
+
const TAG_RE = /^v\d+\.\d+\.\d+(?:-(alpha|beta|rc|next)\.\d+)?$/;
|
|
11
|
+
const DEFAULT_PUBLISH_FILES = ['lib', 'package.json', 'README.md'];
|
|
9
12
|
|
|
10
13
|
function readPackageJson() {
|
|
11
14
|
const pkgPath = join(process.cwd(), 'package.json');
|
|
@@ -69,8 +72,21 @@ function ensureCleanGit() {
|
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
function normalizeVersionInput(version) {
|
|
76
|
+
return String(version).trim().replace(/^v/, '');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function validatePreid(preid) {
|
|
80
|
+
const value = String(preid || 'beta').trim();
|
|
81
|
+
if (!PRERELEASE_IDS.has(value)) {
|
|
82
|
+
throw new Error(`非法预发布标识: ${value},仅允许 alpha、beta、rc、next`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
|
|
72
88
|
function parseVersion(version) {
|
|
73
|
-
const matched = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(
|
|
89
|
+
const matched = normalizeVersionInput(version).match(/^(\d+)\.(\d+)\.(\d+)(?:-((alpha|beta|rc|next)\.(\d+)))?$/);
|
|
74
90
|
if (!matched) {
|
|
75
91
|
throw new Error(`非法版本号: ${version}`);
|
|
76
92
|
}
|
|
@@ -79,7 +95,9 @@ function parseVersion(version) {
|
|
|
79
95
|
major: Number(matched[1]),
|
|
80
96
|
minor: Number(matched[2]),
|
|
81
97
|
patch: Number(matched[3]),
|
|
82
|
-
prerelease: matched[4] ?? null
|
|
98
|
+
prerelease: matched[4] ?? null,
|
|
99
|
+
prereleaseId: matched[5] ?? null,
|
|
100
|
+
prereleaseNum: matched[6] ? Number(matched[6]) : null
|
|
83
101
|
};
|
|
84
102
|
}
|
|
85
103
|
|
|
@@ -101,6 +119,7 @@ function compareVersions(a, b) {
|
|
|
101
119
|
|
|
102
120
|
function incrementVersion(baseVersion, releaseType, preid = 'beta') {
|
|
103
121
|
const parsed = parseVersion(baseVersion);
|
|
122
|
+
const safePreid = validatePreid(preid);
|
|
104
123
|
|
|
105
124
|
if (releaseType === 'patch') {
|
|
106
125
|
return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`;
|
|
@@ -115,28 +134,23 @@ function incrementVersion(baseVersion, releaseType, preid = 'beta') {
|
|
|
115
134
|
}
|
|
116
135
|
|
|
117
136
|
if (releaseType === 'prepatch') {
|
|
118
|
-
return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}-${
|
|
137
|
+
return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}-${safePreid}.0`;
|
|
119
138
|
}
|
|
120
139
|
|
|
121
140
|
if (releaseType === 'preminor') {
|
|
122
|
-
return `${parsed.major}.${parsed.minor + 1}.0-${
|
|
141
|
+
return `${parsed.major}.${parsed.minor + 1}.0-${safePreid}.0`;
|
|
123
142
|
}
|
|
124
143
|
|
|
125
144
|
if (releaseType === 'premajor') {
|
|
126
|
-
return `${parsed.major + 1}.0.0-${
|
|
145
|
+
return `${parsed.major + 1}.0.0-${safePreid}.0`;
|
|
127
146
|
}
|
|
128
147
|
|
|
129
148
|
if (releaseType === 'prerelease') {
|
|
130
|
-
if (parsed.prerelease) {
|
|
131
|
-
|
|
132
|
-
if (next) {
|
|
133
|
-
return `${parsed.major}.${parsed.minor}.${parsed.patch}-${next[1]}${Number(next[2]) + 1}`;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return `${parsed.major}.${parsed.minor}.${parsed.patch}-${parsed.prerelease}.1`;
|
|
149
|
+
if (parsed.prerelease && parsed.prereleaseId === safePreid && parsed.prereleaseNum !== null) {
|
|
150
|
+
return `${parsed.major}.${parsed.minor}.${parsed.patch}-${safePreid}.${parsed.prereleaseNum + 1}`;
|
|
137
151
|
}
|
|
138
152
|
|
|
139
|
-
return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}-${
|
|
153
|
+
return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}-${safePreid}.0`;
|
|
140
154
|
}
|
|
141
155
|
|
|
142
156
|
throw new Error(`不支持的发布类型: ${releaseType}`);
|
|
@@ -160,8 +174,10 @@ function resolveTargetVersion(localVersion, remoteVersion, release, preid) {
|
|
|
160
174
|
return incrementVersion(base, release, preid);
|
|
161
175
|
}
|
|
162
176
|
|
|
163
|
-
|
|
164
|
-
|
|
177
|
+
const normalizedRelease = normalizeVersionInput(release);
|
|
178
|
+
|
|
179
|
+
if (SEMVER_RE.test(normalizedRelease)) {
|
|
180
|
+
return normalizedRelease;
|
|
165
181
|
}
|
|
166
182
|
|
|
167
183
|
throw new Error(`无法识别的发布参数: ${release}`);
|
|
@@ -188,29 +204,49 @@ function getPackResult(cwd = process.cwd()) {
|
|
|
188
204
|
return result[0];
|
|
189
205
|
}
|
|
190
206
|
|
|
191
|
-
function
|
|
192
|
-
|
|
207
|
+
function hasNpmPublishRules(pkg) {
|
|
208
|
+
if (fs.existsSync(join(process.cwd(), '.npmignore'))) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
193
211
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const sourcePath = join(process.cwd(), relativePath);
|
|
197
|
-
const targetPath = join(stageDir, relativePath);
|
|
212
|
+
return Array.isArray(pkg.files) && pkg.files.length > 0;
|
|
213
|
+
}
|
|
198
214
|
|
|
199
|
-
|
|
200
|
-
|
|
215
|
+
function getDefaultPublishFiles() {
|
|
216
|
+
return DEFAULT_PUBLISH_FILES.filter(file => fs.existsSync(join(process.cwd(), file)));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function warnDefaultPublishState(pkg, publishFiles) {
|
|
220
|
+
const hasLibDir = fs.existsSync(join(process.cwd(), 'lib'));
|
|
221
|
+
const mainField = typeof pkg.main === 'string' ? pkg.main : '';
|
|
222
|
+
|
|
223
|
+
if (!hasLibDir && mainField.startsWith('./lib/')) {
|
|
224
|
+
console.warn(`警告: 缺少 lib/ 目录,但 package.json main 指向 ${mainField},将继续发布`);
|
|
201
225
|
}
|
|
202
226
|
|
|
203
|
-
|
|
227
|
+
if (publishFiles.length === 0) {
|
|
228
|
+
console.warn('警告: 默认发布规则下没有匹配到任何文件');
|
|
229
|
+
}
|
|
204
230
|
}
|
|
205
231
|
|
|
206
|
-
function
|
|
207
|
-
const publishDir = fs.mkdtempSync(join(os.tmpdir(), 'alemon-
|
|
232
|
+
function copyPublishFiles(files) {
|
|
233
|
+
const publishDir = fs.mkdtempSync(join(os.tmpdir(), 'alemon-publish-'));
|
|
208
234
|
|
|
209
235
|
for (const item of files) {
|
|
210
|
-
const relativePath = item.path;
|
|
211
|
-
const sourcePath = join(
|
|
236
|
+
const relativePath = typeof item === 'string' ? item : item.path;
|
|
237
|
+
const sourcePath = join(process.cwd(), relativePath);
|
|
212
238
|
const targetPath = join(publishDir, relativePath);
|
|
213
239
|
|
|
240
|
+
if (!fs.existsSync(sourcePath)) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (fs.statSync(sourcePath).isDirectory()) {
|
|
245
|
+
fs.mkdirSync(join(targetPath, '..'), { recursive: true });
|
|
246
|
+
fs.cpSync(sourcePath, targetPath, { recursive: true });
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
|
|
214
250
|
fs.mkdirSync(join(targetPath, '..'), { recursive: true });
|
|
215
251
|
fs.copyFileSync(sourcePath, targetPath);
|
|
216
252
|
}
|
|
@@ -240,6 +276,22 @@ function ensureGitRepo() {
|
|
|
240
276
|
}
|
|
241
277
|
}
|
|
242
278
|
|
|
279
|
+
function getLatestReleaseVersion() {
|
|
280
|
+
const tags = getCommandOutput('git tag --list --sort=-v:refname');
|
|
281
|
+
if (!tags) {
|
|
282
|
+
return '';
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
for (const tag of tags.split('\n')) {
|
|
286
|
+
const value = tag.trim();
|
|
287
|
+
if (TAG_RE.test(value)) {
|
|
288
|
+
return value.slice(1);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return '';
|
|
293
|
+
}
|
|
294
|
+
|
|
243
295
|
function remoteBranchExists(branch) {
|
|
244
296
|
const result = spawnSync('git', ['ls-remote', '--exit-code', '--heads', 'origin', branch], {
|
|
245
297
|
cwd: process.cwd(),
|
|
@@ -296,7 +348,7 @@ export async function publish(release, options = {}) {
|
|
|
296
348
|
|
|
297
349
|
const { pkgPath, pkg } = readPackageJson();
|
|
298
350
|
const packageName = pkg.name;
|
|
299
|
-
const localVersion = String(pkg.version || '').trim();
|
|
351
|
+
const localVersion = normalizeVersionInput(String(pkg.version || '').trim());
|
|
300
352
|
|
|
301
353
|
if (!packageName) {
|
|
302
354
|
throw new Error('package.json 缺少 name');
|
|
@@ -312,7 +364,7 @@ export async function publish(release, options = {}) {
|
|
|
312
364
|
ensureGitRepo();
|
|
313
365
|
|
|
314
366
|
const releaseBranch = options.branch || 'release';
|
|
315
|
-
const remoteVersion =
|
|
367
|
+
const remoteVersion = getLatestReleaseVersion();
|
|
316
368
|
if (remoteVersion) {
|
|
317
369
|
console.log(`最新 git tag: v${remoteVersion}`);
|
|
318
370
|
} else {
|
|
@@ -323,9 +375,9 @@ export async function publish(release, options = {}) {
|
|
|
323
375
|
ensureCleanGit();
|
|
324
376
|
}
|
|
325
377
|
|
|
326
|
-
const
|
|
327
|
-
const
|
|
328
|
-
const gitTagName =
|
|
378
|
+
const preid = validatePreid(options.preid);
|
|
379
|
+
const targetVersion = resolveTargetVersion(localVersion, remoteVersion, release, preid);
|
|
380
|
+
const gitTagName = `v${targetVersion}`;
|
|
329
381
|
console.log(`目标版本: ${targetVersion}`);
|
|
330
382
|
console.log(`发布分支: ${releaseBranch}`);
|
|
331
383
|
console.log(`git 标签: ${gitTagName}`);
|
|
@@ -335,7 +387,6 @@ export async function publish(release, options = {}) {
|
|
|
335
387
|
console.log(`已更新 package.json 版本: ${localVersion} -> ${targetVersion}`);
|
|
336
388
|
}
|
|
337
389
|
|
|
338
|
-
let stageDir = null;
|
|
339
390
|
let publishDir = null;
|
|
340
391
|
let worktreeDir = null;
|
|
341
392
|
try {
|
|
@@ -350,15 +401,23 @@ export async function publish(release, options = {}) {
|
|
|
350
401
|
console.log('已跳过构建');
|
|
351
402
|
}
|
|
352
403
|
|
|
353
|
-
const
|
|
354
|
-
|
|
404
|
+
const useNpmRules = hasNpmPublishRules(pkg);
|
|
405
|
+
const publishFiles = useNpmRules ? getPackResult().files : getDefaultPublishFiles();
|
|
355
406
|
|
|
356
|
-
|
|
357
|
-
|
|
407
|
+
if (!useNpmRules) {
|
|
408
|
+
warnDefaultPublishState(pkg, publishFiles);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
publishDir = copyPublishFiles(publishFiles);
|
|
358
412
|
|
|
359
|
-
console.log(
|
|
413
|
+
console.log(`发布规则: ${useNpmRules ? 'npm' : 'default'}`);
|
|
414
|
+
console.log(`发布文件数: ${publishFiles.length}`);
|
|
360
415
|
|
|
361
416
|
if (options.dryRun) {
|
|
417
|
+
if (targetVersion !== localVersion) {
|
|
418
|
+
updateVersion(pkgPath, pkg, localVersion);
|
|
419
|
+
console.log(`已回滚 package.json 版本到 ${localVersion}`);
|
|
420
|
+
}
|
|
362
421
|
console.log('dry-run 模式,不会真正推送到 git');
|
|
363
422
|
return;
|
|
364
423
|
}
|
|
@@ -388,9 +447,6 @@ export async function publish(release, options = {}) {
|
|
|
388
447
|
}
|
|
389
448
|
throw error;
|
|
390
449
|
} finally {
|
|
391
|
-
if (stageDir) {
|
|
392
|
-
fs.rmSync(stageDir, { recursive: true, force: true });
|
|
393
|
-
}
|
|
394
450
|
if (publishDir) {
|
|
395
451
|
fs.rmSync(publishDir, { recursive: true, force: true });
|
|
396
452
|
}
|
|
@@ -15,6 +15,11 @@ import { normalizeInboundMessage } from '../../../../common/cbp/normalize.js';
|
|
|
15
15
|
import { apiRequestResolves, apiRequestTimeouts, actionRequestResolves, actionRequestTimeouts } from '../processor/request-registry.js';
|
|
16
16
|
import { setDirectSend } from '../processor/transport.js';
|
|
17
17
|
|
|
18
|
+
const notifyTransportReady = (transport) => {
|
|
19
|
+
if (typeof process.send === 'function') {
|
|
20
|
+
process.send({ type: 'transport_ready', protocolVersion: 'v2', transport });
|
|
21
|
+
}
|
|
22
|
+
};
|
|
18
23
|
const handleInboundMessage = (message) => {
|
|
19
24
|
const normalized = normalizeInboundMessage(message);
|
|
20
25
|
if (!normalized) {
|
|
@@ -72,6 +77,7 @@ const cbpClientDirect = (sockPath, open) => {
|
|
|
72
77
|
})
|
|
73
78
|
.then(channel => {
|
|
74
79
|
setDirectSend(channel.send);
|
|
80
|
+
notifyTransportReady('direct');
|
|
75
81
|
open();
|
|
76
82
|
logger.debug({
|
|
77
83
|
code: ResultCode.Ok,
|
|
@@ -104,6 +110,7 @@ const cbpClientIPC = (open) => {
|
|
|
104
110
|
});
|
|
105
111
|
}
|
|
106
112
|
});
|
|
113
|
+
notifyTransportReady('ipc');
|
|
107
114
|
open();
|
|
108
115
|
logger.debug({
|
|
109
116
|
code: ResultCode.Ok,
|
|
@@ -128,7 +135,10 @@ const cbpClient = (url, options = {}) => {
|
|
|
128
135
|
extraHeaders: {
|
|
129
136
|
[FULL_RECEIVE_HEADER]: isFullReceive ? '1' : '0'
|
|
130
137
|
},
|
|
131
|
-
onOpen:
|
|
138
|
+
onOpen: () => {
|
|
139
|
+
notifyTransportReady('ws');
|
|
140
|
+
open();
|
|
141
|
+
},
|
|
132
142
|
onMessage: (messageStr) => {
|
|
133
143
|
try {
|
|
134
144
|
const parsedMessage = flattedJSON.parse(messageStr);
|
|
@@ -28,7 +28,8 @@ import { dispatchDisposeAllApps } from './lifecycle-callbacks.js';
|
|
|
28
28
|
|
|
29
29
|
global.__client_loaded = true;
|
|
30
30
|
let runtimeDisposed = false;
|
|
31
|
-
|
|
31
|
+
let runtimeStarted = false;
|
|
32
|
+
const disposeClientRuntime = async () => {
|
|
32
33
|
if (runtimeDisposed) {
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
@@ -40,11 +41,6 @@ const disposeRuntime = async () => {
|
|
|
40
41
|
unregisterAppDir(app.name);
|
|
41
42
|
});
|
|
42
43
|
};
|
|
43
|
-
const shutdown = async (reason) => {
|
|
44
|
-
logger.info?.(`[alemonjs][${reason}] 收到信号,正在关闭...`);
|
|
45
|
-
await disposeRuntime();
|
|
46
|
-
process.exit(0);
|
|
47
|
-
};
|
|
48
44
|
const mainServer = () => {
|
|
49
45
|
const port = process.env.serverPort;
|
|
50
46
|
if (!port) {
|
|
@@ -68,37 +64,19 @@ const main = () => {
|
|
|
68
64
|
else {
|
|
69
65
|
cbpClient(`http://127.0.0.1:${port}`, { isFullReceive });
|
|
70
66
|
}
|
|
71
|
-
loadModels();
|
|
72
67
|
};
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
83
|
-
process?.on?.('exit', code => {
|
|
84
|
-
void disposeRuntime();
|
|
85
|
-
logger.info?.(`[alemonjs][exit] 进程退出,code=${code}`);
|
|
86
|
-
});
|
|
87
|
-
process.on('message', msg => {
|
|
88
|
-
try {
|
|
89
|
-
const data = typeof msg === 'string' ? JSON.parse(msg) : msg;
|
|
90
|
-
if (data?.type === 'start') {
|
|
91
|
-
main();
|
|
92
|
-
mainServer();
|
|
93
|
-
}
|
|
94
|
-
else if (data?.type === 'stop') {
|
|
95
|
-
void shutdown('stop');
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
catch { }
|
|
99
|
-
});
|
|
68
|
+
const startClientRuntime = async () => {
|
|
69
|
+
if (runtimeStarted) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
runtimeStarted = true;
|
|
73
|
+
runtimeDisposed = false;
|
|
74
|
+
main();
|
|
75
|
+
mainServer();
|
|
76
|
+
await loadModels();
|
|
100
77
|
if (process.send) {
|
|
101
|
-
process.send({ type: '
|
|
78
|
+
process.send({ type: 'app_ready', protocolVersion: 'v2' });
|
|
102
79
|
}
|
|
103
80
|
};
|
|
104
|
-
|
|
81
|
+
|
|
82
|
+
export { disposeClientRuntime, startClientRuntime };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const run: (input: string) => void
|
|
2
|
-
export declare function loadModels(): void
|
|
1
|
+
export declare const run: (input: string) => Promise<void>;
|
|
2
|
+
export declare function loadModels(): Promise<void>;
|
|
@@ -13,7 +13,7 @@ const loadApps = () => {
|
|
|
13
13
|
.filter(([, enabled]) => Boolean(enabled))
|
|
14
14
|
.map(([name]) => name);
|
|
15
15
|
const uniqueApps = Array.from(new Set(apps));
|
|
16
|
-
uniqueApps.
|
|
16
|
+
return Promise.all(uniqueApps.map(async (app) => {
|
|
17
17
|
registerRuntimeApp({
|
|
18
18
|
name: app,
|
|
19
19
|
kind: 'plugin',
|
|
@@ -22,10 +22,10 @@ const loadApps = () => {
|
|
|
22
22
|
rootDir: '',
|
|
23
23
|
mainPath: ''
|
|
24
24
|
});
|
|
25
|
-
|
|
26
|
-
});
|
|
25
|
+
await loadChildrenFile(app);
|
|
26
|
+
}));
|
|
27
27
|
};
|
|
28
|
-
const run = (input) => {
|
|
28
|
+
const run = async (input) => {
|
|
29
29
|
if (!input) {
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
@@ -46,12 +46,12 @@ const run = (input) => {
|
|
|
46
46
|
rootDir: join(process.cwd(), dirname(input)),
|
|
47
47
|
mainPath
|
|
48
48
|
});
|
|
49
|
-
|
|
49
|
+
await loadChildren(mainPath, 'main');
|
|
50
50
|
};
|
|
51
|
-
function loadModels() {
|
|
51
|
+
async function loadModels() {
|
|
52
52
|
const input = process.env.input ?? '';
|
|
53
|
-
run(input);
|
|
54
|
-
loadApps();
|
|
53
|
+
await run(input);
|
|
54
|
+
await loadApps();
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
export { loadModels, run };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const loadChildren: (mainPath: string, appName: string) => Promise<void>;
|
|
2
|
-
export declare const loadChildrenFile: (appName: string) => void
|
|
2
|
+
export declare const loadChildrenFile: (appName: string) => Promise<void>;
|
|
@@ -287,7 +287,7 @@ const loadChildren = async (mainPath, appName) => {
|
|
|
287
287
|
App.un();
|
|
288
288
|
}
|
|
289
289
|
};
|
|
290
|
-
const loadChildrenFile = (appName) => {
|
|
290
|
+
const loadChildrenFile = async (appName) => {
|
|
291
291
|
if (typeof appName !== 'string') {
|
|
292
292
|
logger.error({
|
|
293
293
|
code: ResultCode.FailParams,
|
|
@@ -322,7 +322,7 @@ const loadChildrenFile = (appName) => {
|
|
|
322
322
|
rootDir: dirname(mainPath),
|
|
323
323
|
mainPath
|
|
324
324
|
});
|
|
325
|
-
|
|
325
|
+
await loadChildren(mainPath, appName);
|
|
326
326
|
}
|
|
327
327
|
catch (e) {
|
|
328
328
|
const packageDir = resolvePackageDir(appName);
|
|
@@ -336,7 +336,7 @@ const loadChildrenFile = (appName) => {
|
|
|
336
336
|
rootDir: dirname(fallbackMainPath),
|
|
337
337
|
mainPath: fallbackMainPath
|
|
338
338
|
});
|
|
339
|
-
|
|
339
|
+
await loadChildren(fallbackMainPath, appName);
|
|
340
340
|
return;
|
|
341
341
|
}
|
|
342
342
|
updateRuntimeAppStatus(appName, 'failed', e);
|
package/lib/client.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
package/lib/client.js
CHANGED
|
@@ -1 +1,91 @@
|
|
|
1
|
-
import './
|
|
1
|
+
import { logger } from './common/logger.js';
|
|
2
|
+
|
|
3
|
+
let runtimeModulePromise = null;
|
|
4
|
+
let runtimeStarted = false;
|
|
5
|
+
let stopping = false;
|
|
6
|
+
const notifyParent = (message) => {
|
|
7
|
+
if (typeof process.send === 'function') {
|
|
8
|
+
process.send(message);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const normalizeError = (error) => {
|
|
12
|
+
if (error instanceof Error) {
|
|
13
|
+
return {
|
|
14
|
+
message: error.message,
|
|
15
|
+
stack: error.stack
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
message: typeof error === 'string' ? error : 'Unknown client bootstrap error'
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const loadRuntimeModule = async () => {
|
|
23
|
+
runtimeModulePromise ??= import('./application/runtime/client-runtime.js');
|
|
24
|
+
return runtimeModulePromise;
|
|
25
|
+
};
|
|
26
|
+
const shutdown = async (reason) => {
|
|
27
|
+
if (stopping) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
stopping = true;
|
|
31
|
+
logger.info?.(`[client-bootstrap][${reason}] 收到信号,正在关闭...`);
|
|
32
|
+
try {
|
|
33
|
+
const runtimeModule = runtimeModulePromise ? await runtimeModulePromise : null;
|
|
34
|
+
if (runtimeModule?.disposeClientRuntime) {
|
|
35
|
+
await runtimeModule.disposeClientRuntime();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logger.error?.('[client-bootstrap] 关闭失败', error);
|
|
40
|
+
}
|
|
41
|
+
process.exit(0);
|
|
42
|
+
};
|
|
43
|
+
const startRuntime = async () => {
|
|
44
|
+
if (runtimeStarted) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
runtimeStarted = true;
|
|
48
|
+
try {
|
|
49
|
+
const runtimeModule = await loadRuntimeModule();
|
|
50
|
+
if (typeof runtimeModule.startClientRuntime !== 'function') {
|
|
51
|
+
throw new Error('Client runtime missing startClientRuntime');
|
|
52
|
+
}
|
|
53
|
+
await runtimeModule.startClientRuntime();
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
notifyParent({
|
|
57
|
+
type: 'boot_error',
|
|
58
|
+
protocolVersion: 'v2',
|
|
59
|
+
stage: 'app',
|
|
60
|
+
error: normalizeError(error)
|
|
61
|
+
});
|
|
62
|
+
logger.error?.('[client-bootstrap] 启动失败', error);
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
setImmediate(() => process.exit(1));
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
process.on('unhandledRejection', (reason) => {
|
|
68
|
+
logger.error?.('[client-bootstrap][unhandledRejection]', reason);
|
|
69
|
+
});
|
|
70
|
+
process.on('uncaughtException', (error) => {
|
|
71
|
+
logger.error?.('[client-bootstrap][uncaughtException]', error);
|
|
72
|
+
});
|
|
73
|
+
['SIGINT', 'SIGTERM', 'SIGQUIT', 'disconnect'].forEach(sig => {
|
|
74
|
+
process?.on?.(sig, () => void shutdown(sig));
|
|
75
|
+
});
|
|
76
|
+
process?.on?.('exit', code => {
|
|
77
|
+
logger.info?.(`[client-bootstrap][exit] 进程退出,code=${code}`);
|
|
78
|
+
});
|
|
79
|
+
process.on('message', msg => {
|
|
80
|
+
try {
|
|
81
|
+
const data = typeof msg === 'string' ? JSON.parse(msg) : msg;
|
|
82
|
+
if (data?.type === 'start') {
|
|
83
|
+
void startRuntime();
|
|
84
|
+
}
|
|
85
|
+
else if (data?.type === 'stop') {
|
|
86
|
+
void shutdown('stop');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch { }
|
|
90
|
+
});
|
|
91
|
+
notifyParent({ type: 'ready', protocolVersion: 'v2' });
|
package/lib/core/index.d.ts
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
1
|
export { start } from './start.js';
|
|
2
|
+
export { startModuleAdapter, restartModuleAdapter, getModuleAdapterState } from './process/module.js';
|
|
3
|
+
export { startPlatformAdapterWithFallback, restartPlatformAdapter, getPlatformAdapterState } from './process/platform.js';
|
|
4
|
+
export type { ProcessAdapterState, AdapterPhase, AdapterProtocolVersion, AdapterTransportMode, AdapterBootTimings } from './process/types.js';
|
package/lib/core/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { startModuleAdapter } from './module.js';
|
|
2
|
-
export { startPlatformAdapterWithFallback } from './platform.js';
|
|
1
|
+
export { getModuleAdapterState, restartModuleAdapter, startModuleAdapter } from './module.js';
|
|
2
|
+
export { getPlatformAdapterState, restartPlatformAdapter, startPlatformAdapterWithFallback } from './platform.js';
|
|
3
3
|
export { forwardFromClient, forwardFromPlatform, getClientChild, getPlatformChild, setClientChild, setPlatformChild } from './ipc-bridge.js';
|
|
@@ -27,6 +27,12 @@ const forwardFromPlatform = (data) => {
|
|
|
27
27
|
if (clientChild?.connected) {
|
|
28
28
|
clientChild.send({ type: 'ipc:data', data: safeData });
|
|
29
29
|
}
|
|
30
|
+
else if (process.env.NODE_ENV === 'development') {
|
|
31
|
+
logger.debug?.({
|
|
32
|
+
message: 'skip forwarding platform message before client transport ready',
|
|
33
|
+
data: null
|
|
34
|
+
});
|
|
35
|
+
}
|
|
30
36
|
if (fullClient.size > 0) {
|
|
31
37
|
try {
|
|
32
38
|
const messageStr = flattedJSON.stringify(safeData);
|
|
@@ -48,6 +54,12 @@ const forwardFromClient = (data) => {
|
|
|
48
54
|
if (platformChild?.connected) {
|
|
49
55
|
platformChild.send({ type: 'ipc:data', data: safeData });
|
|
50
56
|
}
|
|
57
|
+
else if (process.env.NODE_ENV === 'development') {
|
|
58
|
+
logger.debug?.({
|
|
59
|
+
message: 'skip forwarding client message before platform transport ready',
|
|
60
|
+
data: null
|
|
61
|
+
});
|
|
62
|
+
}
|
|
51
63
|
if (global.__sandbox && global.testoneClient) {
|
|
52
64
|
try {
|
|
53
65
|
const normalized = normalizeInboundMessage(safeData);
|