@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 CHANGED
@@ -10,5 +10,7 @@
10
10
  * - Tools: identity_whoami, identity_logout
11
11
  */
12
12
  import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
13
- export default function register(api: OpenClawPluginApi): void;
13
+ declare function registerImpl(api: OpenClawPluginApi): void;
14
+ declare const _default: typeof registerImpl;
15
+ export default _default;
14
16
  //# sourceMappingURL=index.d.ts.map
@@ -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;AAqF3E,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QA6iBtD"}
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
- export default function register(api) {
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: run async after register() returns so startup is never blocked.
496
- // On any failure, set pluginState.degraded so hooks skip all interception.
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
- runPluginPreflight({
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
- }).then((result) => {
521
- if (!result.ok) {
522
- pluginState.degraded = true;
523
- pluginState.failures = result.failures;
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;AASrD,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,CA2IxE"}
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: true,
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,CAkEtF"}
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
- const warnFailed = (failures) => {
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
- warnFailed(failures);
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
- return new Promise((resolve) => {
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([{ check: name, reason: `Unexpected preflight error: ${errMsg(err)}` }]);
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;AAEF,eAAO,MAAM,WAAW,EAAE,WAGzB,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
- export const pluginState = {
17
- degraded: false,
18
- failures: [],
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;AAoEF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAgE9B"}
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 (err) {
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":"AAgEA;;;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"}
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
- let cachedKey = null;
37
- let initPromise = null;
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
  }
@@ -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;
@@ -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
- * Priority: explicit endpoint > region from regionMetadataUrl -> https://id.{region}.volcengineapi.com > cn-beijing default.
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 Volcengine signing region from Identity endpoint host id.{region}.volcengineapi.com.
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;;;GAGG;AAEH,eAAO,MAAM,yBAAyB,4CAA4C,CAAC;AAUnF;;;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,GAAG,MAAM,CAEjE;AAED,MAAM,MAAM,+BAA+B,GAAG;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,+BAA+B,GACrC,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQhF"}
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
- * Priority: explicit endpoint > region from regionMetadataUrl -> https://id.{region}.volcengineapi.com > cn-beijing default.
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 DEFAULT_IDENTITY_ENDPOINT = "https://id.cn-beijing.volcengineapi.com";
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()}.volcengineapi.com`;
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 fallback = DEFAULT_IDENTITY_ENDPOINT;
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 Volcengine signing region from Identity endpoint host id.{region}.volcengineapi.com.
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 {
@@ -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}.volcengineapi.com. Request timeout ~10s; on failure falls back to https://id.cn-beijing.volcengineapi.com"
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.1",
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",