@sfmc-bds/cli 0.2.0-beta.8 → 0.2.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/LICENSE +663 -0
- package/README.md +4 -5
- package/dist/bds-runtime-version.d.ts +3 -0
- package/dist/bds-runtime-version.d.ts.map +1 -0
- package/dist/bds-runtime-version.js +15 -0
- package/dist/bds-runtime-version.js.map +7 -0
- package/dist/command-surface.js +3 -3
- package/dist/command-surface.js.map +2 -2
- package/dist/commands.d.ts +57 -4
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +184 -68
- package/dist/commands.js.map +2 -2
- package/dist/directory-picker.d.ts +27 -0
- package/dist/directory-picker.d.ts.map +1 -0
- package/dist/directory-picker.js +112 -0
- package/dist/directory-picker.js.map +7 -0
- package/dist/help-text.d.ts.map +1 -1
- package/dist/help-text.js +1 -5
- package/dist/help-text.js.map +2 -2
- package/dist/i18n/locales/en.d.ts +49 -14
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +49 -15
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
- package/dist/i18n/locales/zh-CN.js +50 -16
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +2 -2
- package/dist/interactive-prompts.d.ts +1 -2
- package/dist/interactive-prompts.d.ts.map +1 -1
- package/dist/interactive-prompts.js +12 -23
- package/dist/interactive-prompts.js.map +3 -3
- package/dist/llbot-launch.d.ts +20 -0
- package/dist/llbot-launch.d.ts.map +1 -0
- package/dist/llbot-launch.js +40 -0
- package/dist/llbot-launch.js.map +7 -0
- package/dist/log-filter.d.ts +18 -2
- package/dist/log-filter.d.ts.map +1 -1
- package/dist/log-filter.js +54 -4
- package/dist/log-filter.js.map +2 -2
- package/dist/log-translator.d.ts +36 -0
- package/dist/log-translator.d.ts.map +1 -0
- package/dist/log-translator.js +279 -0
- package/dist/log-translator.js.map +7 -0
- package/dist/logs.d.ts +2 -0
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +24 -11
- package/dist/logs.js.map +2 -2
- package/dist/main.js +9 -6
- package/dist/main.js.map +2 -2
- package/dist/module-commands.d.ts.map +1 -1
- package/dist/module-commands.js +22 -8
- package/dist/module-commands.js.map +2 -2
- package/dist/module-fingerprint.d.ts.map +1 -1
- package/dist/module-fingerprint.js +1 -0
- package/dist/module-fingerprint.js.map +2 -2
- package/dist/module-pack-build.d.ts +14 -4
- package/dist/module-pack-build.d.ts.map +1 -1
- package/dist/module-pack-build.js +81 -108
- package/dist/module-pack-build.js.map +2 -2
- package/dist/module-toggle.d.ts +1 -1
- package/dist/module-toggle.d.ts.map +1 -1
- package/dist/module-toggle.js.map +1 -1
- package/dist/node-service-probe.d.ts +18 -0
- package/dist/node-service-probe.d.ts.map +1 -0
- package/dist/node-service-probe.js +97 -0
- package/dist/node-service-probe.js.map +7 -0
- package/dist/pack-lifecycle.d.ts +15 -1
- package/dist/pack-lifecycle.d.ts.map +1 -1
- package/dist/pack-lifecycle.js +249 -16
- package/dist/pack-lifecycle.js.map +2 -2
- package/dist/player-session.d.ts +13 -0
- package/dist/player-session.d.ts.map +1 -0
- package/dist/player-session.js +26 -0
- package/dist/player-session.js.map +7 -0
- package/dist/registry.d.ts +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -1
- package/dist/registry.js.map +2 -2
- package/dist/repl-windows/format-display.d.ts.map +1 -1
- package/dist/repl-windows/format-display.js +5 -1
- package/dist/repl-windows/format-display.js.map +2 -2
- package/dist/repl-windows/host.d.ts +6 -3
- package/dist/repl-windows/host.d.ts.map +1 -1
- package/dist/repl-windows/host.js +12 -6
- package/dist/repl-windows/host.js.map +2 -2
- package/dist/repl-windows/index.d.ts +1 -0
- package/dist/repl-windows/index.d.ts.map +1 -1
- package/dist/repl-windows/index.js +3 -0
- package/dist/repl-windows/index.js.map +2 -2
- package/dist/repl-windows/service-window.d.ts +1 -1
- package/dist/repl-windows/service-window.d.ts.map +1 -1
- package/dist/repl-windows/service-window.js +9 -1
- package/dist/repl-windows/service-window.js.map +2 -2
- package/dist/repl-windows/sfmc-window.d.ts +7 -0
- package/dist/repl-windows/sfmc-window.d.ts.map +1 -0
- package/dist/repl-windows/sfmc-window.js +28 -0
- package/dist/repl-windows/sfmc-window.js.map +7 -0
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +37 -22
- package/dist/repl.js.map +2 -2
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +15 -2
- package/dist/runtime.js.map +2 -2
- package/dist/send-target.d.ts +2 -0
- package/dist/send-target.d.ts.map +1 -1
- package/dist/send-target.js +12 -2
- package/dist/send-target.js.map +2 -2
- package/dist/services.d.ts +58 -5
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +273 -50
- package/dist/services.js.map +2 -2
- package/dist/sfmc-modules-root.d.ts.map +1 -1
- package/dist/sfmc-modules-root.js +6 -2
- package/dist/sfmc-modules-root.js.map +2 -2
- package/dist/ui-command.d.ts +6 -0
- package/dist/ui-command.d.ts.map +1 -0
- package/dist/ui-command.js +68 -0
- package/dist/ui-command.js.map +7 -0
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +95 -32
- package/dist/wizard.js.map +2 -2
- package/dist/world-packs.d.ts +2 -0
- package/dist/world-packs.d.ts.map +1 -1
- package/dist/world-packs.js +161 -18
- package/dist/world-packs.js.map +2 -2
- package/package.json +21 -15
- package/scripts/module-install/check-modules.mjs +178 -0
- package/scripts/module-install/fetch-module.mjs +1083 -0
- package/scripts/module-install/lib/catalog.mjs +96 -0
- package/scripts/module-install/lib/config-seeding.mjs +128 -0
- package/scripts/module-install/lib/io.mjs +37 -0
- package/scripts/module-install/lib/link-from.mjs +80 -0
- package/scripts/module-install/lib/lock.mjs +78 -0
- package/scripts/module-install/lib/npm-resolver.mjs +55 -0
- package/scripts/module-install/lib/packages.mjs +136 -0
- package/scripts/module-install/lib/paths.mjs +48 -0
- package/scripts/module-install/lib/registry-index.mjs +50 -0
- package/dist/cmd-remote.d.ts +0 -13
- package/dist/cmd-remote.d.ts.map +0 -1
- package/dist/cmd-remote.js +0 -38
- package/dist/cmd-remote.js.map +0 -7
- package/dist/remote-agent.d.ts +0 -18
- package/dist/remote-agent.d.ts.map +0 -1
- package/dist/remote-agent.js +0 -198
- package/dist/remote-agent.js.map +0 -7
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* 解析 Tanya7z/sfmc-modules index.json
|
|
4
|
+
*
|
|
5
|
+
* 契约(与 sfmc/src/registry.ts#parseRegistryIndex 保持一致):
|
|
6
|
+
* { modules: { <id>: { npm?, version?, sdk?, repo?, tag? } } }
|
|
7
|
+
* 条目至少具备 npm 或 repo+tag。`_` 前缀键视为元数据并忽略。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {{ npm?: string, version?: string, sdk?: string, repo?: string, tag?: string }} RegistryEntry
|
|
12
|
+
* @typedef {Record<string, RegistryEntry>} RegistryIndex
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {unknown} json
|
|
17
|
+
* @returns {RegistryIndex}
|
|
18
|
+
*/
|
|
19
|
+
export function parseRegistryIndex(json) {
|
|
20
|
+
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
|
21
|
+
throw new Error("registry index must be a JSON object with a 'modules' field");
|
|
22
|
+
}
|
|
23
|
+
const modules = /** @type {Record<string, unknown>} */ (json).modules;
|
|
24
|
+
if (typeof modules !== "object" || modules === null || Array.isArray(modules)) {
|
|
25
|
+
throw new Error("registry index must have a 'modules' object mapping id → entry");
|
|
26
|
+
}
|
|
27
|
+
/** @type {RegistryIndex} */
|
|
28
|
+
const filtered = {};
|
|
29
|
+
for (const [k, v] of Object.entries(modules)) {
|
|
30
|
+
if (k.startsWith("_")) continue;
|
|
31
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) continue;
|
|
32
|
+
const entry = /** @type {Record<string, unknown>} */ (v);
|
|
33
|
+
const hasNpm = typeof entry.npm === "string" && entry.npm.length > 0;
|
|
34
|
+
const hasGh = typeof entry.repo === "string" && typeof entry.tag === "string";
|
|
35
|
+
if (!hasNpm && !hasGh) continue;
|
|
36
|
+
/** @type {RegistryEntry} */
|
|
37
|
+
const out = {};
|
|
38
|
+
if (hasNpm) {
|
|
39
|
+
out.npm = /** @type {string} */ (entry.npm);
|
|
40
|
+
if (typeof entry.version === "string") out.version = entry.version;
|
|
41
|
+
if (typeof entry.sdk === "string") out.sdk = entry.sdk;
|
|
42
|
+
}
|
|
43
|
+
if (hasGh) {
|
|
44
|
+
out.repo = /** @type {string} */ (entry.repo);
|
|
45
|
+
out.tag = /** @type {string} */ (entry.tag);
|
|
46
|
+
}
|
|
47
|
+
filtered[k] = out;
|
|
48
|
+
}
|
|
49
|
+
return filtered;
|
|
50
|
+
}
|
package/dist/cmd-remote.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export type CmdRemoteOptions = {
|
|
2
|
-
/**
|
|
3
|
-
* enroll 成功后是否挂起进程(外壳 `sfmc remote enroll` 守护)。
|
|
4
|
-
* REPL 内应为 false,只启动 agent 后返回。
|
|
5
|
-
*/
|
|
6
|
-
daemonAfterEnroll?: boolean;
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* 执行 remote 子命令;返回要打印的文本。
|
|
10
|
-
* enroll+daemon 时本函数不返回(进程挂起)。
|
|
11
|
-
*/
|
|
12
|
-
export declare function cmdRemote(args: string[], opts?: CmdRemoteOptions): Promise<string>;
|
|
13
|
-
//# sourceMappingURL=cmd-remote.d.ts.map
|
package/dist/cmd-remote.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cmd-remote.d.ts","sourceRoot":"","sources":["../src/cmd-remote.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyB5F"}
|
package/dist/cmd-remote.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { t } from "./i18n/index.js";
|
|
2
|
-
import {
|
|
3
|
-
disableRemoteAgent,
|
|
4
|
-
enrollRemoteAgent,
|
|
5
|
-
remoteStatus,
|
|
6
|
-
startRemoteAgent,
|
|
7
|
-
stopRemoteAgent
|
|
8
|
-
} from "./remote-agent.js";
|
|
9
|
-
async function cmdRemote(args, opts = {}) {
|
|
10
|
-
const [subcommand, ...remoteArgs] = args;
|
|
11
|
-
if (subcommand === "enroll" && remoteArgs[0] && remoteArgs[1]) {
|
|
12
|
-
const name = remoteArgs[2] ?? process.env.COMPUTERNAME ?? "sfmc-agent";
|
|
13
|
-
const agentId = await enrollRemoteAgent(remoteArgs[0], remoteArgs[1], name);
|
|
14
|
-
startRemoteAgent();
|
|
15
|
-
if (opts.daemonAfterEnroll) {
|
|
16
|
-
const exit = () => {
|
|
17
|
-
stopRemoteAgent();
|
|
18
|
-
process.exit(0);
|
|
19
|
-
};
|
|
20
|
-
process.once("SIGINT", exit);
|
|
21
|
-
process.once("SIGTERM", exit);
|
|
22
|
-
await new Promise(() => void 0);
|
|
23
|
-
}
|
|
24
|
-
return t("remote.enrolled", { id: agentId });
|
|
25
|
-
}
|
|
26
|
-
if (subcommand === "status") {
|
|
27
|
-
return JSON.stringify(remoteStatus(), null, 2);
|
|
28
|
-
}
|
|
29
|
-
if (subcommand === "disable") {
|
|
30
|
-
disableRemoteAgent();
|
|
31
|
-
return t("remote.disabled");
|
|
32
|
-
}
|
|
33
|
-
return t("remote.usage");
|
|
34
|
-
}
|
|
35
|
-
export {
|
|
36
|
-
cmdRemote
|
|
37
|
-
};
|
|
38
|
-
//# sourceMappingURL=cmd-remote.js.map
|
package/dist/cmd-remote.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/cmd-remote.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * cmd-remote.ts \u2014 remote \u5B50\u547D\u4EE4\u8C03\u5EA6\uFF08main / REPL \u5171\u7528\uFF0C\u907F\u514D\u4E24\u5904\u590D\u5236\uFF09\n */\nimport { t } from \"./i18n/index.js\";\nimport {\n disableRemoteAgent,\n enrollRemoteAgent,\n remoteStatus,\n startRemoteAgent,\n stopRemoteAgent,\n} from \"./remote-agent.js\";\n\nexport type CmdRemoteOptions = {\n /**\n * enroll \u6210\u529F\u540E\u662F\u5426\u6302\u8D77\u8FDB\u7A0B\uFF08\u5916\u58F3 `sfmc remote enroll` \u5B88\u62A4\uFF09\u3002\n * REPL \u5185\u5E94\u4E3A false\uFF0C\u53EA\u542F\u52A8 agent \u540E\u8FD4\u56DE\u3002\n */\n daemonAfterEnroll?: boolean;\n};\n\n/**\n * \u6267\u884C remote \u5B50\u547D\u4EE4\uFF1B\u8FD4\u56DE\u8981\u6253\u5370\u7684\u6587\u672C\u3002\n * enroll+daemon \u65F6\u672C\u51FD\u6570\u4E0D\u8FD4\u56DE\uFF08\u8FDB\u7A0B\u6302\u8D77\uFF09\u3002\n */\nexport async function cmdRemote(args: string[], opts: CmdRemoteOptions = {}): Promise<string> {\n const [subcommand, ...remoteArgs] = args;\n if (subcommand === \"enroll\" && remoteArgs[0] && remoteArgs[1]) {\n const name = remoteArgs[2] ?? process.env.COMPUTERNAME ?? \"sfmc-agent\";\n const agentId = await enrollRemoteAgent(remoteArgs[0]!, remoteArgs[1]!, name);\n startRemoteAgent();\n if (opts.daemonAfterEnroll) {\n const exit = (): void => {\n stopRemoteAgent();\n process.exit(0);\n };\n process.once(\"SIGINT\", exit);\n process.once(\"SIGTERM\", exit);\n await new Promise(() => undefined);\n }\n return t(\"remote.enrolled\", { id: agentId });\n }\n if (subcommand === \"status\") {\n return JSON.stringify(remoteStatus(), null, 2);\n }\n if (subcommand === \"disable\") {\n disableRemoteAgent();\n return t(\"remote.disabled\");\n }\n return t(\"remote.usage\");\n}\n"],
|
|
5
|
-
"mappings": "AAGA,SAAS,SAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAcP,eAAsB,UAAU,MAAgB,OAAyB,CAAC,GAAoB;AAC5F,QAAM,CAAC,YAAY,GAAG,UAAU,IAAI;AACpC,MAAI,eAAe,YAAY,WAAW,CAAC,KAAK,WAAW,CAAC,GAAG;AAC7D,UAAM,OAAO,WAAW,CAAC,KAAK,QAAQ,IAAI,gBAAgB;AAC1D,UAAM,UAAU,MAAM,kBAAkB,WAAW,CAAC,GAAI,WAAW,CAAC,GAAI,IAAI;AAC5E,qBAAiB;AACjB,QAAI,KAAK,mBAAmB;AAC1B,YAAM,OAAO,MAAY;AACvB,wBAAgB;AAChB,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,KAAK,UAAU,IAAI;AAC3B,cAAQ,KAAK,WAAW,IAAI;AAC5B,YAAM,IAAI,QAAQ,MAAM,MAAS;AAAA,IACnC;AACA,WAAO,EAAE,mBAAmB,EAAE,IAAI,QAAQ,CAAC;AAAA,EAC7C;AACA,MAAI,eAAe,UAAU;AAC3B,WAAO,KAAK,UAAU,aAAa,GAAG,MAAM,CAAC;AAAA,EAC/C;AACA,MAAI,eAAe,WAAW;AAC5B,uBAAmB;AACnB,WAAO,EAAE,iBAAiB;AAAA,EAC5B;AACA,SAAO,EAAE,cAAc;AACzB;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/dist/remote-agent.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
type RemoteStatus = {
|
|
2
|
-
enabled?: boolean;
|
|
3
|
-
controller_url?: string;
|
|
4
|
-
agent_id?: string;
|
|
5
|
-
connected: boolean;
|
|
6
|
-
last_error?: string;
|
|
7
|
-
retry_in_ms?: number;
|
|
8
|
-
};
|
|
9
|
-
/** Close the active socket (if any) and stop reconnecting. Idempotent. */
|
|
10
|
-
export declare function stopRemoteAgent(): void;
|
|
11
|
-
/** Start one outbound-only remote-management connection for this supervisor process. */
|
|
12
|
-
export declare function startRemoteAgent(): void;
|
|
13
|
-
export declare function enrollRemoteAgent(controllerUrl: string, enrollmentToken: string, name: string): Promise<string>;
|
|
14
|
-
/** Disable the remote agent: clear enabled flag and close the connection. */
|
|
15
|
-
export declare function disableRemoteAgent(): void;
|
|
16
|
-
export declare function remoteStatus(): RemoteStatus;
|
|
17
|
-
export {};
|
|
18
|
-
//# sourceMappingURL=remote-agent.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remote-agent.d.ts","sourceRoot":"","sources":["../src/remote-agent.ts"],"names":[],"mappings":"AAqBA,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AA6FF,0EAA0E;AAC1E,wBAAgB,eAAe,IAAI,IAAI,CAetC;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,IAAI,IAAI,CAkEvC;AAED,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWrH;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,IAAI,CAOzC;AAED,wBAAgB,YAAY,IAAI,YAAY,CAW3C"}
|
package/dist/remote-agent.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { WebSocket } from "ws";
|
|
2
|
-
import {
|
|
3
|
-
configPath,
|
|
4
|
-
DEFAULT_REMOTE_CONFIG,
|
|
5
|
-
loadEnsuredConfig,
|
|
6
|
-
writeJson,
|
|
7
|
-
withConfigSchema
|
|
8
|
-
} from "@sfmc-bds/sdk/node/config";
|
|
9
|
-
import { cmdRestart, cmdSend, cmdStart, cmdStop } from "./commands.js";
|
|
10
|
-
import { ROOT } from "./runtime.js";
|
|
11
|
-
import { SERVICE_NAMES, queryServicesRuntime } from "./services.js";
|
|
12
|
-
let socket = null;
|
|
13
|
-
let retryTimer = null;
|
|
14
|
-
let retryDelay = 1e3;
|
|
15
|
-
let heartbeatTimer = null;
|
|
16
|
-
let lastError = "";
|
|
17
|
-
let warnedMissingConfig = false;
|
|
18
|
-
let stopping = false;
|
|
19
|
-
const HEARTBEAT_INTERVAL_MS = 2e4;
|
|
20
|
-
function loadConfig() {
|
|
21
|
-
return loadEnsuredConfig(
|
|
22
|
-
ROOT,
|
|
23
|
-
"remote.json",
|
|
24
|
-
"remote",
|
|
25
|
-
{ ...DEFAULT_REMOTE_CONFIG }
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
function writeConfig(config) {
|
|
29
|
-
writeJson(configPath(ROOT, "remote.json"), withConfigSchema({ ...config }, "remote"));
|
|
30
|
-
}
|
|
31
|
-
function isService(value) {
|
|
32
|
-
return !!value && SERVICE_NAMES.includes(value);
|
|
33
|
-
}
|
|
34
|
-
function isAction(value) {
|
|
35
|
-
return value === "status" || value === "start" || value === "stop" || value === "restart" || value === "send";
|
|
36
|
-
}
|
|
37
|
-
function websocketUrl(controllerUrl, agentId) {
|
|
38
|
-
const url = new URL(controllerUrl);
|
|
39
|
-
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
40
|
-
url.pathname = "/v1/agent";
|
|
41
|
-
url.search = new URLSearchParams({ id: agentId }).toString();
|
|
42
|
-
return url.toString();
|
|
43
|
-
}
|
|
44
|
-
function send(payload) {
|
|
45
|
-
if (socket?.readyState === WebSocket.OPEN) socket.send(JSON.stringify(payload));
|
|
46
|
-
}
|
|
47
|
-
function startHeartbeat() {
|
|
48
|
-
stopHeartbeat();
|
|
49
|
-
heartbeatTimer = setInterval(() => send({ type: "ping" }), HEARTBEAT_INTERVAL_MS);
|
|
50
|
-
}
|
|
51
|
-
function stopHeartbeat() {
|
|
52
|
-
if (heartbeatTimer) {
|
|
53
|
-
clearInterval(heartbeatTimer);
|
|
54
|
-
heartbeatTimer = null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
async function execute(task) {
|
|
58
|
-
if (!isAction(task.action)) throw new Error("invalid task action");
|
|
59
|
-
if (task.action === "status") return { services: await queryServicesRuntime() };
|
|
60
|
-
if (!isService(task.service)) throw new Error("service is required and must be one of: " + SERVICE_NAMES.join(", "));
|
|
61
|
-
if (task.action === "send") {
|
|
62
|
-
if (!task.message) throw new Error("message is required for send action");
|
|
63
|
-
return { output: await cmdSend(task.service, task.message), services: await queryServicesRuntime() };
|
|
64
|
-
}
|
|
65
|
-
const output = task.action === "start" ? await cmdStart(task.service) : task.action === "stop" ? await cmdStop(task.service) : await cmdRestart(task.service);
|
|
66
|
-
return { output, services: await queryServicesRuntime() };
|
|
67
|
-
}
|
|
68
|
-
function scheduleReconnect() {
|
|
69
|
-
if (retryTimer || stopping) return;
|
|
70
|
-
const delay = retryDelay;
|
|
71
|
-
retryTimer = setTimeout(() => {
|
|
72
|
-
retryTimer = null;
|
|
73
|
-
startRemoteAgent();
|
|
74
|
-
}, delay);
|
|
75
|
-
}
|
|
76
|
-
function resetReconnect(reason) {
|
|
77
|
-
retryDelay = 1e3;
|
|
78
|
-
if (reason) {
|
|
79
|
-
lastError = reason;
|
|
80
|
-
console.warn(`[remote-agent] ${reason} \u2014 will retry in ${retryDelay}ms`);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function stopRemoteAgent() {
|
|
84
|
-
stopping = true;
|
|
85
|
-
stopHeartbeat();
|
|
86
|
-
if (retryTimer) {
|
|
87
|
-
clearTimeout(retryTimer);
|
|
88
|
-
retryTimer = null;
|
|
89
|
-
}
|
|
90
|
-
if (socket) {
|
|
91
|
-
try {
|
|
92
|
-
socket.close(1e3, "client_shutdown");
|
|
93
|
-
} catch {
|
|
94
|
-
}
|
|
95
|
-
socket = null;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function startRemoteAgent() {
|
|
99
|
-
if (stopping) return;
|
|
100
|
-
if (socket || retryTimer) return;
|
|
101
|
-
const config = loadConfig();
|
|
102
|
-
if (!config.enabled || !config.controller_url || !config.agent_id || !config.agent_secret) {
|
|
103
|
-
if (!warnedMissingConfig) {
|
|
104
|
-
const missing = [];
|
|
105
|
-
if (!config.enabled) missing.push("enabled");
|
|
106
|
-
if (!config.controller_url) missing.push("controller_url");
|
|
107
|
-
if (!config.agent_id) missing.push("agent_id");
|
|
108
|
-
if (!config.agent_secret) missing.push("agent_secret");
|
|
109
|
-
if (missing.length) {
|
|
110
|
-
console.warn(`[remote-agent] disabled \u2014 missing remote.json fields: ${missing.join(", ")} (run \`sfmc remote enroll\`)`);
|
|
111
|
-
}
|
|
112
|
-
warnedMissingConfig = true;
|
|
113
|
-
}
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
warnedMissingConfig = true;
|
|
117
|
-
let ws;
|
|
118
|
-
try {
|
|
119
|
-
ws = new WebSocket(websocketUrl(config.controller_url, config.agent_id));
|
|
120
|
-
} catch (e) {
|
|
121
|
-
resetReconnect(`failed to construct websocket: ${e.message}`);
|
|
122
|
-
scheduleReconnect();
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
socket = ws;
|
|
126
|
-
ws.on("open", () => {
|
|
127
|
-
retryDelay = 1e3;
|
|
128
|
-
lastError = "";
|
|
129
|
-
void queryServicesRuntime().then((status) => {
|
|
130
|
-
send({ type: "hello", agentId: config.agent_id, secret: config.agent_secret, status });
|
|
131
|
-
startHeartbeat();
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
ws.on("message", (raw) => {
|
|
135
|
-
let msg;
|
|
136
|
-
try {
|
|
137
|
-
msg = JSON.parse(raw.toString());
|
|
138
|
-
} catch {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
if (msg.type === "ping") {
|
|
142
|
-
send({ type: "pong" });
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
if (msg.type !== "task") return;
|
|
146
|
-
const task = msg;
|
|
147
|
-
void execute(task).then((result) => send({ type: "task_result", taskId: task.taskId, ok: true, result })).catch((error) => send({ type: "task_result", taskId: task.taskId, ok: false, error: error.message }));
|
|
148
|
-
});
|
|
149
|
-
ws.on("close", (code, reason) => {
|
|
150
|
-
if (socket === ws) socket = null;
|
|
151
|
-
stopHeartbeat();
|
|
152
|
-
if (stopping) return;
|
|
153
|
-
resetReconnect(`disconnected (code=${code} ${reason.toString() || "no_reason"})`);
|
|
154
|
-
scheduleReconnect();
|
|
155
|
-
});
|
|
156
|
-
ws.on("error", (e) => {
|
|
157
|
-
resetReconnect(`socket error: ${e.message}`);
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
async function enrollRemoteAgent(controllerUrl, enrollmentToken, name) {
|
|
161
|
-
const response = await fetch(new URL("/v1/enroll", controllerUrl), {
|
|
162
|
-
method: "POST",
|
|
163
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${enrollmentToken}` },
|
|
164
|
-
body: JSON.stringify({ name })
|
|
165
|
-
});
|
|
166
|
-
const result = await response.json();
|
|
167
|
-
if (!response.ok || !result.agentId || !result.agentSecret) throw new Error(result.error ?? "enrollment failed");
|
|
168
|
-
writeConfig({ enabled: true, controller_url: controllerUrl, agent_id: result.agentId, agent_secret: result.agentSecret });
|
|
169
|
-
return result.agentId;
|
|
170
|
-
}
|
|
171
|
-
function disableRemoteAgent() {
|
|
172
|
-
const config = loadConfig();
|
|
173
|
-
if (config.agent_id || config.agent_secret) {
|
|
174
|
-
writeConfig({ ...config, enabled: false });
|
|
175
|
-
}
|
|
176
|
-
stopRemoteAgent();
|
|
177
|
-
stopping = false;
|
|
178
|
-
}
|
|
179
|
-
function remoteStatus() {
|
|
180
|
-
const config = loadConfig();
|
|
181
|
-
const result = { connected: socket?.readyState === WebSocket.OPEN };
|
|
182
|
-
if (config.enabled !== void 0) result.enabled = config.enabled;
|
|
183
|
-
if (config.controller_url) result.controller_url = config.controller_url;
|
|
184
|
-
if (config.agent_id) result.agent_id = config.agent_id;
|
|
185
|
-
if (lastError) {
|
|
186
|
-
result.last_error = lastError;
|
|
187
|
-
result.retry_in_ms = retryDelay;
|
|
188
|
-
}
|
|
189
|
-
return result;
|
|
190
|
-
}
|
|
191
|
-
export {
|
|
192
|
-
disableRemoteAgent,
|
|
193
|
-
enrollRemoteAgent,
|
|
194
|
-
remoteStatus,
|
|
195
|
-
startRemoteAgent,
|
|
196
|
-
stopRemoteAgent
|
|
197
|
-
};
|
|
198
|
-
//# sourceMappingURL=remote-agent.js.map
|
package/dist/remote-agent.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/remote-agent.ts"],
|
|
4
|
-
"sourcesContent": ["import { WebSocket } from \"ws\";\nimport {\n configPath,\n DEFAULT_REMOTE_CONFIG,\n loadEnsuredConfig,\n writeJson,\n withConfigSchema,\n type RemoteConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport { cmdRestart, cmdSend, cmdStart, cmdStop } from \"./commands.js\";\nimport { ROOT } from \"./runtime.js\";\nimport { SERVICE_NAMES, queryServicesRuntime, type ServiceName } from \"./services.js\";\n\ntype Task = {\n type: \"task\";\n taskId: string;\n action: \"status\" | \"start\" | \"stop\" | \"restart\" | \"send\";\n service?: string;\n message?: string;\n};\n\ntype RemoteStatus = {\n enabled?: boolean;\n controller_url?: string;\n agent_id?: string;\n connected: boolean;\n last_error?: string;\n retry_in_ms?: number;\n};\n\nlet socket: WebSocket | null = null;\nlet retryTimer: NodeJS.Timeout | null = null;\nlet retryDelay = 1000;\nlet heartbeatTimer: NodeJS.Timeout | null = null;\nlet lastError = \"\";\nlet warnedMissingConfig = false;\nlet stopping = false;\n\nconst HEARTBEAT_INTERVAL_MS = 20_000;\n\n/** \u542F\u52A8\u65F6\u786E\u4FDD remote.json \u5B58\u5728,\u8FD4\u56DE\u73B0\u6709\u6216\u7A7A\u914D\u7F6E\uFF08\u5DF2\u5265\u79BB $schema\uFF09\u3002 */\nfunction loadConfig(): RemoteConfig {\n return loadEnsuredConfig(\n ROOT,\n \"remote.json\",\n \"remote\",\n { ...DEFAULT_REMOTE_CONFIG } as Record<string, unknown>\n ) as RemoteConfig;\n}\n\nfunction writeConfig(config: RemoteConfig): void {\n writeJson(configPath(ROOT, \"remote.json\"), withConfigSchema({ ...config } as Record<string, unknown>, \"remote\"));\n}\n\nfunction isService(value: string | undefined): value is ServiceName {\n return !!value && SERVICE_NAMES.includes(value as ServiceName);\n}\n\nfunction isAction(value: unknown): value is Task[\"action\"] {\n return value === \"status\" || value === \"start\" || value === \"stop\" || value === \"restart\" || value === \"send\";\n}\n\nfunction websocketUrl(controllerUrl: string, agentId: string): string {\n const url = new URL(controllerUrl);\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n url.pathname = \"/v1/agent\";\n url.search = new URLSearchParams({ id: agentId }).toString();\n return url.toString();\n}\n\nfunction send(payload: unknown): void {\n if (socket?.readyState === WebSocket.OPEN) socket.send(JSON.stringify(payload));\n}\n\nfunction startHeartbeat(): void {\n stopHeartbeat();\n heartbeatTimer = setInterval(() => send({ type: \"ping\" }), HEARTBEAT_INTERVAL_MS);\n}\n\nfunction stopHeartbeat(): void {\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n}\n\nasync function execute(task: Task): Promise<unknown> {\n if (!isAction(task.action)) throw new Error(\"invalid task action\");\n if (task.action === \"status\") return { services: await queryServicesRuntime() };\n if (!isService(task.service)) throw new Error(\"service is required and must be one of: \" + SERVICE_NAMES.join(\", \"));\n if (task.action === \"send\") {\n if (!task.message) throw new Error(\"message is required for send action\");\n return { output: await cmdSend(task.service, task.message), services: await queryServicesRuntime() };\n }\n\n const output =\n task.action === \"start\"\n ? await cmdStart(task.service)\n : task.action === \"stop\"\n ? await cmdStop(task.service)\n : await cmdRestart(task.service);\n return { output, services: await queryServicesRuntime() };\n}\n\nfunction scheduleReconnect(): void {\n if (retryTimer || stopping) return;\n const delay = retryDelay;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n startRemoteAgent();\n }, delay);\n}\n\nfunction resetReconnect(reason?: string): void {\n retryDelay = 1000;\n if (reason) {\n lastError = reason;\n console.warn(`[remote-agent] ${reason} \u2014 will retry in ${retryDelay}ms`);\n }\n}\n\n/** Close the active socket (if any) and stop reconnecting. Idempotent. */\nexport function stopRemoteAgent(): void {\n stopping = true;\n stopHeartbeat();\n if (retryTimer) {\n clearTimeout(retryTimer);\n retryTimer = null;\n }\n if (socket) {\n try {\n socket.close(1000, \"client_shutdown\");\n } catch {\n /* ignore */\n }\n socket = null;\n }\n}\n\n/** Start one outbound-only remote-management connection for this supervisor process. */\nexport function startRemoteAgent(): void {\n if (stopping) return;\n if (socket || retryTimer) return;\n const config = loadConfig();\n if (!config.enabled || !config.controller_url || !config.agent_id || !config.agent_secret) {\n if (!warnedMissingConfig) {\n const missing: string[] = [];\n if (!config.enabled) missing.push(\"enabled\");\n if (!config.controller_url) missing.push(\"controller_url\");\n if (!config.agent_id) missing.push(\"agent_id\");\n if (!config.agent_secret) missing.push(\"agent_secret\");\n if (missing.length) {\n console.warn(`[remote-agent] disabled \u2014 missing remote.json fields: ${missing.join(\", \")} (run \\`sfmc remote enroll\\`)`);\n }\n warnedMissingConfig = true;\n }\n return;\n }\n warnedMissingConfig = true;\n\n let ws: WebSocket;\n try {\n ws = new WebSocket(websocketUrl(config.controller_url, config.agent_id));\n } catch (e) {\n resetReconnect(`failed to construct websocket: ${(e as Error).message}`);\n scheduleReconnect();\n return;\n }\n socket = ws;\n\n ws.on(\"open\", () => {\n retryDelay = 1000;\n lastError = \"\";\n void queryServicesRuntime().then((status) => {\n send({ type: \"hello\", agentId: config.agent_id, secret: config.agent_secret, status });\n startHeartbeat();\n });\n });\n ws.on(\"message\", (raw) => {\n let msg: { type?: string };\n try {\n msg = JSON.parse(raw.toString()) as { type?: string };\n } catch {\n return;\n }\n if (msg.type === \"ping\") {\n send({ type: \"pong\" });\n return;\n }\n if (msg.type !== \"task\") return;\n const task = msg as Task;\n void execute(task)\n .then((result) => send({ type: \"task_result\", taskId: task.taskId, ok: true, result }))\n .catch((error: Error) => send({ type: \"task_result\", taskId: task.taskId, ok: false, error: error.message }));\n });\n ws.on(\"close\", (code, reason) => {\n if (socket === ws) socket = null;\n stopHeartbeat();\n if (stopping) return;\n resetReconnect(`disconnected (code=${code} ${reason.toString() || \"no_reason\"})`);\n scheduleReconnect();\n });\n ws.on(\"error\", (e) => {\n resetReconnect(`socket error: ${e.message}`);\n /* close event will follow and trigger reconnect */\n });\n}\n\nexport async function enrollRemoteAgent(controllerUrl: string, enrollmentToken: string, name: string): Promise<string> {\n const response = await fetch(new URL(\"/v1/enroll\", controllerUrl), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${enrollmentToken}` },\n body: JSON.stringify({ name }),\n });\n const result = (await response.json()) as { agentId?: string; agentSecret?: string; error?: string };\n if (!response.ok || !result.agentId || !result.agentSecret) throw new Error(result.error ?? \"enrollment failed\");\n\n writeConfig({ enabled: true, controller_url: controllerUrl, agent_id: result.agentId, agent_secret: result.agentSecret });\n return result.agentId;\n}\n\n/** Disable the remote agent: clear enabled flag and close the connection. */\nexport function disableRemoteAgent(): void {\n const config = loadConfig();\n if (config.agent_id || config.agent_secret) {\n writeConfig({ ...config, enabled: false });\n }\n stopRemoteAgent();\n stopping = false;\n}\n\nexport function remoteStatus(): RemoteStatus {\n const config = loadConfig();\n const result: RemoteStatus = { connected: socket?.readyState === WebSocket.OPEN };\n if (config.enabled !== undefined) result.enabled = config.enabled;\n if (config.controller_url) result.controller_url = config.controller_url;\n if (config.agent_id) result.agent_id = config.agent_id;\n if (lastError) {\n result.last_error = lastError;\n result.retry_in_ms = retryDelay;\n }\n return result;\n}"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|