@m1a0rz/agent-identity 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -10
- package/dist/src/local-server/handlers.d.ts.map +1 -1
- package/dist/src/local-server/handlers.js +6 -1
- package/dist/src/preflight/plugin-preflight.d.ts +9 -0
- package/dist/src/preflight/plugin-preflight.d.ts.map +1 -1
- package/dist/src/preflight/plugin-preflight.js +22 -8
- package/dist/src/preflight/plugin-state.d.ts.map +1 -1
- package/dist/src/preflight/plugin-state.js +10 -4
- package/dist/src/services/identity-credentials.d.ts.map +1 -1
- package/dist/src/services/identity-credentials.js +1 -23
- package/dist/src/store/encryption.d.ts.map +1 -1
- package/dist/src/store/encryption.js +15 -11
- package/dist/src/types.d.ts +6 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/resolve-identity-endpoint.d.ts +34 -4
- package/dist/src/utils/resolve-identity-endpoint.d.ts.map +1 -1
- package/dist/src/utils/resolve-identity-endpoint.js +85 -9
- package/openclaw.plugin.json +5 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,7 @@
|
|
|
10
10
|
* - Tools: identity_whoami, identity_logout
|
|
11
11
|
*/
|
|
12
12
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
13
|
-
|
|
13
|
+
declare function registerImpl(api: OpenClawPluginApi): void;
|
|
14
|
+
declare const _default: typeof registerImpl;
|
|
15
|
+
export default _default;
|
|
14
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,qBAAqB,CAAC;AAmG3E,iBAAS,YAAY,CAAC,GAAG,EAAE,iBAAiB,QAyjB3C;wBAMwC,OAAO,YAAY;AAA5D,wBAA6D"}
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,7 @@ import { parseSessionKeyToDeliveryTarget, } from "./src/utils/derive-session-key
|
|
|
54
54
|
import { createSessionPutHandler, createSessionGetHandler, } from "./src/gateway/identity-session-methods.js";
|
|
55
55
|
import { logDebug, logInfo, logWarn } from "./src/utils/logger.js";
|
|
56
56
|
import { initEncryptionKey } from "./src/store/encryption.js";
|
|
57
|
+
import { setSiteMetadataUrl } from "./src/utils/resolve-identity-endpoint.js";
|
|
57
58
|
import { startIdentitySocket, stopIdentitySocket } from "./src/local-server/identity-socket.js";
|
|
58
59
|
const PLUGIN_STORE_DIR = "~/.openclaw/plugins/identity";
|
|
59
60
|
/**
|
|
@@ -75,11 +76,27 @@ function hasAnyIdentityConfig(identity) {
|
|
|
75
76
|
identity.audience?.length ||
|
|
76
77
|
identity.durationSeconds);
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Guard against jiti module duplication.
|
|
81
|
+
*
|
|
82
|
+
* OpenClaw ≥ v2026.3.28 may create multiple jiti instances with independent
|
|
83
|
+
* module caches. If this file is loaded twice, module-level state (Maps,
|
|
84
|
+
* flags, cached promises) in transitive imports splits into two copies and
|
|
85
|
+
* silently diverges. By pinning the register function on globalThis, the
|
|
86
|
+
* second load re-exports the first load's function, whose closures reference
|
|
87
|
+
* the first module graph — keeping all 27+ mutable module-level variables in
|
|
88
|
+
* a single, consistent copy.
|
|
89
|
+
*/
|
|
90
|
+
const PLUGIN_REGISTER_KEY = Symbol.for("openclaw-identity.pluginRegister");
|
|
91
|
+
function registerImpl(api) {
|
|
79
92
|
const pluginConfig = (api.pluginConfig ?? {});
|
|
80
93
|
const storeDir = api.resolvePath(PLUGIN_STORE_DIR);
|
|
81
94
|
initEncryptionKey(storeDir);
|
|
82
95
|
const identityCfg = pluginConfig.identity;
|
|
96
|
+
if (identityCfg?.siteMetadataUrl) {
|
|
97
|
+
setSiteMetadataUrl(identityCfg.siteMetadataUrl);
|
|
98
|
+
logInfo(api.logger, `identity.siteMetadataUrl: ${identityCfg.siteMetadataUrl}`);
|
|
99
|
+
}
|
|
83
100
|
setPersonalSessionMode(identityCfg?.personalSessionMode === true);
|
|
84
101
|
if (identityCfg?.personalSessionMode) {
|
|
85
102
|
logInfo(api.logger, "identity.personalSessionMode: non-subagent TIP/session/credentials use agent:main:main only");
|
|
@@ -492,10 +509,13 @@ export default function register(api) {
|
|
|
492
509
|
api.registerGatewayMethod("identity.session.get", createSessionGetHandler(sessionMethodDeps));
|
|
493
510
|
logInfo(api.logger, "gateway methods: identity.session.put, identity.session.get (webchat session exchange)");
|
|
494
511
|
}
|
|
495
|
-
// Preflight:
|
|
496
|
-
//
|
|
512
|
+
// Preflight: deferred to gateway_start hook so all subsystems (gateway,
|
|
513
|
+
// plugins, channels, …) have finished their synchronous plugin loading.
|
|
514
|
+
// Running inside register() would race against the next subsystem's sync
|
|
515
|
+
// load, whose event-loop blocking delays our fetch response callbacks and
|
|
516
|
+
// causes false timeouts (observed: ListUserPools 6836 ms → 55 ms once warm).
|
|
497
517
|
const authzEnabled = !!(authz?.agentCheck || authz?.toolCheck || authz?.requireRiskApproval);
|
|
498
|
-
|
|
518
|
+
const preflightDeps = {
|
|
499
519
|
pluginConfig,
|
|
500
520
|
identityClient,
|
|
501
521
|
hasIdentity,
|
|
@@ -517,13 +537,18 @@ export default function register(api) {
|
|
|
517
537
|
authzEnabled,
|
|
518
538
|
namespaceName: authz?.namespaceName ?? "default",
|
|
519
539
|
logger: api.logger,
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
540
|
+
};
|
|
541
|
+
api.on("gateway_start", async () => {
|
|
542
|
+
try {
|
|
543
|
+
const result = await runPluginPreflight(preflightDeps);
|
|
544
|
+
if (!result.ok) {
|
|
545
|
+
pluginState.degraded = true;
|
|
546
|
+
pluginState.failures = result.failures;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
catch (err) {
|
|
550
|
+
logWarn(api.logger, `[identity] preflight threw unexpectedly: ${String(err)}`);
|
|
524
551
|
}
|
|
525
|
-
}).catch((err) => {
|
|
526
|
-
logWarn(api.logger, `[identity] preflight threw unexpectedly: ${String(err)}`);
|
|
527
552
|
});
|
|
528
553
|
// Local UDS server: lets other processes on the same machine retrieve
|
|
529
554
|
// TIP tokens via HTTP-over-UDS (no network exposure, 0600 socket).
|
|
@@ -551,3 +576,8 @@ export default function register(api) {
|
|
|
551
576
|
});
|
|
552
577
|
}
|
|
553
578
|
}
|
|
579
|
+
const g = globalThis;
|
|
580
|
+
if (!g[PLUGIN_REGISTER_KEY]) {
|
|
581
|
+
g[PLUGIN_REGISTER_KEY] = registerImpl;
|
|
582
|
+
}
|
|
583
|
+
export default g[PLUGIN_REGISTER_KEY];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/local-server/handlers.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/local-server/handlers.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAUrD,oEAAoE;AACpE,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACrH,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,iBAAiB,KAAK,cAAc,CAAC;AAE1E,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,MAAM,EAAE;QACN,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC9B,CAAC;IACF,oEAAoE;IACpE,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACvD,CAAC;AAwBF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,eAAe,IAc1C,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC,CA+IxE"}
|
|
@@ -17,6 +17,7 @@ import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
|
|
|
17
17
|
import { getSessionWithRefresh } from "../services/session-refresh.js";
|
|
18
18
|
import { getAllTIPTokens } from "../store/tip-store.js";
|
|
19
19
|
import { isPersonalSessionModeEnabled, PERSONAL_SESSION_STORAGE_KEY, } from "../store/sender-session-store.js";
|
|
20
|
+
import { pluginState } from "../preflight/plugin-state.js";
|
|
20
21
|
const MAIN_SESSION_KEY = "agent:main:main";
|
|
21
22
|
function resolveMainSessionKey() {
|
|
22
23
|
if (isPersonalSessionModeEnabled())
|
|
@@ -129,7 +130,11 @@ export function createRequestHandler(deps) {
|
|
|
129
130
|
ttlSec: Math.max(0, Math.floor((entry.expiresAt - now) / 1000)),
|
|
130
131
|
}));
|
|
131
132
|
json(res, 200, {
|
|
132
|
-
ok:
|
|
133
|
+
ok: !pluginState.degraded,
|
|
134
|
+
degraded: pluginState.degraded,
|
|
135
|
+
failures: pluginState.failures.length > 0
|
|
136
|
+
? pluginState.failures.map((f) => ({ check: f.check, reason: f.reason }))
|
|
137
|
+
: undefined,
|
|
133
138
|
personalSessionMode: isPersonalSessionModeEnabled(),
|
|
134
139
|
mainSessionKey: resolveMainSessionKey(),
|
|
135
140
|
activeSessions: sessions.length,
|
|
@@ -61,5 +61,14 @@ export type PreflightDeps = {
|
|
|
61
61
|
info?: (msg: string) => void;
|
|
62
62
|
};
|
|
63
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* Run preflight checks.
|
|
66
|
+
*
|
|
67
|
+
* Expected to be called from the `gateway_start` hook, which fires after
|
|
68
|
+
* ALL subsystems (gateway, plugins, channels, …) have finished their
|
|
69
|
+
* synchronous plugin loading and the server is listening. This guarantees
|
|
70
|
+
* the event loop is free and network requests complete promptly — no yield
|
|
71
|
+
* loops or retry hacks needed.
|
|
72
|
+
*/
|
|
64
73
|
export declare function runPluginPreflight(deps: PreflightDeps): Promise<PreflightResult>;
|
|
65
74
|
//# sourceMappingURL=plugin-preflight.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-preflight.d.ts","sourceRoot":"","sources":["../../../src/preflight/plugin-preflight.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAG9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAO9E,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B,CAAC;AAEF;;GAEG;AACH,wBAAgB,4CAA4C,CAC1D,GAAG,EAAE,YAAY,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA0BxC;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,+CAA+C;IAC/C,cAAc,EAAE,uBAAuB,CAAC;IACxC,8DAA8D;IAC9D,WAAW,EAAE,OAAO,CAAC;IACrB,uDAAuD;IACvD,gBAAgB,CAAC,EAAE;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,SAAS,GAAG,UAAU,CAAC;QAC7B,mBAAmB;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,oBAAoB;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACzE,CAAC;AA4JF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"plugin-preflight.d.ts","sourceRoot":"","sources":["../../../src/preflight/plugin-preflight.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAG9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAO9E,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B,CAAC;AAEF;;GAEG;AACH,wBAAgB,4CAA4C,CAC1D,GAAG,EAAE,YAAY,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA0BxC;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,+CAA+C;IAC/C,cAAc,EAAE,uBAAuB,CAAC;IACxC,8DAA8D;IAC9D,WAAW,EAAE,OAAO,CAAC;IACrB,uDAAuD;IACvD,gBAAgB,CAAC,EAAE;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,SAAS,GAAG,UAAU,CAAC;QAC7B,mBAAmB;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,oBAAoB;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACzE,CAAC;AA4JF;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CAwEtF"}
|
|
@@ -192,11 +192,18 @@ async function checkNamespace(deps) {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
// ─── Main entry ───────────────────────────────────────────────────────────────
|
|
195
|
+
/**
|
|
196
|
+
* Run preflight checks.
|
|
197
|
+
*
|
|
198
|
+
* Expected to be called from the `gateway_start` hook, which fires after
|
|
199
|
+
* ALL subsystems (gateway, plugins, channels, …) have finished their
|
|
200
|
+
* synchronous plugin loading and the server is listening. This guarantees
|
|
201
|
+
* the event loop is free and network requests complete promptly — no yield
|
|
202
|
+
* loops or retry hacks needed.
|
|
203
|
+
*/
|
|
195
204
|
export async function runPluginPreflight(deps) {
|
|
196
205
|
const logger = deps.logger;
|
|
197
|
-
|
|
198
|
-
logger?.warn?.(`[identity] preflight failed (${failures.length} issue(s)): ${failures.map((f) => `${f.check}: ${f.reason}`).join(" | ")}`);
|
|
199
|
-
};
|
|
206
|
+
// Quick config sanity check.
|
|
200
207
|
if (deps.pluginConfig) {
|
|
201
208
|
const hit = findFirstUnrenderedPlaceholderInPluginConfig(deps.pluginConfig);
|
|
202
209
|
if (hit) {
|
|
@@ -206,7 +213,7 @@ export async function runPluginPreflight(deps) {
|
|
|
206
213
|
reason: `Configuration contains an unrendered environment variable placeholder ${hit.match} at ${hit.path}`,
|
|
207
214
|
},
|
|
208
215
|
];
|
|
209
|
-
|
|
216
|
+
logger?.warn?.(`[identity] preflight failed (${failures.length} issue(s)): ${failures.map((f) => `${f.check}: ${f.reason}`).join(" | ")}`);
|
|
210
217
|
return { ok: false, failures };
|
|
211
218
|
}
|
|
212
219
|
}
|
|
@@ -215,21 +222,19 @@ export async function runPluginPreflight(deps) {
|
|
|
215
222
|
{ name: "userpool", run: () => checkUserpool(deps) },
|
|
216
223
|
{ name: "namespace", run: () => checkNamespace(deps) },
|
|
217
224
|
];
|
|
218
|
-
|
|
225
|
+
const result = await new Promise((resolve) => {
|
|
219
226
|
let pending = steps.length;
|
|
220
227
|
let settled = false;
|
|
221
228
|
const finishOk = () => {
|
|
222
229
|
if (settled)
|
|
223
230
|
return;
|
|
224
231
|
settled = true;
|
|
225
|
-
logger?.info?.("[identity] preflight passed");
|
|
226
232
|
resolve({ ok: true, failures: [] });
|
|
227
233
|
};
|
|
228
234
|
const finishFail = (failures) => {
|
|
229
235
|
if (settled)
|
|
230
236
|
return;
|
|
231
237
|
settled = true;
|
|
232
|
-
warnFailed(failures);
|
|
233
238
|
resolve({ ok: false, failures });
|
|
234
239
|
};
|
|
235
240
|
for (const { name, run } of steps) {
|
|
@@ -246,8 +251,17 @@ export async function runPluginPreflight(deps) {
|
|
|
246
251
|
finishOk();
|
|
247
252
|
})
|
|
248
253
|
.catch((err) => {
|
|
249
|
-
finishFail([
|
|
254
|
+
finishFail([
|
|
255
|
+
{ check: name, reason: `Unexpected preflight error: ${errMsg(err)}` },
|
|
256
|
+
]);
|
|
250
257
|
});
|
|
251
258
|
}
|
|
252
259
|
});
|
|
260
|
+
if (result.ok) {
|
|
261
|
+
logger?.info?.("[identity] preflight passed");
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
logger?.warn?.(`[identity] preflight failed (${result.failures.length} issue(s)): ${result.failures.map((f) => `${f.check}: ${f.reason}`).join(" | ")}`);
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
253
267
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-state.d.ts","sourceRoot":"","sources":["../../../src/preflight/plugin-state.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,aAAa,GACb,UAAU,GACV,WAAW,CAAC;AAEhB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin-state.d.ts","sourceRoot":"","sources":["../../../src/preflight/plugin-state.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,aAAa,GACb,UAAU,GACV,WAAW,CAAC;AAEhB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B,CAAC;AAWF,eAAO,MAAM,WAAW,EAA2B,WAAW,CAAC"}
|
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
// Share across jiti module duplicates. Two subsystems each run preflight
|
|
17
|
+
// independently — the first may time out (sets degraded=true) while the
|
|
18
|
+
// second succeeds. Without sharing, hooks from the first instance stay
|
|
19
|
+
// degraded even though the process-wide state is healthy.
|
|
20
|
+
const PLUGIN_STATE_KEY = Symbol.for("openclaw-identity.pluginState");
|
|
21
|
+
const _g = globalThis;
|
|
22
|
+
if (!_g[PLUGIN_STATE_KEY]) {
|
|
23
|
+
_g[PLUGIN_STATE_KEY] = { degraded: false, failures: [] };
|
|
24
|
+
}
|
|
25
|
+
export const pluginState = _g[PLUGIN_STATE_KEY];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-credentials.d.ts","sourceRoot":"","sources":["../../../src/services/identity-credentials.ts"],"names":[],"mappings":"AAgCA,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AASF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC,CAAC;
|
|
1
|
+
{"version":3,"file":"identity-credentials.d.ts","sourceRoot":"","sources":["../../../src/services/identity-credentials.ts"],"names":[],"mappings":"AAgCA,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AASF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC,CAAC;AA8DF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAgE9B"}
|
|
@@ -38,17 +38,14 @@ const REMOTE_METADATA_REFRESH_BUFFER_SEC = 300;
|
|
|
38
38
|
* Returns the raw AK/SK/Token from the response, or null on failure.
|
|
39
39
|
*/
|
|
40
40
|
async function fetchRemoteMetadata(fullUrl) {
|
|
41
|
-
stsDebugLog("metadata fetch", { url: fullUrl });
|
|
42
41
|
let res;
|
|
43
42
|
try {
|
|
44
43
|
res = await fetch(fullUrl);
|
|
45
44
|
}
|
|
46
|
-
catch
|
|
47
|
-
stsDebugLog("metadata fetch failed", { error: String(err) });
|
|
45
|
+
catch {
|
|
48
46
|
return null;
|
|
49
47
|
}
|
|
50
48
|
const resText = await res.text();
|
|
51
|
-
stsDebugLog("metadata response", { status: res.status, body: resText });
|
|
52
49
|
if (!res.ok)
|
|
53
50
|
return null;
|
|
54
51
|
let json;
|
|
@@ -77,7 +74,6 @@ async function fetchRemoteMetadataThenAssumeRole(fullUrl, roleTrn) {
|
|
|
77
74
|
const creds = await fetchRemoteMetadata(fullUrl);
|
|
78
75
|
if (!creds)
|
|
79
76
|
return null;
|
|
80
|
-
stsDebugLog("metadata creds ok, calling AssumeRole", { roleTrn });
|
|
81
77
|
return assumeRole({
|
|
82
78
|
accessKeyId: creds.accessKeyId,
|
|
83
79
|
secretAccessKey: creds.secretAccessKey,
|
|
@@ -169,13 +165,6 @@ async function loadCredentialsFromFile(path) {
|
|
|
169
165
|
};
|
|
170
166
|
}
|
|
171
167
|
const STS_ENDPOINT = "https://sts.volcengineapi.com";
|
|
172
|
-
const STS_DEBUG = process.env["IDENTITY_STS_DEBUG"] === "1" || process.env["IDENTITY_STS_DEBUG"] === "true";
|
|
173
|
-
function stsDebugLog(msg, data) {
|
|
174
|
-
if (STS_DEBUG) {
|
|
175
|
-
const payload = data !== undefined ? ` ${JSON.stringify(data)}` : "";
|
|
176
|
-
console.warn(`[identity-credentials] STS AssumeRole: ${msg}${payload}`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
168
|
/**
|
|
180
169
|
* Call STS AssumeRole to get temporary credentials.
|
|
181
170
|
* Uses GET with params in query per volcengine-nodejs-sdk (metaPath: get/text_plain).
|
|
@@ -221,22 +210,11 @@ async function assumeRole(params) {
|
|
|
221
210
|
Accept: "application/json",
|
|
222
211
|
...signedHeaders,
|
|
223
212
|
};
|
|
224
|
-
stsDebugLog("request", {
|
|
225
|
-
method: "GET",
|
|
226
|
-
url: url.toString(),
|
|
227
|
-
query,
|
|
228
|
-
headers: { ...headers, Authorization: "(redacted)" },
|
|
229
|
-
});
|
|
230
213
|
const res = await fetch(url.toString(), {
|
|
231
214
|
method: "GET",
|
|
232
215
|
headers,
|
|
233
216
|
});
|
|
234
217
|
const resText = await res.text();
|
|
235
|
-
stsDebugLog("response", {
|
|
236
|
-
status: res.status,
|
|
237
|
-
statusText: res.statusText,
|
|
238
|
-
body: resText,
|
|
239
|
-
});
|
|
240
218
|
if (!res.ok) {
|
|
241
219
|
throw new Error(`STS AssumeRole failed ${res.status}: ${resText}`);
|
|
242
220
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../../src/store/encryption.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../../src/store/encryption.ts"],"names":[],"mappings":"AA2EA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAMxD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAIxD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAS9D;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAGf;AAID,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAExD;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
|
|
@@ -33,8 +33,12 @@ const SALT_LEN = 32;
|
|
|
33
33
|
const SALT_FILENAME = ".key-salt";
|
|
34
34
|
const PEPPER = "openclaw-identity-plugin-v1-AES256GCM-7f3a9c";
|
|
35
35
|
const HKDF_INFO = "openclaw-identity-enc";
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const ENC_STATE_KEY = Symbol.for("openclaw-identity.encryptionState");
|
|
37
|
+
const _g = globalThis;
|
|
38
|
+
if (!_g[ENC_STATE_KEY]) {
|
|
39
|
+
_g[ENC_STATE_KEY] = { cachedKey: null, initPromise: null };
|
|
40
|
+
}
|
|
41
|
+
const encState = _g[ENC_STATE_KEY];
|
|
38
42
|
async function readOrCreateSalt(storeDir) {
|
|
39
43
|
const saltPath = path.join(storeDir, SALT_FILENAME);
|
|
40
44
|
try {
|
|
@@ -60,10 +64,10 @@ async function deriveKey(storeDir) {
|
|
|
60
64
|
* is fine — the returned promise is awaited lazily by getEncryptionKey).
|
|
61
65
|
*/
|
|
62
66
|
export function initEncryptionKey(storeDir) {
|
|
63
|
-
if (cachedKey || initPromise)
|
|
67
|
+
if (encState.cachedKey || encState.initPromise)
|
|
64
68
|
return;
|
|
65
|
-
initPromise = deriveKey(storeDir).then((key) => {
|
|
66
|
-
cachedKey = key;
|
|
69
|
+
encState.initPromise = deriveKey(storeDir).then((key) => {
|
|
70
|
+
encState.cachedKey = key;
|
|
67
71
|
return key;
|
|
68
72
|
});
|
|
69
73
|
}
|
|
@@ -72,10 +76,10 @@ export function initEncryptionKey(storeDir) {
|
|
|
72
76
|
* completed yet. Callers in async hooks simply `await getEncryptionKey()`.
|
|
73
77
|
*/
|
|
74
78
|
export async function getEncryptionKey() {
|
|
75
|
-
if (cachedKey)
|
|
76
|
-
return cachedKey;
|
|
77
|
-
if (initPromise)
|
|
78
|
-
return initPromise;
|
|
79
|
+
if (encState.cachedKey)
|
|
80
|
+
return encState.cachedKey;
|
|
81
|
+
if (encState.initPromise)
|
|
82
|
+
return encState.initPromise;
|
|
79
83
|
throw new Error("Encryption key not initialized — call initEncryptionKey first");
|
|
80
84
|
}
|
|
81
85
|
export function encrypt(key, plaintext) {
|
|
@@ -142,6 +146,6 @@ export function isEncryptedField(value) {
|
|
|
142
146
|
}
|
|
143
147
|
/** Reset cached key and init promise (for testing only). */
|
|
144
148
|
export function __resetCachedKey() {
|
|
145
|
-
cachedKey = null;
|
|
146
|
-
initPromise = null;
|
|
149
|
+
encState.cachedKey = null;
|
|
150
|
+
encState.initPromise = null;
|
|
147
151
|
}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -24,6 +24,12 @@ export type IdentityConfig = {
|
|
|
24
24
|
* Lower priority than `endpoint`.
|
|
25
25
|
*/
|
|
26
26
|
regionMetadataUrl?: string;
|
|
27
|
+
/**
|
|
28
|
+
* URL to fetch deployment site name (e.g. http://100.96.0.96/volcstack/latest/site_name).
|
|
29
|
+
* Response "BytePlus" → byteplusapi.com, otherwise → volcengineapi.com.
|
|
30
|
+
* Default: http://100.96.0.96/volcstack/latest/site_name
|
|
31
|
+
*/
|
|
32
|
+
siteMetadataUrl?: string;
|
|
27
33
|
accessKeyId?: string;
|
|
28
34
|
secretAccessKey?: string;
|
|
29
35
|
sessionToken?: string;
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Resolve Volcengine Identity API base URL.
|
|
3
|
-
*
|
|
2
|
+
* Resolve Volcengine / BytePlus Identity API base URL.
|
|
3
|
+
*
|
|
4
|
+
* Site detection: GET http://100.96.0.96/volcstack/latest/site_name
|
|
5
|
+
* - "BytePlus" → byteplusapi.com
|
|
6
|
+
* - anything else / failure → volcengineapi.com (default)
|
|
7
|
+
*
|
|
8
|
+
* Endpoint priority:
|
|
9
|
+
* explicit endpoint > region from regionMetadataUrl → https://id.{region}.{domain} > cn-beijing default.
|
|
4
10
|
*/
|
|
11
|
+
export declare const VOLCENGINE_API_DOMAIN = "volcengineapi.com";
|
|
12
|
+
export declare const BYTEPLUS_API_DOMAIN = "byteplusapi.com";
|
|
5
13
|
export declare const DEFAULT_IDENTITY_ENDPOINT = "https://id.cn-beijing.volcengineapi.com";
|
|
14
|
+
/**
|
|
15
|
+
* Fetch ECS site name from metadata service.
|
|
16
|
+
* Returns the trimmed text body (e.g. "BytePlus") or null on any failure.
|
|
17
|
+
*/
|
|
18
|
+
export declare function fetchSiteName(url: string, options?: {
|
|
19
|
+
totalTimeoutMs?: number;
|
|
20
|
+
}): Promise<string | null>;
|
|
21
|
+
export declare function apiDomainForSite(siteName: string | null): string;
|
|
22
|
+
/**
|
|
23
|
+
* Override the default site metadata URL.
|
|
24
|
+
* Call once at plugin init when config.identity.siteMetadataUrl is provided.
|
|
25
|
+
*/
|
|
26
|
+
export declare function setSiteMetadataUrl(url: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the API domain suffix once per process.
|
|
29
|
+
* Only fetches ECS site metadata when siteMetadataUrl is explicitly configured;
|
|
30
|
+
* otherwise returns volcengineapi.com immediately (no network request).
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveApiDomain(): Promise<string>;
|
|
33
|
+
/** @internal — only for tests. */
|
|
34
|
+
export declare function _resetCachedApiDomain(): void;
|
|
6
35
|
/**
|
|
7
36
|
* GET metadata URL; expect plain-text region id (e.g. cn-beijing).
|
|
8
37
|
* Uses total request timeout (similar to curl --max-time 10).
|
|
@@ -10,17 +39,18 @@ export declare const DEFAULT_IDENTITY_ENDPOINT = "https://id.cn-beijing.volcengi
|
|
|
10
39
|
export declare function fetchRegionIdFromMetadata(metadataUrl: string, options?: {
|
|
11
40
|
totalTimeoutMs?: number;
|
|
12
41
|
}): Promise<string | null>;
|
|
13
|
-
export declare function identityEndpointFromRegion(region: string): string;
|
|
42
|
+
export declare function identityEndpointFromRegion(region: string, apiDomain?: string): string;
|
|
14
43
|
export type ResolveIdentityApiEndpointInput = {
|
|
15
44
|
endpoint?: string;
|
|
16
45
|
regionMetadataUrl?: string;
|
|
17
46
|
};
|
|
18
47
|
/**
|
|
19
48
|
* Resolve Identity control/data plane base URL for signing and requests.
|
|
49
|
+
* Automatically detects BytePlus vs Volcengine site from ECS metadata.
|
|
20
50
|
*/
|
|
21
51
|
export declare function resolveIdentityApiEndpoint(input: ResolveIdentityApiEndpointInput): Promise<string>;
|
|
22
52
|
/**
|
|
23
|
-
* Derive
|
|
53
|
+
* Derive signing region from Identity endpoint host: id.{region}.(volcengineapi|byteplusapi).com.
|
|
24
54
|
*/
|
|
25
55
|
export declare function signingRegionFromIdentityEndpoint(baseUrl: string): string | null;
|
|
26
56
|
//# sourceMappingURL=resolve-identity-endpoint.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-identity-endpoint.d.ts","sourceRoot":"","sources":["../../../src/utils/resolve-identity-endpoint.ts"],"names":[],"mappings":"AAgBA
|
|
1
|
+
{"version":3,"file":"resolve-identity-endpoint.d.ts","sourceRoot":"","sources":["../../../src/utils/resolve-identity-endpoint.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;GASG;AAEH,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AACzD,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,eAAO,MAAM,yBAAyB,4CAAmD,CAAC;AAM1F;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACpC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcxB;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAIhE;AAcD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGpD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAWlD;AAED,kCAAkC;AAClC,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAUD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACpC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuBxB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAErF;AAID,MAAM,MAAM,+BAA+B,GAAG;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,+BAA+B,GACrC,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQhF"}
|
|
@@ -14,11 +14,85 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
/**
|
|
17
|
-
* Resolve Volcengine Identity API base URL.
|
|
18
|
-
*
|
|
17
|
+
* Resolve Volcengine / BytePlus Identity API base URL.
|
|
18
|
+
*
|
|
19
|
+
* Site detection: GET http://100.96.0.96/volcstack/latest/site_name
|
|
20
|
+
* - "BytePlus" → byteplusapi.com
|
|
21
|
+
* - anything else / failure → volcengineapi.com (default)
|
|
22
|
+
*
|
|
23
|
+
* Endpoint priority:
|
|
24
|
+
* explicit endpoint > region from regionMetadataUrl → https://id.{region}.{domain} > cn-beijing default.
|
|
19
25
|
*/
|
|
20
|
-
export const
|
|
26
|
+
export const VOLCENGINE_API_DOMAIN = "volcengineapi.com";
|
|
27
|
+
export const BYTEPLUS_API_DOMAIN = "byteplusapi.com";
|
|
28
|
+
export const DEFAULT_IDENTITY_ENDPOINT = `https://id.cn-beijing.${VOLCENGINE_API_DOMAIN}`;
|
|
21
29
|
const DEFAULT_TOTAL_TIMEOUT_MS = 10_000;
|
|
30
|
+
// ── Site detection ──────────────────────────────────────────────────────
|
|
31
|
+
/**
|
|
32
|
+
* Fetch ECS site name from metadata service.
|
|
33
|
+
* Returns the trimmed text body (e.g. "BytePlus") or null on any failure.
|
|
34
|
+
*/
|
|
35
|
+
export async function fetchSiteName(url, options) {
|
|
36
|
+
const totalTimeoutMs = options?.totalTimeoutMs ?? 3_000;
|
|
37
|
+
const controller = new AbortController();
|
|
38
|
+
const timer = setTimeout(() => controller.abort(), totalTimeoutMs);
|
|
39
|
+
try {
|
|
40
|
+
const res = await fetch(url, { signal: controller.signal, redirect: "follow" });
|
|
41
|
+
if (!res.ok)
|
|
42
|
+
return null;
|
|
43
|
+
const text = (await res.text()).trim();
|
|
44
|
+
return text || null;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function apiDomainForSite(siteName) {
|
|
54
|
+
return siteName?.trim().toLowerCase() === "byteplus"
|
|
55
|
+
? BYTEPLUS_API_DOMAIN
|
|
56
|
+
: VOLCENGINE_API_DOMAIN;
|
|
57
|
+
}
|
|
58
|
+
const SITE_STATE_KEY = Symbol.for("openclaw-identity.siteDetectionState");
|
|
59
|
+
const _g = globalThis;
|
|
60
|
+
if (!_g[SITE_STATE_KEY]) {
|
|
61
|
+
_g[SITE_STATE_KEY] = { cachedApiDomain: null, customSiteMetadataUrl: null };
|
|
62
|
+
}
|
|
63
|
+
const siteState = _g[SITE_STATE_KEY];
|
|
64
|
+
/**
|
|
65
|
+
* Override the default site metadata URL.
|
|
66
|
+
* Call once at plugin init when config.identity.siteMetadataUrl is provided.
|
|
67
|
+
*/
|
|
68
|
+
export function setSiteMetadataUrl(url) {
|
|
69
|
+
siteState.customSiteMetadataUrl = url.trim() || null;
|
|
70
|
+
siteState.cachedApiDomain = null;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the API domain suffix once per process.
|
|
74
|
+
* Only fetches ECS site metadata when siteMetadataUrl is explicitly configured;
|
|
75
|
+
* otherwise returns volcengineapi.com immediately (no network request).
|
|
76
|
+
*/
|
|
77
|
+
export function resolveApiDomain() {
|
|
78
|
+
if (!siteState.cachedApiDomain) {
|
|
79
|
+
if (siteState.customSiteMetadataUrl) {
|
|
80
|
+
siteState.cachedApiDomain = fetchSiteName(siteState.customSiteMetadataUrl)
|
|
81
|
+
.then(apiDomainForSite)
|
|
82
|
+
.catch(() => VOLCENGINE_API_DOMAIN);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
siteState.cachedApiDomain = Promise.resolve(VOLCENGINE_API_DOMAIN);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return siteState.cachedApiDomain;
|
|
89
|
+
}
|
|
90
|
+
/** @internal — only for tests. */
|
|
91
|
+
export function _resetCachedApiDomain() {
|
|
92
|
+
siteState.cachedApiDomain = null;
|
|
93
|
+
siteState.customSiteMetadataUrl = null;
|
|
94
|
+
}
|
|
95
|
+
// ── Region detection ────────────────────────────────────────────────────
|
|
22
96
|
/** Region values that must not be used to build an endpoint. */
|
|
23
97
|
function isInvalidRegionId(text) {
|
|
24
98
|
const t = text.trim().toLowerCase();
|
|
@@ -56,32 +130,34 @@ export async function fetchRegionIdFromMetadata(metadataUrl, options) {
|
|
|
56
130
|
clearTimeout(timer);
|
|
57
131
|
}
|
|
58
132
|
}
|
|
59
|
-
export function identityEndpointFromRegion(region) {
|
|
60
|
-
return `https://id.${region.trim()}
|
|
133
|
+
export function identityEndpointFromRegion(region, apiDomain) {
|
|
134
|
+
return `https://id.${region.trim()}.${apiDomain ?? VOLCENGINE_API_DOMAIN}`;
|
|
61
135
|
}
|
|
62
136
|
/**
|
|
63
137
|
* Resolve Identity control/data plane base URL for signing and requests.
|
|
138
|
+
* Automatically detects BytePlus vs Volcengine site from ECS metadata.
|
|
64
139
|
*/
|
|
65
140
|
export async function resolveIdentityApiEndpoint(input) {
|
|
66
141
|
const explicit = input.endpoint?.trim();
|
|
67
142
|
if (explicit)
|
|
68
143
|
return explicit;
|
|
69
|
-
const
|
|
144
|
+
const apiDomain = await resolveApiDomain();
|
|
145
|
+
const fallback = `https://id.cn-beijing.${apiDomain}`;
|
|
70
146
|
const metaUrl = input.regionMetadataUrl?.trim();
|
|
71
147
|
if (metaUrl) {
|
|
72
148
|
const region = await fetchRegionIdFromMetadata(metaUrl);
|
|
73
149
|
if (region)
|
|
74
|
-
return identityEndpointFromRegion(region);
|
|
150
|
+
return identityEndpointFromRegion(region, apiDomain);
|
|
75
151
|
}
|
|
76
152
|
return fallback;
|
|
77
153
|
}
|
|
78
154
|
/**
|
|
79
|
-
* Derive
|
|
155
|
+
* Derive signing region from Identity endpoint host: id.{region}.(volcengineapi|byteplusapi).com.
|
|
80
156
|
*/
|
|
81
157
|
export function signingRegionFromIdentityEndpoint(baseUrl) {
|
|
82
158
|
try {
|
|
83
159
|
const host = new URL(baseUrl).host;
|
|
84
|
-
const m = /^id\.([a-z0-9-]+)\.volcengineapi\.com$/i.exec(host);
|
|
160
|
+
const m = /^id\.([a-z0-9-]+)\.(volcengineapi|byteplusapi)\.com$/i.exec(host);
|
|
85
161
|
return m ? m[1] : null;
|
|
86
162
|
}
|
|
87
163
|
catch {
|
package/openclaw.plugin.json
CHANGED
|
@@ -17,7 +17,11 @@
|
|
|
17
17
|
},
|
|
18
18
|
"regionMetadataUrl": {
|
|
19
19
|
"type": "string",
|
|
20
|
-
"description": "GET this URL for plain-text region id (e.g. http://100.96.0.96/latest/region_id). When endpoint is unset, builds https://id.{region}.
|
|
20
|
+
"description": "GET this URL for plain-text region id (e.g. http://100.96.0.96/latest/region_id). When endpoint is unset, builds https://id.{region}.{domain}. Request timeout ~10s; on failure falls back to cn-beijing default."
|
|
21
|
+
},
|
|
22
|
+
"siteMetadataUrl": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "URL to fetch deployment site name (e.g. http://100.96.0.96/volcstack/latest/site_name). Response 'BytePlus' → byteplusapi.com, otherwise → volcengineapi.com. Default: http://100.96.0.96/volcstack/latest/site_name"
|
|
21
25
|
},
|
|
22
26
|
"accessKeyId": {
|
|
23
27
|
"type": "string",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m1a0rz/agent-identity",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Agent Identity: UserPool (用户池) login, TIP token (工作负载令牌), credential hosting (凭据托管 OAuth2/API key), optional tool/skill permission control (CheckPermission) and risk approval. Integrates with Volcengine 智能体身份和权限管理平台.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|