@agenthifive/openclaw-setup 0.1.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.
@@ -0,0 +1,124 @@
1
+ import { importES256Key, exchangeToken } from "./jwt-utils.js";
2
+ export class VaultTokenManager {
3
+ baseUrl;
4
+ agentId;
5
+ privateKeyJWK;
6
+ tokenAudience;
7
+ privateKeyObj = null;
8
+ accessToken = null;
9
+ tokenExpiresAt = 0; // epoch ms
10
+ refreshTimer = null;
11
+ refreshInFlight = null;
12
+ /** Called after every successful token refresh with the new token. */
13
+ onRefresh = null;
14
+ /** Called when token refresh fails with 401 — indicates the agent's key is no longer valid. */
15
+ onAuthFailure = null;
16
+ constructor(config) {
17
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
18
+ this.agentId = config.agentId;
19
+ this.privateKeyJWK = config.privateKey;
20
+ this.tokenAudience = (config.tokenAudience ?? this.baseUrl).replace(/\/+$/, "");
21
+ }
22
+ /**
23
+ * Perform the initial token exchange and start the background refresh timer.
24
+ * Must be called (and awaited) before getToken().
25
+ */
26
+ async init() {
27
+ // Import the JWK once
28
+ this.privateKeyObj = await importES256Key(this.privateKeyJWK);
29
+ // Initial token exchange
30
+ await this.refreshToken();
31
+ // Schedule background refresh — check every 30s, refresh when near expiry
32
+ this.refreshTimer = setInterval(() => {
33
+ if (Date.now() >= this.tokenExpiresAt - 60_000) {
34
+ this.refreshToken().catch((err) => {
35
+ const ttlLeft = Math.max(0, Math.round((this.tokenExpiresAt - Date.now()) / 1000));
36
+ console.error(`[vault-token-manager] refresh failed (current token expires in ${ttlLeft}s, ` +
37
+ `prefix: ${this.accessToken?.slice(0, 4) ?? "none"}): ${err instanceof Error ? err.message : String(err)}`);
38
+ });
39
+ }
40
+ }, 30_000);
41
+ // Don't keep the process alive just for token refresh
42
+ if (this.refreshTimer &&
43
+ typeof this.refreshTimer === "object" &&
44
+ "unref" in this.refreshTimer) {
45
+ this.refreshTimer.unref();
46
+ }
47
+ }
48
+ /**
49
+ * Get the current bearer token. Synchronous — relies on background refresh.
50
+ * Throws if init() hasn't been called.
51
+ */
52
+ getToken() {
53
+ if (!this.accessToken) {
54
+ throw new Error("VaultTokenManager not initialized — call init() first");
55
+ }
56
+ return this.accessToken;
57
+ }
58
+ /** Stop the background refresh timer. */
59
+ stop() {
60
+ if (this.refreshTimer) {
61
+ clearInterval(this.refreshTimer);
62
+ this.refreshTimer = null;
63
+ }
64
+ }
65
+ /**
66
+ * Force an immediate token refresh. Called on-demand when a 401 is received.
67
+ * Coalesces concurrent requests — if a refresh is already in flight, callers
68
+ * wait for the same promise instead of hammering the token endpoint.
69
+ */
70
+ async forceRefresh() {
71
+ if (this.refreshInFlight) {
72
+ try {
73
+ await this.refreshInFlight;
74
+ return true;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ const attempt = this.refreshToken();
81
+ this.refreshInFlight = attempt;
82
+ try {
83
+ await attempt;
84
+ return true;
85
+ }
86
+ catch {
87
+ return false;
88
+ }
89
+ finally {
90
+ this.refreshInFlight = null;
91
+ }
92
+ }
93
+ async refreshToken() {
94
+ if (!this.privateKeyObj) {
95
+ throw new Error("Private key not imported — call init() first");
96
+ }
97
+ try {
98
+ const result = await exchangeToken(this.privateKeyObj, {
99
+ baseUrl: this.baseUrl,
100
+ agentId: this.agentId,
101
+ tokenAudience: this.tokenAudience,
102
+ });
103
+ const previousToken = this.accessToken;
104
+ this.accessToken = result.accessToken;
105
+ this.tokenExpiresAt = Date.now() + result.expiresIn * 1000;
106
+ console.log(`[vault-token-manager] Token refreshed (prefix: ${this.accessToken.slice(0, 4)}..., ` +
107
+ `ttl: ${result.expiresIn}s, previous: ${previousToken ? previousToken.slice(0, 4) + "..." : "none"})`);
108
+ // Notify listener (register.ts uses this to update the shared mutable auth object)
109
+ this.onRefresh?.(this.accessToken);
110
+ }
111
+ catch (err) {
112
+ // Check for 401 specifically
113
+ if (err instanceof Error && err.message.includes("401")) {
114
+ console.error("[vault-token-manager] Token exchange rejected (401). " +
115
+ "The agent's key pair is no longer valid — agent may have been disabled or key rotated. " +
116
+ "Generate a bootstrap secret from the AgentHiFive dashboard (Agents → Bootstrap Secret), " +
117
+ "then run `openclaw configure` to reconnect.");
118
+ this.onAuthFailure?.();
119
+ }
120
+ throw err;
121
+ }
122
+ }
123
+ }
124
+ //# sourceMappingURL=vault-token-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault-token-manager.js","sourceRoot":"","sources":["../src/vault-token-manager.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@agenthifive/openclaw-setup",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "ah5-setup": "dist/cli.js"
7
+ },
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc -p tsconfig.json",
13
+ "typecheck": "tsc -p tsconfig.json --noEmit",
14
+ "lint": "echo Lint: OK"
15
+ },
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/supersantux/AgentH5.git",
20
+ "directory": "packages/openclaw-setup"
21
+ },
22
+ "keywords": [
23
+ "openclaw",
24
+ "agenthifive",
25
+ "vault",
26
+ "ai-agent",
27
+ "setup",
28
+ "cli"
29
+ ],
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "dependencies": {
34
+ "jose": "^5.9.3"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.0.0",
38
+ "typescript": "^5.6.0"
39
+ }
40
+ }