@tangle-network/agent-core 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/auth/browser.d.ts +22 -0
- package/dist/auth/browser.d.ts.map +1 -0
- package/dist/auth/browser.js +43 -0
- package/dist/auth/browser.js.map +1 -0
- package/dist/auth/index.d.ts +430 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +841 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/computer-use/index.d.ts +122 -0
- package/dist/computer-use/index.d.ts.map +1 -0
- package/dist/computer-use/index.js +422 -0
- package/dist/computer-use/index.js.map +1 -0
- package/dist/errors-DJ6U6cHY.js +146 -0
- package/dist/errors-DJ6U6cHY.js.map +1 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +2 -0
- package/dist/events-CUWh9qrv.js +263 -0
- package/dist/events-CUWh9qrv.js.map +1 -0
- package/dist/index-CFA8kgHJ.d.ts +352 -0
- package/dist/index-CFA8kgHJ.d.ts.map +1 -0
- package/dist/index-CtebBodu.d.ts +108 -0
- package/dist/index-CtebBodu.d.ts.map +1 -0
- package/dist/index-DiQX9bjq.d.ts +55 -0
- package/dist/index-DiQX9bjq.d.ts.map +1 -0
- package/dist/index-DlPznmKA.d.ts +158 -0
- package/dist/index-DlPznmKA.d.ts.map +1 -0
- package/dist/index-z2wPdzFb.d.ts +133 -0
- package/dist/index-z2wPdzFb.d.ts.map +1 -0
- package/dist/index.d.ts +565 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +822 -0
- package/dist/index.js.map +1 -0
- package/dist/resilience/index.d.ts +2 -0
- package/dist/resilience/index.js +2 -0
- package/dist/resilience-BQzDfw_C.js +221 -0
- package/dist/resilience-BQzDfw_C.js.map +1 -0
- package/dist/sse/index.d.ts +174 -0
- package/dist/sse/index.d.ts.map +1 -0
- package/dist/sse/index.js +303 -0
- package/dist/sse/index.js.map +1 -0
- package/dist/transport/index.d.ts +2 -0
- package/dist/transport/index.js +2 -0
- package/dist/transport-mKLoQep5.js +427 -0
- package/dist/transport-mKLoQep5.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types-D5VLaol0.js +31 -0
- package/dist/types-D5VLaol0.js.map +1 -0
- package/dist/types-DC6OJ1um.js +331 -0
- package/dist/types-DC6OJ1um.js.map +1 -0
- package/dist/types-DiDSGM8K.d.ts +320 -0
- package/dist/types-DiDSGM8K.d.ts.map +1 -0
- package/package.json +132 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tangle Network
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @tangle-network/agent-core
|
|
2
|
+
|
|
3
|
+
Runtime primitives for talking to Tangle agents:
|
|
4
|
+
|
|
5
|
+
- **Auth** — issue and verify scoped access tokens for sidecar/session access.
|
|
6
|
+
- **SSE** — parse agent event streams (`SSEChunkParser`, `parseSSEStream`, `parseSSEData`).
|
|
7
|
+
- **Transport** — connection-manager and transport interfaces.
|
|
8
|
+
- **Resilience** — retries, timeouts, and circuit breakers.
|
|
9
|
+
- **Telemetry** — GenAI attribute and token-usage helpers.
|
|
10
|
+
|
|
11
|
+
Depends on [`@tangle-network/agent-interface`](../agent-interface) for the shared
|
|
12
|
+
type/schema contract.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @tangle-network/agent-core @tangle-network/agent-interface
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Requires Node.js >= 18 — the auth module uses `node:crypto` for token signing and
|
|
21
|
+
verification.
|
|
22
|
+
|
|
23
|
+
## Subpath exports
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { } from "@tangle-network/agent-core"; // top-level
|
|
27
|
+
import { } from "@tangle-network/agent-core/auth"; // token issue/verify
|
|
28
|
+
import { } from "@tangle-network/agent-core/sse"; // SSE parsing
|
|
29
|
+
import { } from "@tangle-network/agent-core/transport"; // transport interfaces
|
|
30
|
+
import { } from "@tangle-network/agent-core/resilience"; // retries / breakers
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
|
|
35
|
+
MIT
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { C as ReadTokenAuth, S as NoAuth, T as StaticTokenAuth, a as CreateSessionResponse, b as AuthProvider, c as ProductSchema, f as ReadTokenPayload, h as SendMessageRequestSchema, i as CreateSessionRequestSchema, l as ProductSecrets, m as SendMessageRequest, o as Product, p as ReadTokenPayloadSchema, r as CreateSessionRequest, s as ProductAuthInfo, w as RefreshableTokenAuth, x as CallbackAuth, y as TokenValidationResult } from "../types-DiDSGM8K.js";
|
|
2
|
+
|
|
3
|
+
//#region src/auth/tokens-browser.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Decode a JWT without verification (to extract claims for lookup).
|
|
6
|
+
* Returns null if the token is malformed.
|
|
7
|
+
*
|
|
8
|
+
* This is safe to use in browsers - it only parses the token, doesn't verify.
|
|
9
|
+
*/
|
|
10
|
+
declare function decodeToken(token: string): ReadTokenPayload | null;
|
|
11
|
+
/**
|
|
12
|
+
* Get time until token expires (in seconds).
|
|
13
|
+
* Returns negative if expired.
|
|
14
|
+
*/
|
|
15
|
+
declare function getTokenTTL(payload: ReadTokenPayload): number;
|
|
16
|
+
/**
|
|
17
|
+
* Check if token is expiring soon (within buffer seconds).
|
|
18
|
+
*/
|
|
19
|
+
declare function isTokenExpiringSoon(payload: ReadTokenPayload, bufferSeconds?: number): boolean;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { type AuthProvider, CallbackAuth, type CreateSessionRequest, CreateSessionRequestSchema, type CreateSessionResponse, NoAuth, type Product, type ProductAuthInfo, ProductSchema, type ProductSecrets, ReadTokenAuth, type ReadTokenPayload, ReadTokenPayloadSchema, RefreshableTokenAuth, type SendMessageRequest, SendMessageRequestSchema, StaticTokenAuth, type TokenValidationResult, decodeToken, getTokenTTL, isTokenExpiringSoon };
|
|
22
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","names":[],"sources":["../../src/auth/tokens-browser.ts"],"mappings":";;;;AAkDA;;;;;iBAlBgB,WAAA,CAAY,KAAA,WAAgB,gBAAA;;;;;iBAkB5B,WAAA,CAAY,OAAA,EAAS,gBAAA;;;;iBAQrB,mBAAA,CACd,OAAA,EAAS,gBAAA,EACT,aAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { a as ReadTokenPayloadSchema, c as CallbackAuth, d as RefreshableTokenAuth, f as StaticTokenAuth, l as NoAuth, n as CreateSessionRequestSchema, o as SendMessageRequestSchema, r as ProductSchema, u as ReadTokenAuth } from "../types-DC6OJ1um.js";
|
|
2
|
+
//#region src/auth/tokens-browser.ts
|
|
3
|
+
/**
|
|
4
|
+
* Base64URL decode (browser-safe).
|
|
5
|
+
*/
|
|
6
|
+
function base64UrlDecode(data) {
|
|
7
|
+
const base64 = (data + "=".repeat((4 - data.length % 4) % 4)).replace(/-/g, "+").replace(/_/g, "/");
|
|
8
|
+
if (typeof atob === "function") return atob(base64);
|
|
9
|
+
return Buffer.from(base64, "base64").toString();
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Decode a JWT without verification (to extract claims for lookup).
|
|
13
|
+
* Returns null if the token is malformed.
|
|
14
|
+
*
|
|
15
|
+
* This is safe to use in browsers - it only parses the token, doesn't verify.
|
|
16
|
+
*/
|
|
17
|
+
function decodeToken(token) {
|
|
18
|
+
try {
|
|
19
|
+
const parts = token.split(".");
|
|
20
|
+
if (parts.length !== 3) return null;
|
|
21
|
+
return JSON.parse(base64UrlDecode(parts[1]));
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get time until token expires (in seconds).
|
|
28
|
+
* Returns negative if expired.
|
|
29
|
+
*/
|
|
30
|
+
function getTokenTTL(payload) {
|
|
31
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
32
|
+
return payload.exp - now;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if token is expiring soon (within buffer seconds).
|
|
36
|
+
*/
|
|
37
|
+
function isTokenExpiringSoon(payload, bufferSeconds = 60) {
|
|
38
|
+
return getTokenTTL(payload) <= bufferSeconds;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { CallbackAuth, CreateSessionRequestSchema, NoAuth, ProductSchema, ReadTokenAuth, ReadTokenPayloadSchema, RefreshableTokenAuth, SendMessageRequestSchema, StaticTokenAuth, decodeToken, getTokenTTL, isTokenExpiringSoon };
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","names":[],"sources":["../../src/auth/tokens-browser.ts"],"sourcesContent":["/**\n * Browser-safe Token Utilities\n *\n * Token decoding and inspection that works in both browser and Node.js.\n * Uses only standard APIs (atob/btoa or TextEncoder/TextDecoder).\n */\n\nimport type { ReadTokenPayload } from \"./types.js\";\n\n/**\n * Base64URL decode (browser-safe).\n */\nfunction base64UrlDecode(data: string): string {\n // Add padding if needed\n const padded = data + \"=\".repeat((4 - (data.length % 4)) % 4);\n // Convert base64url to base64\n const base64 = padded.replace(/-/g, \"+\").replace(/_/g, \"/\");\n\n // Use atob in browser, Buffer in Node\n if (typeof atob === \"function\") {\n return atob(base64);\n }\n // Node.js fallback\n return Buffer.from(base64, \"base64\").toString();\n}\n\n/**\n * Decode a JWT without verification (to extract claims for lookup).\n * Returns null if the token is malformed.\n *\n * This is safe to use in browsers - it only parses the token, doesn't verify.\n */\nexport function decodeToken(token: string): ReadTokenPayload | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = JSON.parse(base64UrlDecode(parts[1]));\n return payload as ReadTokenPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Get time until token expires (in seconds).\n * Returns negative if expired.\n */\nexport function getTokenTTL(payload: ReadTokenPayload): number {\n const now = Math.floor(Date.now() / 1000);\n return payload.exp - now;\n}\n\n/**\n * Check if token is expiring soon (within buffer seconds).\n */\nexport function isTokenExpiringSoon(\n payload: ReadTokenPayload,\n bufferSeconds = 60,\n): boolean {\n return getTokenTTL(payload) <= bufferSeconds;\n}\n"],"mappings":";;;;;AAYA,SAAS,gBAAgB,MAAsB;CAI7C,MAAM,UAFS,OAAO,IAAI,QAAQ,IAAK,KAAK,SAAS,KAAM,EAAE,EAEvC,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI;AAG3D,KAAI,OAAO,SAAS,WAClB,QAAO,KAAK,OAAO;AAGrB,QAAO,OAAO,KAAK,QAAQ,SAAS,CAAC,UAAU;;;;;;;;AASjD,SAAgB,YAAY,OAAwC;AAClE,KAAI;EACF,MAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,MAAI,MAAM,WAAW,EACnB,QAAO;AAIT,SADgB,KAAK,MAAM,gBAAgB,MAAM,GAAG,CACtC;SACR;AACN,SAAO;;;;;;;AAQX,SAAgB,YAAY,SAAmC;CAC7D,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;AACzC,QAAO,QAAQ,MAAM;;;;;AAMvB,SAAgB,oBACd,SACA,gBAAgB,IACP;AACT,QAAO,YAAY,QAAQ,IAAI"}
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import { C as ReadTokenAuth, S as NoAuth, T as StaticTokenAuth, _ as SessionScopedTokenPayloadSchema, a as CreateSessionResponse, b as AuthProvider, c as ProductSchema, d as ProjectScopedTokenPayloadSchema, f as ReadTokenPayload, g as SessionScopedTokenPayload, h as SendMessageRequestSchema, i as CreateSessionRequestSchema, l as ProductSecrets, m as SendMessageRequest, n as BatchScopedTokenPayloadSchema, o as Product, p as ReadTokenPayloadSchema, r as CreateSessionRequest, s as ProductAuthInfo, t as BatchScopedTokenPayload, u as ProjectScopedTokenPayload, v as TokenScope, w as RefreshableTokenAuth, x as CallbackAuth, y as TokenValidationResult } from "../types-DiDSGM8K.js";
|
|
2
|
+
|
|
3
|
+
//#region src/auth/channel-access.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Result of channel access check.
|
|
6
|
+
*/
|
|
7
|
+
interface ChannelAccessResult {
|
|
8
|
+
/** Whether access is allowed */
|
|
9
|
+
allowed: boolean;
|
|
10
|
+
/** Reason for denial (if not allowed) */
|
|
11
|
+
reason?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extract session ID from a session channel pattern.
|
|
15
|
+
* Returns null if not a session channel.
|
|
16
|
+
*/
|
|
17
|
+
declare function extractSessionFromChannel(channel: string): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Extract project ID from a project channel pattern.
|
|
20
|
+
* Returns null if not a project channel.
|
|
21
|
+
*/
|
|
22
|
+
declare function extractProjectFromChannel(channel: string): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a session-scoped token can access a channel.
|
|
25
|
+
*
|
|
26
|
+
* Session tokens can access:
|
|
27
|
+
* - session:{their-sid}
|
|
28
|
+
* - agent:{their-sid}
|
|
29
|
+
* - system (always allowed)
|
|
30
|
+
* - Wildcard patterns matching their session
|
|
31
|
+
*/
|
|
32
|
+
declare function canSessionTokenAccessChannel(payload: SessionScopedTokenPayload, channel: string): ChannelAccessResult;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a project-scoped token can access a channel.
|
|
35
|
+
*
|
|
36
|
+
* Project tokens can access:
|
|
37
|
+
* - project:{their-projectId}
|
|
38
|
+
* - session:* (all sessions within project - requires validation by caller)
|
|
39
|
+
* - agent:* (all agent events within project)
|
|
40
|
+
* - system (always allowed)
|
|
41
|
+
*/
|
|
42
|
+
declare function canProjectTokenAccessChannel(payload: ProjectScopedTokenPayload, channel: string): ChannelAccessResult;
|
|
43
|
+
/**
|
|
44
|
+
* Check if a batch-scoped token can access a channel.
|
|
45
|
+
*
|
|
46
|
+
* Batch tokens can access:
|
|
47
|
+
* - project:{any of their projectIds}
|
|
48
|
+
* - session:* (all sessions within their projects)
|
|
49
|
+
* - agent:* (all agent events within their projects)
|
|
50
|
+
* - system (always allowed)
|
|
51
|
+
* - * (global wildcard - for organization-wide subscriptions)
|
|
52
|
+
*/
|
|
53
|
+
declare function canBatchTokenAccessChannel(payload: BatchScopedTokenPayload, channel: string): ChannelAccessResult;
|
|
54
|
+
/**
|
|
55
|
+
* Check if a token can access a channel.
|
|
56
|
+
* Dispatches to scope-specific functions based on token type.
|
|
57
|
+
*
|
|
58
|
+
* @param payload - The token payload
|
|
59
|
+
* @param channel - The channel to check access for
|
|
60
|
+
* @returns Access result with allowed boolean and optional reason
|
|
61
|
+
*/
|
|
62
|
+
declare function canTokenAccessChannel(payload: ReadTokenPayload, channel: string): ChannelAccessResult;
|
|
63
|
+
/**
|
|
64
|
+
* Get the list of allowed channel patterns for a token.
|
|
65
|
+
* Useful for informing clients what they can subscribe to.
|
|
66
|
+
*
|
|
67
|
+
* @param payload - The token payload
|
|
68
|
+
* @returns Array of allowed channel patterns
|
|
69
|
+
*/
|
|
70
|
+
declare function getAllowedChannelPatterns(payload: ReadTokenPayload): string[];
|
|
71
|
+
/**
|
|
72
|
+
* Validate channel subscription request.
|
|
73
|
+
* Checks multiple channels and returns aggregated result.
|
|
74
|
+
*
|
|
75
|
+
* @param payload - The token payload
|
|
76
|
+
* @param channels - Channels to validate
|
|
77
|
+
* @returns Object with allowed channels and denied channels with reasons
|
|
78
|
+
*/
|
|
79
|
+
declare function validateChannelSubscription(payload: ReadTokenPayload, channels: string[]): {
|
|
80
|
+
allowed: string[];
|
|
81
|
+
denied: Array<{
|
|
82
|
+
channel: string;
|
|
83
|
+
reason: string;
|
|
84
|
+
}>;
|
|
85
|
+
};
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/auth/tokens.d.ts
|
|
88
|
+
/**
|
|
89
|
+
* Generate a cryptographically secure random string.
|
|
90
|
+
* @param prefix - Prefix for the generated string (e.g., "orch_prod_")
|
|
91
|
+
* @param bytes - Number of random bytes (default: 32 = 256 bits)
|
|
92
|
+
*/
|
|
93
|
+
declare function generateSecureToken(prefix: string, bytes?: number): string;
|
|
94
|
+
/**
|
|
95
|
+
* Generate a product API key.
|
|
96
|
+
*/
|
|
97
|
+
declare function generateApiKey(): string;
|
|
98
|
+
/**
|
|
99
|
+
* Generate a signing secret.
|
|
100
|
+
*/
|
|
101
|
+
declare function generateSigningSecret(): string;
|
|
102
|
+
/**
|
|
103
|
+
* Issue a read token (JWT) for WebSocket authentication.
|
|
104
|
+
*
|
|
105
|
+
* @param signingSecret - The product's signing secret
|
|
106
|
+
* @param payload - Token payload (without iat/exp, those are added)
|
|
107
|
+
* @param ttlMinutes - Token TTL in minutes
|
|
108
|
+
*/
|
|
109
|
+
declare function issueReadToken(signingSecret: string, payload: Omit<ReadTokenPayload, "iat" | "exp" | "typ">, ttlMinutes: number): string;
|
|
110
|
+
/**
|
|
111
|
+
* Issue a session-scoped token (JWT) for WebSocket authentication.
|
|
112
|
+
* Grants access to a single session's events.
|
|
113
|
+
*
|
|
114
|
+
* @param signingSecret - The product's signing secret
|
|
115
|
+
* @param payload - Token payload with session ID
|
|
116
|
+
* @param ttlMinutes - Token TTL in minutes
|
|
117
|
+
*/
|
|
118
|
+
declare function issueSessionScopedToken(signingSecret: string, payload: Omit<SessionScopedTokenPayload, "iat" | "exp" | "typ">, ttlMinutes: number): string;
|
|
119
|
+
/**
|
|
120
|
+
* Issue a project-scoped token (JWT) for WebSocket authentication.
|
|
121
|
+
* Grants access to all sessions within a single project.
|
|
122
|
+
*
|
|
123
|
+
* @param signingSecret - The product's signing secret
|
|
124
|
+
* @param payload - Token payload with project ID
|
|
125
|
+
* @param ttlMinutes - Token TTL in minutes
|
|
126
|
+
*/
|
|
127
|
+
declare function issueProjectScopedToken(signingSecret: string, payload: Omit<ProjectScopedTokenPayload, "iat" | "exp" | "typ">, ttlMinutes: number): string;
|
|
128
|
+
/**
|
|
129
|
+
* Issue a batch-scoped token (JWT) for WebSocket authentication.
|
|
130
|
+
* Grants access to multiple projects (organization-level access).
|
|
131
|
+
*
|
|
132
|
+
* @param signingSecret - The product's signing secret
|
|
133
|
+
* @param payload - Token payload with project IDs array
|
|
134
|
+
* @param ttlMinutes - Token TTL in minutes
|
|
135
|
+
*/
|
|
136
|
+
declare function issueBatchScopedToken(signingSecret: string, payload: Omit<BatchScopedTokenPayload, "iat" | "exp" | "typ">, ttlMinutes: number): string;
|
|
137
|
+
/**
|
|
138
|
+
* Capability strings carried in a sidecar token's `cap` claim. The
|
|
139
|
+
* sidecar route allowlist (SIDECAR_CAPABILITY_ROUTES) maps each path
|
|
140
|
+
* prefix to the capability required to access it. Tokens with a `cap`
|
|
141
|
+
* claim are strictly limited to those capabilities; tokens without a
|
|
142
|
+
* `cap` claim are full-scope (legacy orchestrator-internal use).
|
|
143
|
+
*
|
|
144
|
+
* Adding a new capability:
|
|
145
|
+
* 1. Extend this union.
|
|
146
|
+
* 2. Add the path prefix → capability mapping in SIDECAR_CAPABILITY_ROUTES.
|
|
147
|
+
* 3. Mint tokens with the new capability via `issueSidecarAccessToken`.
|
|
148
|
+
*/
|
|
149
|
+
type SidecarCapability = "computer_use" | "read" | "debug" | "terminal";
|
|
150
|
+
/**
|
|
151
|
+
* Public ↔ capability binding. The sidecar's auth middleware uses this
|
|
152
|
+
* to enforce: a token with a `cap` claim can only call routes whose
|
|
153
|
+
* required capability is in the token's `cap` list. Routes not listed
|
|
154
|
+
* here implicitly require full scope (no `cap` claim, i.e. legacy
|
|
155
|
+
* orchestrator-internal tokens).
|
|
156
|
+
*
|
|
157
|
+
* Order matters — longest prefix wins so `/mcp/x` matches before `/`.
|
|
158
|
+
*/
|
|
159
|
+
declare const SIDECAR_CAPABILITY_ROUTES: ReadonlyArray<{
|
|
160
|
+
prefix: string;
|
|
161
|
+
capability: SidecarCapability;
|
|
162
|
+
}>;
|
|
163
|
+
/**
|
|
164
|
+
* Pattern-gated routes, for capabilities that must bind to a SPECIFIC path
|
|
165
|
+
* shape rather than a whole prefix. The terminal/ssh WebSocket upgrade paths
|
|
166
|
+
* are the raw-input interactive surface (keystrokes straight to a PTY / SSH
|
|
167
|
+
* tunnel) — the highest-trust action in the box — so they require a `terminal`
|
|
168
|
+
* capability, while the sibling REST route `/terminals/commands` (one-shot
|
|
169
|
+
* command exec, called by the public SDK + artifact queue) deliberately stays
|
|
170
|
+
* OUT of the gate so a prefix match does not break those callers.
|
|
171
|
+
*
|
|
172
|
+
* Adding a pattern: anchor it (`^…$`) so it cannot over-match a sibling path.
|
|
173
|
+
*/
|
|
174
|
+
declare const SIDECAR_CAPABILITY_ROUTE_PATTERNS: ReadonlyArray<{
|
|
175
|
+
pattern: RegExp;
|
|
176
|
+
capability: SidecarCapability;
|
|
177
|
+
}>;
|
|
178
|
+
/**
|
|
179
|
+
* Routes a token with `cap: ["read"]` is allowed to call, with the HTTP
|
|
180
|
+
* methods permitted on each. Used by `box.mintScopedToken({scope:
|
|
181
|
+
* "read-only" | "project" | "session"})` (Issue #913 Gap 1).
|
|
182
|
+
*
|
|
183
|
+
* The "read" capability is intentionally NOT in
|
|
184
|
+
* `SIDECAR_CAPABILITY_ROUTES` — that table maps gated routes that ONLY
|
|
185
|
+
* the matching cap can access. "read" is *additive*: it grants a token
|
|
186
|
+
* access to a narrow allow-list of read routes WITHOUT also denying
|
|
187
|
+
* those same routes to master tokens. Master tokens (cap=undefined)
|
|
188
|
+
* keep reaching every non-gated route as before.
|
|
189
|
+
*
|
|
190
|
+
* Adding a route here: keep it GET-only by default. Mutating methods
|
|
191
|
+
* on a read-token would defeat the "read-only" promise customers rely
|
|
192
|
+
* on when handing the token to browser code.
|
|
193
|
+
*/
|
|
194
|
+
declare const READ_CAPABILITY_ROUTES: ReadonlyArray<{
|
|
195
|
+
prefix: string;
|
|
196
|
+
methods: ReadonlyArray<string>;
|
|
197
|
+
}>;
|
|
198
|
+
/**
|
|
199
|
+
* Returns the capability required to access `path`, or `null` if the
|
|
200
|
+
* route requires full scope (no `cap` claim).
|
|
201
|
+
*/
|
|
202
|
+
declare function requiredCapabilityForPath(path: string): SidecarCapability | null;
|
|
203
|
+
/**
|
|
204
|
+
* Authorize a verified sidecar token for `path` (and optionally
|
|
205
|
+
* `method`). Returns true iff one of:
|
|
206
|
+
* - the token has NO `cap` claim (legacy full-scope master) AND the
|
|
207
|
+
* path is not capability-gated;
|
|
208
|
+
* - the path is capability-gated and the token's `cap` claim
|
|
209
|
+
* includes the required capability;
|
|
210
|
+
* - the token has `cap: ["read"]` (Issue #913 Gap 1 consumer
|
|
211
|
+
* scoped tokens) AND the path is in `READ_CAPABILITY_ROUTES`
|
|
212
|
+
* with the request method on the allow-list.
|
|
213
|
+
*
|
|
214
|
+
* Fail-closed semantics:
|
|
215
|
+
* - An explicit `cap` claim is a scope assertion. Even an empty
|
|
216
|
+
* array (`cap: []`) means "scoped to no capability" → reject every
|
|
217
|
+
* request, including admin routes (see harden report 2026-04-26).
|
|
218
|
+
* - A capability-scoped token CANNOT access non-capability-gated
|
|
219
|
+
* routes outside its explicit allow-list.
|
|
220
|
+
*
|
|
221
|
+
* `method` defaults to undefined for backwards compatibility — callers
|
|
222
|
+
* that don't pass it will fail-closed for the read-cap allow-list,
|
|
223
|
+
* which matches the old behavior (read-cap didn't exist).
|
|
224
|
+
*/
|
|
225
|
+
declare function authorizeSidecarToken(payload: {
|
|
226
|
+
cap?: readonly SidecarCapability[];
|
|
227
|
+
}, path: string, method?: string): boolean;
|
|
228
|
+
/**
|
|
229
|
+
* Generate an Ed25519 key pair for per-session JWT signing.
|
|
230
|
+
* Private key stays in orchestrator memory. Public key is injected into
|
|
231
|
+
* the sidecar container. Even if the sidecar is fully compromised,
|
|
232
|
+
* the attacker cannot forge JWTs for any container.
|
|
233
|
+
*
|
|
234
|
+
* @returns { privateKey, publicKey } as PEM strings
|
|
235
|
+
*/
|
|
236
|
+
declare function generateSidecarKeyPair(): {
|
|
237
|
+
privateKey: string;
|
|
238
|
+
publicKey: string;
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* Issue a sidecar access token (JWT) using Ed25519 signing.
|
|
242
|
+
* Scoped to a specific container via the required `cid` claim.
|
|
243
|
+
*
|
|
244
|
+
* @param privateKey - Ed25519 private key (PEM). If not provided, falls back to HMAC.
|
|
245
|
+
* @param hmacFallbackSecret - HMAC secret for backward compat (used when no Ed25519 key)
|
|
246
|
+
* @param payload - Token payload with container ID
|
|
247
|
+
* @param ttlMinutes - Token TTL in minutes
|
|
248
|
+
*/
|
|
249
|
+
declare function issueSidecarAccessToken(privateKey: string, payload: {
|
|
250
|
+
sub: string;
|
|
251
|
+
pid: string;
|
|
252
|
+
cid: string;
|
|
253
|
+
sid?: string;
|
|
254
|
+
/**
|
|
255
|
+
* Capability allowlist. When present, the token is restricted to
|
|
256
|
+
* routes whose required capability is in this list (see
|
|
257
|
+
* SIDECAR_CAPABILITY_ROUTES). Absent = full scope (legacy
|
|
258
|
+
* orchestrator-internal tokens).
|
|
259
|
+
*/
|
|
260
|
+
cap?: SidecarCapability[];
|
|
261
|
+
}, ttlMinutes: number): string;
|
|
262
|
+
/**
|
|
263
|
+
* Verify a sidecar JWT using Ed25519 public key. Rejects non-EdDSA tokens.
|
|
264
|
+
* Returns decoded payload on success, null on failure.
|
|
265
|
+
*/
|
|
266
|
+
declare function verifySidecarToken(token: string, publicKey: string, containerId: string): {
|
|
267
|
+
sub: string;
|
|
268
|
+
pid: string;
|
|
269
|
+
cid: string;
|
|
270
|
+
sid?: string;
|
|
271
|
+
typ: string;
|
|
272
|
+
jti?: string;
|
|
273
|
+
exp: number;
|
|
274
|
+
cap?: SidecarCapability[];
|
|
275
|
+
} | null;
|
|
276
|
+
/**
|
|
277
|
+
* Check if a token payload is session-scoped.
|
|
278
|
+
* Session-scoped tokens have a sid claim and no projectId/projectIds.
|
|
279
|
+
*/
|
|
280
|
+
declare function isSessionScopedToken(payload: ReadTokenPayload): payload is SessionScopedTokenPayload;
|
|
281
|
+
/**
|
|
282
|
+
* Check if a token payload is project-scoped.
|
|
283
|
+
* Project-scoped tokens have a projectId claim and no sid/projectIds.
|
|
284
|
+
*/
|
|
285
|
+
declare function isProjectScopedToken(payload: ReadTokenPayload): payload is ProjectScopedTokenPayload;
|
|
286
|
+
/**
|
|
287
|
+
* Check if a token payload is batch-scoped.
|
|
288
|
+
* Batch-scoped tokens have a projectIds claim and no sid/projectId.
|
|
289
|
+
*/
|
|
290
|
+
declare function isBatchScopedToken(payload: ReadTokenPayload): payload is BatchScopedTokenPayload;
|
|
291
|
+
/**
|
|
292
|
+
* Get the scope of a token payload.
|
|
293
|
+
* Returns null if the token has an invalid/ambiguous scope.
|
|
294
|
+
*/
|
|
295
|
+
declare function getTokenScope(payload: ReadTokenPayload): TokenScope | null;
|
|
296
|
+
/**
|
|
297
|
+
* Validate that a token payload has exactly one valid scope.
|
|
298
|
+
* Returns an error message if invalid, null if valid.
|
|
299
|
+
*/
|
|
300
|
+
declare function validateTokenScope(payload: ReadTokenPayload): string | null;
|
|
301
|
+
/**
|
|
302
|
+
* Decode a JWT without verification (to extract claims for lookup).
|
|
303
|
+
* Returns null if the token is malformed.
|
|
304
|
+
*/
|
|
305
|
+
declare function decodeToken(token: string): ReadTokenPayload | null;
|
|
306
|
+
/**
|
|
307
|
+
* Verify a read token against a product's signing secrets.
|
|
308
|
+
*
|
|
309
|
+
* @param token - The JWT token to verify
|
|
310
|
+
* @param product - Product auth info containing secrets
|
|
311
|
+
*/
|
|
312
|
+
declare function verifyReadToken(token: string, product: ProductAuthInfo): TokenValidationResult;
|
|
313
|
+
/**
|
|
314
|
+
* Get time until token expires (in seconds).
|
|
315
|
+
* Returns negative if expired.
|
|
316
|
+
*/
|
|
317
|
+
declare function getTokenTTL(payload: ReadTokenPayload): number;
|
|
318
|
+
/**
|
|
319
|
+
* Check if token is expiring soon (within buffer seconds).
|
|
320
|
+
*/
|
|
321
|
+
declare function isTokenExpiringSoon(payload: ReadTokenPayload, bufferSeconds?: number): boolean;
|
|
322
|
+
/**
|
|
323
|
+
* Hash an API key for storage/lookup.
|
|
324
|
+
* Uses HMAC-SHA256 for consistent, fast hashing.
|
|
325
|
+
*
|
|
326
|
+
* The salt can be configured via API_KEY_HASH_SALT environment variable.
|
|
327
|
+
* WARNING: Changing the salt will invalidate all existing API key hashes.
|
|
328
|
+
*/
|
|
329
|
+
declare function hashApiKey(apiKey: string): string;
|
|
330
|
+
/**
|
|
331
|
+
* Hash an API key with an explicit salt.
|
|
332
|
+
* Use this when you need to verify against a specific salt.
|
|
333
|
+
*/
|
|
334
|
+
declare function hashApiKeyWithSalt(apiKey: string, salt: string): string;
|
|
335
|
+
/**
|
|
336
|
+
* Verify an API key using timing-safe comparison.
|
|
337
|
+
*/
|
|
338
|
+
declare function verifyApiKey(provided: string, stored: string): boolean;
|
|
339
|
+
//#endregion
|
|
340
|
+
//#region src/auth/index.d.ts
|
|
341
|
+
/**
|
|
342
|
+
* Environment-based auth that reads from env vars.
|
|
343
|
+
* Matches the server-side patterns used in sidecar/orchestrator.
|
|
344
|
+
*/
|
|
345
|
+
declare class EnvTokenAuth {
|
|
346
|
+
private envVar;
|
|
347
|
+
private fallback?;
|
|
348
|
+
constructor(options: {
|
|
349
|
+
envVar: string;
|
|
350
|
+
fallback?: string;
|
|
351
|
+
});
|
|
352
|
+
getToken(): Promise<string | null>;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Pre-configured auth for sidecar connections.
|
|
356
|
+
* Uses SIDECAR_AUTH_TOKEN env var (matches server expectation).
|
|
357
|
+
*/
|
|
358
|
+
declare class SidecarAuth extends EnvTokenAuth {
|
|
359
|
+
constructor(token?: string);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Product-based auth for multi-tenant orchestrator connections.
|
|
363
|
+
* Uses ORCHESTRATOR_API_SECRET_KEY env var.
|
|
364
|
+
*/
|
|
365
|
+
declare class ProductAuth extends EnvTokenAuth {
|
|
366
|
+
constructor(apiKey?: string);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Product token issuer for backend services.
|
|
370
|
+
*
|
|
371
|
+
* Use this in product backends to issue read tokens for WebSocket connections.
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```typescript
|
|
375
|
+
* import { ProductTokenIssuer } from "@tangle-network/agent-core";
|
|
376
|
+
*
|
|
377
|
+
* const issuer = new ProductTokenIssuer({
|
|
378
|
+
* productId: "vibecode",
|
|
379
|
+
* signingSecret: process.env.ORCHESTRATOR_SIGNING_SECRET!,
|
|
380
|
+
* ttlMinutes: { free: 15, pro: 240 },
|
|
381
|
+
* });
|
|
382
|
+
*
|
|
383
|
+
* // Issue a token for a user session
|
|
384
|
+
* const token = issuer.issue({
|
|
385
|
+
* userId: "user_123",
|
|
386
|
+
* sessionId: "sess_abc",
|
|
387
|
+
* tier: "pro",
|
|
388
|
+
* });
|
|
389
|
+
*
|
|
390
|
+
* // Return token to frontend for WebSocket connection
|
|
391
|
+
* res.json({
|
|
392
|
+
* readToken: token.token,
|
|
393
|
+
* expiresAt: token.expiresAt,
|
|
394
|
+
* websocketUrl: `wss://orchestrator.example.com/session?token=${token.token}`,
|
|
395
|
+
* });
|
|
396
|
+
* ```
|
|
397
|
+
*/
|
|
398
|
+
declare class ProductTokenIssuer {
|
|
399
|
+
private readonly productId;
|
|
400
|
+
private readonly signingSecret;
|
|
401
|
+
private readonly ttlMinutes;
|
|
402
|
+
constructor(config: {
|
|
403
|
+
productId: string;
|
|
404
|
+
signingSecret: string; /** TTL in minutes for each tier (default: { free: 15, pro: 240 }) */
|
|
405
|
+
ttlMinutes?: {
|
|
406
|
+
free?: number;
|
|
407
|
+
pro?: number;
|
|
408
|
+
enterprise?: number;
|
|
409
|
+
};
|
|
410
|
+
});
|
|
411
|
+
/**
|
|
412
|
+
* Issue a read token for a user session.
|
|
413
|
+
*/
|
|
414
|
+
issue(params: {
|
|
415
|
+
userId: string;
|
|
416
|
+
sessionId: string;
|
|
417
|
+
tier?: "free" | "pro" | "enterprise";
|
|
418
|
+
sidecarId?: string;
|
|
419
|
+
}): {
|
|
420
|
+
token: string;
|
|
421
|
+
expiresAt: number;
|
|
422
|
+
};
|
|
423
|
+
/**
|
|
424
|
+
* Get the TTL in minutes for a tier.
|
|
425
|
+
*/
|
|
426
|
+
getTtlMinutes(tier?: "free" | "pro" | "enterprise"): number;
|
|
427
|
+
}
|
|
428
|
+
//#endregion
|
|
429
|
+
export { type AuthProvider, BatchScopedTokenPayload, BatchScopedTokenPayloadSchema, CallbackAuth, ChannelAccessResult, CreateSessionRequest, CreateSessionRequestSchema, CreateSessionResponse, EnvTokenAuth, NoAuth, Product, ProductAuth, ProductAuthInfo, ProductSchema, ProductSecrets, ProductTokenIssuer, ProjectScopedTokenPayload, ProjectScopedTokenPayloadSchema, READ_CAPABILITY_ROUTES, ReadTokenAuth, ReadTokenPayload, ReadTokenPayloadSchema, RefreshableTokenAuth, SIDECAR_CAPABILITY_ROUTES, SIDECAR_CAPABILITY_ROUTE_PATTERNS, SendMessageRequest, SendMessageRequestSchema, SessionScopedTokenPayload, SessionScopedTokenPayloadSchema, SidecarAuth, SidecarCapability, StaticTokenAuth, TokenScope, TokenValidationResult, authorizeSidecarToken, canBatchTokenAccessChannel, canProjectTokenAccessChannel, canSessionTokenAccessChannel, canTokenAccessChannel, decodeToken, extractProjectFromChannel, extractSessionFromChannel, generateApiKey, generateSecureToken, generateSidecarKeyPair, generateSigningSecret, getAllowedChannelPatterns, getTokenScope, getTokenTTL, hashApiKey, hashApiKeyWithSalt, isBatchScopedToken, isProjectScopedToken, isSessionScopedToken, isTokenExpiringSoon, issueBatchScopedToken, issueProjectScopedToken, issueReadToken, issueSessionScopedToken, issueSidecarAccessToken, requiredCapabilityForPath, validateChannelSubscription, validateTokenScope, verifyApiKey, verifyReadToken, verifySidecarToken };
|
|
430
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/auth/channel-access.ts","../../src/auth/tokens.ts","../../src/auth/index.ts"],"mappings":"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"}
|