@sfmc-bds/cli 0.1.0 → 0.2.0-beta.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 +7 -1
- package/dist/cli-result.d.ts +12 -0
- package/dist/cli-result.d.ts.map +1 -0
- package/dist/cli-result.js +15 -0
- package/dist/cli-result.js.map +7 -0
- package/dist/commands-behavior-pack.d.ts +11 -42
- package/dist/commands-behavior-pack.d.ts.map +1 -1
- package/dist/commands-behavior-pack.js +40 -159
- package/dist/commands-behavior-pack.js.map +7 -1
- package/dist/commands-reload.d.ts +9 -0
- package/dist/commands-reload.d.ts.map +1 -0
- package/dist/commands-reload.js +30 -0
- package/dist/commands-reload.js.map +7 -0
- package/dist/commands.d.ts +7 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +182 -172
- package/dist/commands.js.map +7 -1
- package/dist/i18n/index.d.ts +26 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +107 -0
- package/dist/i18n/index.js.map +7 -0
- package/dist/i18n/locales/en.d.ts +381 -0
- package/dist/i18n/locales/en.d.ts.map +1 -0
- package/dist/i18n/locales/en.js +393 -0
- package/dist/i18n/locales/en.js.map +7 -0
- package/dist/i18n/locales/zh-CN.d.ts +4 -0
- package/dist/i18n/locales/zh-CN.d.ts.map +1 -0
- package/dist/i18n/locales/zh-CN.js +379 -0
- package/dist/i18n/locales/zh-CN.js.map +7 -0
- package/dist/i18n/types.d.ts +7 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +17 -0
- package/dist/i18n/types.js.map +7 -0
- package/dist/index.d.ts +5 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -43
- package/dist/index.js.map +7 -1
- package/dist/interactive-prompts.d.ts +8 -0
- package/dist/interactive-prompts.d.ts.map +1 -0
- package/dist/interactive-prompts.js +57 -0
- package/dist/interactive-prompts.js.map +7 -0
- package/dist/locale-command.d.ts +3 -0
- package/dist/locale-command.d.ts.map +1 -0
- package/dist/locale-command.js +19 -0
- package/dist/locale-command.js.map +7 -0
- package/dist/logs.d.ts +22 -4
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +208 -193
- package/dist/logs.js.map +7 -1
- package/dist/main.js +135 -173
- package/dist/main.js.map +7 -1
- package/dist/module-commands.d.ts +43 -4
- package/dist/module-commands.d.ts.map +1 -1
- package/dist/module-commands.js +440 -327
- package/dist/module-commands.js.map +7 -1
- package/dist/module-fingerprint.d.ts +7 -0
- package/dist/module-fingerprint.d.ts.map +1 -0
- package/dist/module-fingerprint.js +31 -0
- package/dist/module-fingerprint.js.map +7 -0
- package/dist/module-wizard.d.ts +14 -0
- package/dist/module-wizard.d.ts.map +1 -0
- package/dist/module-wizard.js +313 -0
- package/dist/module-wizard.js.map +7 -0
- package/dist/pack-lifecycle.d.ts +95 -0
- package/dist/pack-lifecycle.d.ts.map +1 -0
- package/dist/pack-lifecycle.js +634 -0
- package/dist/pack-lifecycle.js.map +7 -0
- package/dist/pack-update/bindings.d.ts +12 -0
- package/dist/pack-update/bindings.d.ts.map +1 -0
- package/dist/pack-update/bindings.js +64 -0
- package/dist/pack-update/bindings.js.map +7 -0
- package/dist/pack-update/config.d.ts +22 -0
- package/dist/pack-update/config.d.ts.map +1 -0
- package/dist/pack-update/config.js +141 -0
- package/dist/pack-update/config.js.map +7 -0
- package/dist/pack-update/providers/curseforge.d.ts +23 -0
- package/dist/pack-update/providers/curseforge.d.ts.map +1 -0
- package/dist/pack-update/providers/curseforge.js +209 -0
- package/dist/pack-update/providers/curseforge.js.map +7 -0
- package/dist/pack-update/providers/index.d.ts +16 -0
- package/dist/pack-update/providers/index.d.ts.map +1 -0
- package/dist/pack-update/providers/index.js +37 -0
- package/dist/pack-update/providers/index.js.map +7 -0
- package/dist/pack-update/service.d.ts +21 -0
- package/dist/pack-update/service.d.ts.map +1 -0
- package/dist/pack-update/service.js +567 -0
- package/dist/pack-update/service.js.map +7 -0
- package/dist/pack-update/types.d.ts +126 -0
- package/dist/pack-update/types.d.ts.map +1 -0
- package/dist/pack-update/types.js +8 -0
- package/dist/pack-update/types.js.map +7 -0
- package/dist/pack-update/version-policy.d.ts +80 -0
- package/dist/pack-update/version-policy.d.ts.map +1 -0
- package/dist/pack-update/version-policy.js +216 -0
- package/dist/pack-update/version-policy.js.map +7 -0
- package/dist/registry.d.ts +12 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +73 -106
- package/dist/registry.js.map +7 -1
- package/dist/remote-agent.d.ts.map +1 -1
- package/dist/remote-agent.js +160 -176
- package/dist/remote-agent.js.map +7 -1
- package/dist/repl.d.ts +4 -0
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +683 -605
- package/dist/repl.js.map +7 -1
- package/dist/runtime.d.ts +40 -14
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +185 -62
- package/dist/runtime.js.map +7 -1
- package/dist/services.d.ts +2 -0
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +251 -238
- package/dist/services.js.map +7 -1
- package/dist/sfmc-modules-root.d.ts +24 -0
- package/dist/sfmc-modules-root.d.ts.map +1 -0
- package/dist/sfmc-modules-root.js +70 -0
- package/dist/sfmc-modules-root.js.map +7 -0
- package/dist/theme.d.ts +4 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +134 -48
- package/dist/theme.js.map +7 -1
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +363 -438
- package/dist/wizard.js.map +7 -1
- package/dist/world-packs.d.ts +22 -0
- package/dist/world-packs.d.ts.map +1 -0
- package/dist/world-packs.js +872 -0
- package/dist/world-packs.js.map +7 -0
- package/package.json +10 -10
- package/dist/dispatcher.d.ts +0 -13
- package/dist/dispatcher.d.ts.map +0 -1
- package/dist/dispatcher.js +0 -23
- package/dist/dispatcher.js.map +0 -1
- package/dist/terminal.d.ts +0 -3
- package/dist/terminal.d.ts.map +0 -1
- package/dist/terminal.js +0 -178
- package/dist/terminal.js.map +0 -1
package/dist/registry.js
CHANGED
|
@@ -1,125 +1,92 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* registry.ts — first-party sfmc-modules index resolution, shared between
|
|
3
|
-
* the module CLI and the startup unknown-source warning.
|
|
4
|
-
*
|
|
5
|
-
* Talks to https://raw.githubusercontent.com/Tanya7z/sfmc-modules/main/index.json
|
|
6
|
-
* (the registry lives in a separate repo to keep this one free of "what
|
|
7
|
-
* modules exist" governance). Caches to <sfmc/src/.sfmc-registry-cache.json>
|
|
8
|
-
* with a 1h TTL so a brief network blip doesn't degrade the CLI.
|
|
9
|
-
*
|
|
10
|
-
* Both helpers are best-effort: failures are surfaced as `null` and a
|
|
11
|
-
* console warning, never an exception, because the SEA must still boot
|
|
12
|
-
* when the registry is unreachable.
|
|
13
|
-
*/
|
|
14
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
15
2
|
import path from "node:path";
|
|
16
3
|
import process from "node:process";
|
|
17
4
|
import { fileURLToPath } from "node:url";
|
|
18
5
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
6
|
const CACHE_PATH = path.join(__dirname, ".sfmc-registry-cache.json");
|
|
20
|
-
const TTL_MS = 60 * 60 *
|
|
7
|
+
const TTL_MS = 60 * 60 * 1e3;
|
|
21
8
|
const DEFAULT_REGISTRY_REPO = "Tanya7z/sfmc-modules";
|
|
22
9
|
const DEFAULT_REGISTRY_TAG = "main";
|
|
23
10
|
const INDEX_URL = `https://raw.githubusercontent.com/${DEFAULT_REGISTRY_REPO}/${DEFAULT_REGISTRY_TAG}/index.json`;
|
|
24
11
|
function readCache() {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
12
|
+
try {
|
|
13
|
+
if (!existsSync(CACHE_PATH)) return null;
|
|
14
|
+
return JSON.parse(readFileSync(CACHE_PATH, "utf8"));
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
33
18
|
}
|
|
34
19
|
function writeCache(cache) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/* cache write is best-effort */
|
|
41
|
-
}
|
|
20
|
+
try {
|
|
21
|
+
mkdirSync(path.dirname(CACHE_PATH), { recursive: true });
|
|
22
|
+
writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2));
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
42
25
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
62
|
-
continue;
|
|
63
|
-
const entry = v;
|
|
64
|
-
if (typeof entry.repo !== "string" || typeof entry.tag !== "string")
|
|
65
|
-
continue;
|
|
66
|
-
filtered[k] = { repo: entry.repo, tag: entry.tag };
|
|
67
|
-
}
|
|
68
|
-
return filtered;
|
|
26
|
+
function parseRegistryIndex(json) {
|
|
27
|
+
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
|
28
|
+
throw new Error("registry index must be a JSON object with a 'modules' field");
|
|
29
|
+
}
|
|
30
|
+
const root = json;
|
|
31
|
+
const modulesRaw = root.modules;
|
|
32
|
+
if (typeof modulesRaw !== "object" || modulesRaw === null || Array.isArray(modulesRaw)) {
|
|
33
|
+
throw new Error("registry index must have a 'modules' object mapping id \u2192 { repo, tag }");
|
|
34
|
+
}
|
|
35
|
+
const filtered = {};
|
|
36
|
+
for (const [k, v] of Object.entries(modulesRaw)) {
|
|
37
|
+
if (k.startsWith("_")) continue;
|
|
38
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) continue;
|
|
39
|
+
const entry = v;
|
|
40
|
+
if (typeof entry.repo !== "string" || typeof entry.tag !== "string") continue;
|
|
41
|
+
filtered[k] = { repo: entry.repo, tag: entry.tag };
|
|
42
|
+
}
|
|
43
|
+
return filtered;
|
|
69
44
|
}
|
|
70
45
|
async function fetchFresh() {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return parseRegistryIndex(await res.json());
|
|
46
|
+
const res = await fetch(INDEX_URL, { headers: { "User-Agent": "sfmc-cli" } });
|
|
47
|
+
if (!res.ok) throw new Error(`HTTP ${res.status} for ${INDEX_URL}`);
|
|
48
|
+
return parseRegistryIndex(await res.json());
|
|
75
49
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return { index: cache.index, stale: false };
|
|
92
|
-
}
|
|
93
|
-
try {
|
|
94
|
-
const fresh = await fetchFresh();
|
|
95
|
-
writeCache({ fetchedAt: Date.now(), index: fresh });
|
|
96
|
-
return { index: fresh, stale: false };
|
|
97
|
-
}
|
|
98
|
-
catch (err) {
|
|
99
|
-
if (cache) {
|
|
100
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
101
|
-
process.stderr.write(`[sfmc] registry offline (${msg}); using cached index from ${new Date(cache.fetchedAt).toISOString()}\n`);
|
|
102
|
-
return { index: cache.index, stale: true };
|
|
103
|
-
}
|
|
104
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
105
|
-
process.stderr.write(`[sfmc] registry unreachable and no cache: ${msg}\n`);
|
|
106
|
-
return { index: {}, stale: true };
|
|
50
|
+
async function resolveRegistryIndex(opts) {
|
|
51
|
+
const cache = readCache();
|
|
52
|
+
if (!opts?.force && cache && Date.now() - cache.fetchedAt < TTL_MS) {
|
|
53
|
+
return { index: cache.index, stale: false };
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const fresh = await fetchFresh();
|
|
57
|
+
writeCache({ fetchedAt: Date.now(), index: fresh });
|
|
58
|
+
return { index: fresh, stale: false };
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (cache) {
|
|
61
|
+
const msg2 = err instanceof Error ? err.message : String(err);
|
|
62
|
+
process.stderr.write(`[sfmc] registry offline (${msg2}); using cached index from ${new Date(cache.fetchedAt).toISOString()}
|
|
63
|
+
`);
|
|
64
|
+
return { index: cache.index, stale: true };
|
|
107
65
|
}
|
|
66
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
67
|
+
process.stderr.write(`[sfmc] registry unreachable and no cache: ${msg}
|
|
68
|
+
`);
|
|
69
|
+
return { index: {}, stale: true };
|
|
70
|
+
}
|
|
108
71
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return [];
|
|
121
|
-
}
|
|
122
|
-
return installedIds.filter((id) => !index[id]);
|
|
72
|
+
function listRegistryModuleIdsSync() {
|
|
73
|
+
const cache = readCache();
|
|
74
|
+
if (!cache) return [];
|
|
75
|
+
return Object.keys(cache.index).sort((a, b) => a.localeCompare(b));
|
|
76
|
+
}
|
|
77
|
+
async function findUnknownModules(installedIds) {
|
|
78
|
+
const { index, stale } = await resolveRegistryIndex();
|
|
79
|
+
if (stale && Object.keys(index).length === 0) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
return installedIds.filter((id) => !index[id]);
|
|
123
83
|
}
|
|
124
|
-
export {
|
|
125
|
-
|
|
84
|
+
export {
|
|
85
|
+
DEFAULT_REGISTRY_REPO,
|
|
86
|
+
DEFAULT_REGISTRY_TAG,
|
|
87
|
+
findUnknownModules,
|
|
88
|
+
listRegistryModuleIdsSync,
|
|
89
|
+
parseRegistryIndex,
|
|
90
|
+
resolveRegistryIndex
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=registry.js.map
|
package/dist/registry.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/registry.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * registry.ts \u2014 first-party sfmc-modules index resolution, shared between\n * the module CLI and the startup unknown-source warning.\n *\n * Talks to https://raw.githubusercontent.com/Tanya7z/sfmc-modules/main/index.json\n * (the registry lives in a separate repo to keep this one free of \"what\n * modules exist\" governance). Caches to <sfmc/src/.sfmc-registry-cache.json>\n * with a 1h TTL so a brief network blip doesn't degrade the CLI.\n *\n * Both helpers are best-effort: failures are surfaced as `null` and a\n * console warning, never an exception, because the CLI must still boot\n * when the registry is unreachable.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst CACHE_PATH = path.join(__dirname, \".sfmc-registry-cache.json\");\nconst TTL_MS = 60 * 60 * 1000;\n\nconst DEFAULT_REGISTRY_REPO = \"Tanya7z/sfmc-modules\";\nconst DEFAULT_REGISTRY_TAG = \"main\";\nconst INDEX_URL = `https://raw.githubusercontent.com/${DEFAULT_REGISTRY_REPO}/${DEFAULT_REGISTRY_TAG}/index.json`;\n\nexport interface RegistryEntry {\n repo: string;\n tag: string;\n}\nexport type RegistryIndex = Record<string, RegistryEntry>;\n\ninterface RegistryCache {\n fetchedAt: number;\n index: RegistryIndex;\n}\n\nfunction readCache(): RegistryCache | null {\n try {\n if (!existsSync(CACHE_PATH)) return null;\n return JSON.parse(readFileSync(CACHE_PATH, \"utf8\")) as RegistryCache;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(cache: RegistryCache): void {\n try {\n mkdirSync(path.dirname(CACHE_PATH), { recursive: true });\n writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2));\n } catch {\n /* cache write is best-effort */\n }\n}\n\n/**\n * \u89E3\u6790 first-party index.json\u3002\n * \u5951\u7EA6\u4E0E tools/lib/registry-index.mjs#parseRegistryIndex \u4FDD\u6301\u4E00\u81F4\uFF1A\n * `{ modules: { <folder>: { repo, tag } } }`\u3002\u5FFD\u7565 `_` \u524D\u7F00\u5143\u6570\u636E\u952E\u3002\n */\nexport function parseRegistryIndex(json: unknown): RegistryIndex {\n if (typeof json !== \"object\" || json === null || Array.isArray(json)) {\n throw new Error(\"registry index must be a JSON object with a 'modules' field\");\n }\n const root = json as Record<string, unknown>;\n const modulesRaw = root.modules;\n if (typeof modulesRaw !== \"object\" || modulesRaw === null || Array.isArray(modulesRaw)) {\n throw new Error(\"registry index must have a 'modules' object mapping id \u2192 { repo, tag }\");\n }\n const filtered: RegistryIndex = {};\n for (const [k, v] of Object.entries(modulesRaw as Record<string, unknown>)) {\n if (k.startsWith(\"_\")) continue;\n if (typeof v !== \"object\" || v === null || Array.isArray(v)) continue;\n const entry = v as Record<string, unknown>;\n if (typeof entry.repo !== \"string\" || typeof entry.tag !== \"string\") continue;\n filtered[k] = { repo: entry.repo, tag: entry.tag };\n }\n return filtered;\n}\n\nasync function fetchFresh(): Promise<RegistryIndex> {\n const res = await fetch(INDEX_URL, { headers: { \"User-Agent\": \"sfmc-cli\" } });\n if (!res.ok) throw new Error(`HTTP ${res.status} for ${INDEX_URL}`);\n return parseRegistryIndex(await res.json());\n}\n\nexport interface RegistryResult {\n index: RegistryIndex;\n /** True when the index came from a stale cache because the live fetch failed. */\n stale: boolean;\n}\n\n/**\n * Resolve the first-party index.\n *\n * Order (default):\n * 1. If the cache is fresh (< TTL): return it without trying the network.\n * 2. Otherwise attempt a live fetch.\n * - success \u2192 write cache, return fresh.\n * - failure + cache exists \u2192 return cache with `stale: true` and a warning.\n * - failure + no cache \u2192 return `{ index: {}, stale: true }` and warn.\n *\n * `force: true` \u8DF3\u8FC7 TTL \u65E9\u9000,\u59CB\u7EC8\u5C1D\u8BD5\u62C9\u7F51(\u4F9B `mod search` \u4E3B\u52A8\u5237\u65B0\u5217\u8868)\u3002\n * \u5931\u8D25\u65F6\u4ECD\u56DE\u9000\u5230\u7F13\u5B58,\u6C38\u4E0D\u629B\u5F02\u5E38\u3002\n */\nexport async function resolveRegistryIndex(opts?: { force?: boolean }): Promise<RegistryResult> {\n const cache = readCache();\n if (!opts?.force && cache && Date.now() - cache.fetchedAt < TTL_MS) {\n return { index: cache.index, stale: false };\n }\n try {\n const fresh = await fetchFresh();\n writeCache({ fetchedAt: Date.now(), index: fresh });\n return { index: fresh, stale: false };\n } catch (err) {\n if (cache) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[sfmc] registry offline (${msg}); using cached index from ${new Date(cache.fetchedAt).toISOString()}\\n`);\n return { index: cache.index, stale: true };\n }\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[sfmc] registry unreachable and no cache: ${msg}\\n`);\n return { index: {}, stale: true };\n }\n}\n\n/**\n * \u4ECE\u672C\u5730\u7F13\u5B58\u540C\u6B65\u8BFB\u51FA registry \u6A21\u5757 id(\u4F9B Tab \u8865\u5168)\u3002\n * \u65E0\u7F13\u5B58\u65F6\u8FD4\u56DE\u7A7A\u6570\u7EC4,\u4E0D\u89E6\u53D1\u7F51\u7EDC\u3002\n */\nexport function listRegistryModuleIdsSync(): string[] {\n const cache = readCache();\n if (!cache) return [];\n return Object.keys(cache.index).sort((a, b) => a.localeCompare(b));\n}\n\n/**\n * Compare a set of installed module ids to the registry and return the\n * subset that isn't published in the first-party index. The \"best-effort\"\n * guarantee: this returns an empty array when the registry can't be reached\n * (we don't want a network outage to mark every local module as unknown).\n */\nexport async function findUnknownModules(installedIds: string[]): Promise<string[]> {\n const { index, stale } = await resolveRegistryIndex();\n if (stale && Object.keys(index).length === 0) {\n /* No cache either \u2014 silently treat every module as \"we couldn't tell\".\n * Otherwise offline mode would scream warnings at every boot. */\n return [];\n }\n return installedIds.filter((id) => !index[id]);\n}\n\nexport { DEFAULT_REGISTRY_REPO, DEFAULT_REGISTRY_TAG };"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["msg"]
|
|
7
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-agent.d.ts","sourceRoot":"","sources":["../src/remote-agent.ts"],"names":[],"mappings":"
|
|
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,CAgEvC;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
CHANGED
|
@@ -1,212 +1,196 @@
|
|
|
1
1
|
import { WebSocket } from "ws";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
configPath,
|
|
4
|
+
DEFAULT_REMOTE_CONFIG,
|
|
5
|
+
loadEnsuredConfig,
|
|
6
|
+
writeJson,
|
|
7
|
+
withConfigSchema
|
|
8
|
+
} from "@sfmc-bds/sdk/node/config";
|
|
3
9
|
import { cmdRestart, cmdSend, cmdStart, cmdStop } from "./commands.js";
|
|
4
10
|
import { ROOT } from "./runtime.js";
|
|
5
11
|
import { SERVICE_NAMES, serviceStatus } from "./services.js";
|
|
6
12
|
let socket = null;
|
|
7
13
|
let retryTimer = null;
|
|
8
|
-
let retryDelay =
|
|
14
|
+
let retryDelay = 1e3;
|
|
9
15
|
let heartbeatTimer = null;
|
|
10
16
|
let lastError = "";
|
|
11
17
|
let warnedMissingConfig = false;
|
|
12
18
|
let stopping = false;
|
|
13
|
-
const HEARTBEAT_INTERVAL_MS =
|
|
14
|
-
/** 启动时确保 remote.json 存在,返回现有或空配置。 */
|
|
19
|
+
const HEARTBEAT_INTERVAL_MS = 2e4;
|
|
15
20
|
function loadConfig() {
|
|
16
|
-
|
|
21
|
+
return loadEnsuredConfig(
|
|
22
|
+
ROOT,
|
|
23
|
+
"remote.json",
|
|
24
|
+
"remote",
|
|
25
|
+
{ ...DEFAULT_REMOTE_CONFIG }
|
|
26
|
+
);
|
|
17
27
|
}
|
|
18
28
|
function writeConfig(config) {
|
|
19
|
-
|
|
29
|
+
writeJson(configPath(ROOT, "remote.json"), withConfigSchema({ ...config }, "remote"));
|
|
20
30
|
}
|
|
21
31
|
function isService(value) {
|
|
22
|
-
|
|
32
|
+
return !!value && SERVICE_NAMES.includes(value);
|
|
23
33
|
}
|
|
24
34
|
function isAction(value) {
|
|
25
|
-
|
|
35
|
+
return value === "status" || value === "start" || value === "stop" || value === "restart" || value === "send";
|
|
26
36
|
}
|
|
27
37
|
function websocketUrl(controllerUrl, agentId) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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();
|
|
33
43
|
}
|
|
34
44
|
function send(payload) {
|
|
35
|
-
|
|
36
|
-
socket.send(JSON.stringify(payload));
|
|
45
|
+
if (socket?.readyState === WebSocket.OPEN) socket.send(JSON.stringify(payload));
|
|
37
46
|
}
|
|
38
47
|
function startHeartbeat() {
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
stopHeartbeat();
|
|
49
|
+
heartbeatTimer = setInterval(() => send({ type: "ping" }), HEARTBEAT_INTERVAL_MS);
|
|
41
50
|
}
|
|
42
51
|
function stopHeartbeat() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
if (heartbeatTimer) {
|
|
53
|
+
clearInterval(heartbeatTimer);
|
|
54
|
+
heartbeatTimer = null;
|
|
55
|
+
}
|
|
47
56
|
}
|
|
48
57
|
async function execute(task) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (!
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return { output: await cmdSend(task.service, task.message), services: serviceStatus() };
|
|
59
|
-
}
|
|
60
|
-
const output = task.action === "start"
|
|
61
|
-
? await cmdStart(task.service)
|
|
62
|
-
: task.action === "stop"
|
|
63
|
-
? await cmdStop(task.service)
|
|
64
|
-
: await cmdRestart(task.service);
|
|
65
|
-
return { output, services: serviceStatus() };
|
|
58
|
+
if (!isAction(task.action)) throw new Error("invalid task action");
|
|
59
|
+
if (task.action === "status") return { services: serviceStatus() };
|
|
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: serviceStatus() };
|
|
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: serviceStatus() };
|
|
66
67
|
}
|
|
67
68
|
function scheduleReconnect() {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
retryTimer =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}, delay);
|
|
69
|
+
if (retryTimer || stopping) return;
|
|
70
|
+
const delay = retryDelay;
|
|
71
|
+
retryTimer = setTimeout(() => {
|
|
72
|
+
retryTimer = null;
|
|
73
|
+
startRemoteAgent();
|
|
74
|
+
}, delay);
|
|
75
75
|
}
|
|
76
76
|
function resetReconnect(reason) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (socket) {
|
|
92
|
-
try {
|
|
93
|
-
socket.close(1000, "client_shutdown");
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
/* ignore */
|
|
97
|
-
}
|
|
98
|
-
socket = null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
/** Start one outbound-only remote-management connection for this supervisor process. */
|
|
102
|
-
export function startRemoteAgent() {
|
|
103
|
-
if (stopping)
|
|
104
|
-
return;
|
|
105
|
-
if (socket || retryTimer)
|
|
106
|
-
return;
|
|
107
|
-
const config = loadConfig();
|
|
108
|
-
if (!config.enabled || !config.controller_url || !config.agent_id || !config.agent_secret) {
|
|
109
|
-
if (!warnedMissingConfig) {
|
|
110
|
-
const missing = [];
|
|
111
|
-
if (!config.enabled)
|
|
112
|
-
missing.push("enabled");
|
|
113
|
-
if (!config.controller_url)
|
|
114
|
-
missing.push("controller_url");
|
|
115
|
-
if (!config.agent_id)
|
|
116
|
-
missing.push("agent_id");
|
|
117
|
-
if (!config.agent_secret)
|
|
118
|
-
missing.push("agent_secret");
|
|
119
|
-
if (missing.length) {
|
|
120
|
-
console.warn(`[remote-agent] disabled — missing remote.json fields: ${missing.join(", ")} (run \`sfmc remote enroll\`)`);
|
|
121
|
-
}
|
|
122
|
-
warnedMissingConfig = true;
|
|
123
|
-
}
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
warnedMissingConfig = true;
|
|
127
|
-
let ws;
|
|
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) {
|
|
128
91
|
try {
|
|
129
|
-
|
|
92
|
+
socket.close(1e3, "client_shutdown");
|
|
93
|
+
} catch {
|
|
130
94
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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;
|
|
135
113
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
.catch((error) => send({ type: "task_result", taskId: task.taskId, ok: false, error: error.message }));
|
|
161
|
-
});
|
|
162
|
-
ws.on("close", (code, reason) => {
|
|
163
|
-
if (socket === ws)
|
|
164
|
-
socket = null;
|
|
165
|
-
stopHeartbeat();
|
|
166
|
-
if (stopping)
|
|
167
|
-
return;
|
|
168
|
-
resetReconnect(`disconnected (code=${code} ${reason.toString() || "no_reason"})`);
|
|
169
|
-
scheduleReconnect();
|
|
170
|
-
});
|
|
171
|
-
ws.on("error", (e) => {
|
|
172
|
-
resetReconnect(`socket error: ${e.message}`);
|
|
173
|
-
/* close event will follow and trigger reconnect */
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
export async function enrollRemoteAgent(controllerUrl, enrollmentToken, name) {
|
|
177
|
-
const response = await fetch(new URL("/v1/enroll", controllerUrl), {
|
|
178
|
-
method: "POST",
|
|
179
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${enrollmentToken}` },
|
|
180
|
-
body: JSON.stringify({ name }),
|
|
181
|
-
});
|
|
182
|
-
const result = (await response.json());
|
|
183
|
-
if (!response.ok || !result.agentId || !result.agentSecret)
|
|
184
|
-
throw new Error(result.error ?? "enrollment failed");
|
|
185
|
-
writeConfig({ enabled: true, controller_url: controllerUrl, agent_id: result.agentId, agent_secret: result.agentSecret });
|
|
186
|
-
return result.agentId;
|
|
187
|
-
}
|
|
188
|
-
/** Disable the remote agent: clear enabled flag and close the connection. */
|
|
189
|
-
export function disableRemoteAgent() {
|
|
190
|
-
const config = loadConfig();
|
|
191
|
-
if (config.agent_id || config.agent_secret) {
|
|
192
|
-
writeConfig({ ...config, enabled: false });
|
|
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
|
+
send({ type: "hello", agentId: config.agent_id, secret: config.agent_secret, status: serviceStatus() });
|
|
130
|
+
startHeartbeat();
|
|
131
|
+
});
|
|
132
|
+
ws.on("message", (raw) => {
|
|
133
|
+
let msg;
|
|
134
|
+
try {
|
|
135
|
+
msg = JSON.parse(raw.toString());
|
|
136
|
+
} catch {
|
|
137
|
+
return;
|
|
193
138
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
export function remoteStatus() {
|
|
198
|
-
const config = loadConfig();
|
|
199
|
-
const result = { connected: socket?.readyState === WebSocket.OPEN };
|
|
200
|
-
if (config.enabled !== undefined)
|
|
201
|
-
result.enabled = config.enabled;
|
|
202
|
-
if (config.controller_url)
|
|
203
|
-
result.controller_url = config.controller_url;
|
|
204
|
-
if (config.agent_id)
|
|
205
|
-
result.agent_id = config.agent_id;
|
|
206
|
-
if (lastError) {
|
|
207
|
-
result.last_error = lastError;
|
|
208
|
-
result.retry_in_ms = retryDelay;
|
|
139
|
+
if (msg.type === "ping") {
|
|
140
|
+
send({ type: "pong" });
|
|
141
|
+
return;
|
|
209
142
|
}
|
|
210
|
-
return
|
|
211
|
-
|
|
212
|
-
|
|
143
|
+
if (msg.type !== "task") return;
|
|
144
|
+
const task = msg;
|
|
145
|
+
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 }));
|
|
146
|
+
});
|
|
147
|
+
ws.on("close", (code, reason) => {
|
|
148
|
+
if (socket === ws) socket = null;
|
|
149
|
+
stopHeartbeat();
|
|
150
|
+
if (stopping) return;
|
|
151
|
+
resetReconnect(`disconnected (code=${code} ${reason.toString() || "no_reason"})`);
|
|
152
|
+
scheduleReconnect();
|
|
153
|
+
});
|
|
154
|
+
ws.on("error", (e) => {
|
|
155
|
+
resetReconnect(`socket error: ${e.message}`);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
async function enrollRemoteAgent(controllerUrl, enrollmentToken, name) {
|
|
159
|
+
const response = await fetch(new URL("/v1/enroll", controllerUrl), {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${enrollmentToken}` },
|
|
162
|
+
body: JSON.stringify({ name })
|
|
163
|
+
});
|
|
164
|
+
const result = await response.json();
|
|
165
|
+
if (!response.ok || !result.agentId || !result.agentSecret) throw new Error(result.error ?? "enrollment failed");
|
|
166
|
+
writeConfig({ enabled: true, controller_url: controllerUrl, agent_id: result.agentId, agent_secret: result.agentSecret });
|
|
167
|
+
return result.agentId;
|
|
168
|
+
}
|
|
169
|
+
function disableRemoteAgent() {
|
|
170
|
+
const config = loadConfig();
|
|
171
|
+
if (config.agent_id || config.agent_secret) {
|
|
172
|
+
writeConfig({ ...config, enabled: false });
|
|
173
|
+
}
|
|
174
|
+
stopRemoteAgent();
|
|
175
|
+
stopping = false;
|
|
176
|
+
}
|
|
177
|
+
function remoteStatus() {
|
|
178
|
+
const config = loadConfig();
|
|
179
|
+
const result = { connected: socket?.readyState === WebSocket.OPEN };
|
|
180
|
+
if (config.enabled !== void 0) result.enabled = config.enabled;
|
|
181
|
+
if (config.controller_url) result.controller_url = config.controller_url;
|
|
182
|
+
if (config.agent_id) result.agent_id = config.agent_id;
|
|
183
|
+
if (lastError) {
|
|
184
|
+
result.last_error = lastError;
|
|
185
|
+
result.retry_in_ms = retryDelay;
|
|
186
|
+
}
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
export {
|
|
190
|
+
disableRemoteAgent,
|
|
191
|
+
enrollRemoteAgent,
|
|
192
|
+
remoteStatus,
|
|
193
|
+
startRemoteAgent,
|
|
194
|
+
stopRemoteAgent
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=remote-agent.js.map
|