@mearl/cloud-server 2.9.5 → 2.10.0
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/README.md +8 -0
- package/dist/bin.d.ts +2 -0
- package/dist/chunks/{chunk-DCTZIDJ7.js → chunk-AFZKMZDL.js} +31 -8
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +11 -18
- package/dist/index.js +1 -1
- package/dist/sandbox.d.ts +6 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ npx @mearl/setup --qoder-cloud --yes
|
|
|
23
23
|
### 命令行方式
|
|
24
24
|
|
|
25
25
|
Server **默认以后台守护进程方式运行**,启动后立即返回,并打印本地机器需要执行的连接命令。
|
|
26
|
+
POSIX 环境下后台进程会进入独立 session,可在启动命令结束后继续运行。
|
|
26
27
|
Qoder 模式保持相同的 `start/status/restart/stop/logs` 交互;`start` 和 `restart` 生成新的
|
|
27
28
|
pair/connector 信息后退出,不监听端口或创建守护进程。
|
|
28
29
|
|
|
@@ -94,6 +95,13 @@ mearl-cloud-server --foreground
|
|
|
94
95
|
|
|
95
96
|
- `MEARL_TOKEN` - 鉴权密钥(覆盖 --token 选项)
|
|
96
97
|
- `CLOUD_SERVER_HOST` - 公网主机名(默认自动获取)
|
|
98
|
+
- `OPENSANDBOX_ID` - 非空时启用 OpenSandbox 环境自适应
|
|
99
|
+
- `AONE_SANDBOX_ENDPOINT_TEMPLATE` - OpenSandbox 注入的入口模板;必须包含 `{port}`,server 会用 connector 端口替换并生成 `wss://` 连接地址
|
|
100
|
+
|
|
101
|
+
OpenSandbox 中 connector listener 会绑定 `0.0.0.0`,公开地址以平台注入的 endpoint
|
|
102
|
+
template 为准,不会从容器 hostname 推导路由前缀。
|
|
103
|
+
OpenSandbox 与通过 `AONE_SANDBOX_ID` 及本地端口映射接口识别的 AONE Sandbox
|
|
104
|
+
是两种独立环境,server 会分别选择对应的入口解析方式。
|
|
97
105
|
|
|
98
106
|
### 编程方式
|
|
99
107
|
|
package/dist/bin.d.ts
ADDED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import WebSocket, { WebSocketServer } from "ws";
|
|
3
3
|
import { createServer as createHttpServer } from "node:http";
|
|
4
|
-
import { chmodSync
|
|
4
|
+
import { chmodSync } from "node:fs";
|
|
5
5
|
import { randomBytes } from "node:crypto";
|
|
6
6
|
import { networkInterfaces } from "node:os";
|
|
7
|
+
import { writeRecord } from "@mearl/daemon-core";
|
|
7
8
|
|
|
8
9
|
// src/paths.ts
|
|
9
10
|
import { join } from "node:path";
|
|
@@ -13,6 +14,25 @@ var CONFIG_FILE = join(CONFIG_DIR, "cloud-server.json");
|
|
|
13
14
|
var MODE_FILE = join(CONFIG_DIR, "cloud-server-mode.json");
|
|
14
15
|
var LOG_FILE = join(CONFIG_DIR, "cloud-server.log");
|
|
15
16
|
|
|
17
|
+
// src/sandbox.ts
|
|
18
|
+
var PORT_PLACEHOLDER = "{port}";
|
|
19
|
+
function resolveOpenSandboxEndpoint(port, env = process.env) {
|
|
20
|
+
if (!env.OPENSANDBOX_ID?.trim()) return null;
|
|
21
|
+
const template = env.AONE_SANDBOX_ENDPOINT_TEMPLATE?.trim();
|
|
22
|
+
if (!template?.includes(PORT_PLACEHOLDER)) return null;
|
|
23
|
+
const rendered = template.replaceAll(PORT_PLACEHOLDER, String(port));
|
|
24
|
+
const endpoint = /^[a-z][a-z\d+.-]*:\/\//i.test(rendered) ? rendered : `https://${rendered}`;
|
|
25
|
+
try {
|
|
26
|
+
const parsed = new URL(endpoint);
|
|
27
|
+
if (!["http:", "https:", "ws:", "wss:"].includes(parsed.protocol) || !parsed.hostname) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return parsed.toString();
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
16
36
|
// src/index.ts
|
|
17
37
|
import {
|
|
18
38
|
isAgentHelloMessage,
|
|
@@ -484,6 +504,15 @@ var CloudServer = class {
|
|
|
484
504
|
return "localhost";
|
|
485
505
|
}
|
|
486
506
|
async getSandboxPublicUrl(port) {
|
|
507
|
+
if (process.env.OPENSANDBOX_ID?.trim()) {
|
|
508
|
+
const endpoint = resolveOpenSandboxEndpoint(port);
|
|
509
|
+
if (!endpoint) {
|
|
510
|
+
console.warn(
|
|
511
|
+
"[CloudServer] OpenSandbox detected, but AONE_SANDBOX_ENDPOINT_TEMPLATE is missing, invalid, or does not contain {port}."
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
return endpoint;
|
|
515
|
+
}
|
|
487
516
|
if (!process.env.AONE_SANDBOX_ID) {
|
|
488
517
|
return null;
|
|
489
518
|
}
|
|
@@ -507,14 +536,8 @@ var CloudServer = class {
|
|
|
507
536
|
}
|
|
508
537
|
writeConfigFile(info) {
|
|
509
538
|
try {
|
|
510
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
511
|
-
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
512
|
-
}
|
|
513
539
|
const config = { server: info.localUrl, ...info };
|
|
514
|
-
|
|
515
|
-
encoding: "utf-8",
|
|
516
|
-
mode: 384
|
|
517
|
-
});
|
|
540
|
+
writeRecord(CONFIG_FILE, config);
|
|
518
541
|
if (process.platform !== "win32") {
|
|
519
542
|
chmodSync(CONFIG_DIR, 448);
|
|
520
543
|
chmodSync(CONFIG_FILE, 384);
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -4,16 +4,14 @@ import {
|
|
|
4
4
|
CloudServer,
|
|
5
5
|
LOG_FILE,
|
|
6
6
|
MODE_FILE
|
|
7
|
-
} from "./chunks/chunk-
|
|
7
|
+
} from "./chunks/chunk-AFZKMZDL.js";
|
|
8
8
|
|
|
9
9
|
// src/cli.ts
|
|
10
|
-
import path from "node:path";
|
|
11
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
12
10
|
import { Command, CommanderError, InvalidArgumentError } from "commander";
|
|
13
11
|
|
|
14
12
|
// src/daemon.ts
|
|
15
13
|
import { fileURLToPath } from "node:url";
|
|
16
|
-
import { createDaemon, readRecord,
|
|
14
|
+
import { createDaemon, readRecord, removeRecordIfPid } from "@mearl/daemon-core";
|
|
17
15
|
var SCRIPT_PATH = fileURLToPath(import.meta.url);
|
|
18
16
|
function formatConnectInfo(record) {
|
|
19
17
|
const config = record;
|
|
@@ -71,7 +69,7 @@ async function runForeground(options) {
|
|
|
71
69
|
console.log(`
|
|
72
70
|
[CloudServer] Received ${signal}, shutting down...`);
|
|
73
71
|
await server.stop();
|
|
74
|
-
|
|
72
|
+
removeRecordIfPid(CONFIG_FILE, process.pid);
|
|
75
73
|
process.exit(0);
|
|
76
74
|
};
|
|
77
75
|
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
@@ -178,7 +176,7 @@ async function runQoderCloudServerCommand(command, dependencies) {
|
|
|
178
176
|
}
|
|
179
177
|
|
|
180
178
|
// src/cli.ts
|
|
181
|
-
var CLOUD_SERVER_VERSION = true ? "2.
|
|
179
|
+
var CLOUD_SERVER_VERSION = true ? "2.10.0" : "unknown";
|
|
182
180
|
var COMMANDS = ["start", "stop", "restart", "status", "logs"];
|
|
183
181
|
var START_OPTION_NAMES = /* @__PURE__ */ new Set([
|
|
184
182
|
"foreground",
|
|
@@ -355,16 +353,11 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
355
353
|
}
|
|
356
354
|
return 0;
|
|
357
355
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
});
|
|
356
|
+
|
|
357
|
+
// src/bin.ts
|
|
358
|
+
try {
|
|
359
|
+
process.exitCode = await main();
|
|
360
|
+
} catch (error) {
|
|
361
|
+
console.error("[CloudServer] Fatal error:", error);
|
|
362
|
+
process.exitCode = 1;
|
|
366
363
|
}
|
|
367
|
-
export {
|
|
368
|
-
main,
|
|
369
|
-
parseCloudServerArgs
|
|
370
|
-
};
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the ingress endpoint injected into an OpenSandbox environment.
|
|
3
|
+
* The template is authoritative because its routing prefix cannot be derived
|
|
4
|
+
* from the container hostname.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveOpenSandboxEndpoint(port: number, env?: NodeJS.ProcessEnv): string | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mearl/cloud-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"description": "Cloud WebSocket server for Mearl — bridges cloud agents to local connectors",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"commander": "^15.0.0",
|
|
37
37
|
"ws": "^8.18.0",
|
|
38
|
-
"@mearl/
|
|
39
|
-
"@mearl/
|
|
40
|
-
"@mearl/daemon-core": "2.
|
|
38
|
+
"@mearl/client": "2.10.0",
|
|
39
|
+
"@mearl/cloud-types": "2.10.0",
|
|
40
|
+
"@mearl/daemon-core": "2.10.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^24.9.1",
|