@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
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { t as SDKError } from "./errors-DJ6U6cHY.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/auth/shared-providers.ts
|
|
4
|
+
/**
|
|
5
|
+
* Shared Auth Providers
|
|
6
|
+
*
|
|
7
|
+
* Browser-safe auth classes shared between index.ts and browser.ts.
|
|
8
|
+
* These classes have no node:crypto dependency and work in all environments.
|
|
9
|
+
*/
|
|
10
|
+
/** Simple static token auth */
|
|
11
|
+
var StaticTokenAuth = class {
|
|
12
|
+
constructor(token) {
|
|
13
|
+
this.token = token;
|
|
14
|
+
}
|
|
15
|
+
async getToken() {
|
|
16
|
+
return this.token;
|
|
17
|
+
}
|
|
18
|
+
setToken(token) {
|
|
19
|
+
this.token = token;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
/** Token with refresh capability */
|
|
23
|
+
var RefreshableTokenAuth = class {
|
|
24
|
+
accessToken;
|
|
25
|
+
refreshTokenValue;
|
|
26
|
+
expiresAt;
|
|
27
|
+
refreshPromise = null;
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this.config = config;
|
|
30
|
+
this.accessToken = config.accessToken;
|
|
31
|
+
this.refreshTokenValue = config.refreshToken;
|
|
32
|
+
this.expiresAt = Date.now() + config.expiresIn * 1e3;
|
|
33
|
+
}
|
|
34
|
+
async getToken() {
|
|
35
|
+
const buffer = (this.config.refreshBuffer ?? 60) * 1e3;
|
|
36
|
+
if (Date.now() > this.expiresAt - buffer) return this.refreshToken();
|
|
37
|
+
return this.accessToken;
|
|
38
|
+
}
|
|
39
|
+
async refreshToken() {
|
|
40
|
+
if (this.refreshPromise) return this.refreshPromise;
|
|
41
|
+
this.refreshPromise = this.doRefresh();
|
|
42
|
+
try {
|
|
43
|
+
return await this.refreshPromise;
|
|
44
|
+
} finally {
|
|
45
|
+
this.refreshPromise = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async doRefresh() {
|
|
49
|
+
try {
|
|
50
|
+
const result = await this.config.onRefresh(this.refreshTokenValue);
|
|
51
|
+
this.accessToken = result.accessToken;
|
|
52
|
+
if (result.refreshToken) this.refreshTokenValue = result.refreshToken;
|
|
53
|
+
this.expiresAt = Date.now() + result.expiresIn * 1e3;
|
|
54
|
+
return this.accessToken;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
this.config.onRefreshFailed?.(error instanceof Error ? error : new Error(String(error)));
|
|
57
|
+
throw new SDKError("Token refresh failed", {
|
|
58
|
+
code: "AUTH",
|
|
59
|
+
retryable: false,
|
|
60
|
+
cause: error instanceof Error ? error : void 0
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async onTokenRejected(error) {
|
|
65
|
+
if (error.status === 401) this.expiresAt = 0;
|
|
66
|
+
}
|
|
67
|
+
/** Check if token needs refresh */
|
|
68
|
+
isExpired() {
|
|
69
|
+
return Date.now() > this.expiresAt;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/** No auth (for public endpoints) */
|
|
73
|
+
var NoAuth = class {
|
|
74
|
+
async getToken() {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Callback-based auth for dynamic token retrieval.
|
|
80
|
+
* Useful when token comes from external source (user session, secure storage).
|
|
81
|
+
*/
|
|
82
|
+
var CallbackAuth = class {
|
|
83
|
+
constructor(getTokenFn) {
|
|
84
|
+
this.getTokenFn = getTokenFn;
|
|
85
|
+
}
|
|
86
|
+
async getToken() {
|
|
87
|
+
return this.getTokenFn();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Read token auth for WebSocket connections.
|
|
92
|
+
* Wraps a read token with refresh capability.
|
|
93
|
+
*/
|
|
94
|
+
var ReadTokenAuth = class {
|
|
95
|
+
token;
|
|
96
|
+
expiresAt;
|
|
97
|
+
refreshPromise = null;
|
|
98
|
+
expiryWarned = false;
|
|
99
|
+
constructor(config) {
|
|
100
|
+
this.config = config;
|
|
101
|
+
this.token = config.token;
|
|
102
|
+
this.expiresAt = config.expiresAt * 1e3;
|
|
103
|
+
}
|
|
104
|
+
async getToken() {
|
|
105
|
+
const now = Date.now();
|
|
106
|
+
const refreshBuffer = (this.config.refreshBuffer ?? 60) * 1e3;
|
|
107
|
+
const warningBuffer = (this.config.warningBuffer ?? 60) * 1e3;
|
|
108
|
+
if (!this.expiryWarned && now > this.expiresAt - warningBuffer) {
|
|
109
|
+
this.expiryWarned = true;
|
|
110
|
+
const secondsRemaining = Math.floor((this.expiresAt - now) / 1e3);
|
|
111
|
+
this.config.onExpiring?.(secondsRemaining);
|
|
112
|
+
}
|
|
113
|
+
if (now > this.expiresAt - refreshBuffer) return this.refreshToken();
|
|
114
|
+
return this.token;
|
|
115
|
+
}
|
|
116
|
+
async refreshToken() {
|
|
117
|
+
if (this.refreshPromise) return this.refreshPromise;
|
|
118
|
+
this.refreshPromise = this.doRefresh();
|
|
119
|
+
try {
|
|
120
|
+
return await this.refreshPromise;
|
|
121
|
+
} finally {
|
|
122
|
+
this.refreshPromise = null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async doRefresh() {
|
|
126
|
+
try {
|
|
127
|
+
const result = await this.config.onRefresh();
|
|
128
|
+
this.token = result.token;
|
|
129
|
+
this.expiresAt = result.expiresAt * 1e3;
|
|
130
|
+
this.expiryWarned = false;
|
|
131
|
+
return this.token;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
this.config.onRefreshFailed?.(error instanceof Error ? error : new Error(String(error)));
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Check if token is expired */
|
|
138
|
+
isExpired() {
|
|
139
|
+
return Date.now() > this.expiresAt;
|
|
140
|
+
}
|
|
141
|
+
/** Get seconds until expiry */
|
|
142
|
+
getSecondsRemaining() {
|
|
143
|
+
return Math.floor((this.expiresAt - Date.now()) / 1e3);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/auth/types.ts
|
|
148
|
+
/**
|
|
149
|
+
* Auth Types
|
|
150
|
+
*
|
|
151
|
+
* Type definitions for multi-tenant authentication.
|
|
152
|
+
*/
|
|
153
|
+
/**
|
|
154
|
+
* Product configuration for multi-tenant orchestrator.
|
|
155
|
+
*/
|
|
156
|
+
const ProductSchema = z.object({
|
|
157
|
+
/** Unique product identifier (e.g., "vibecode", "bgagents") */
|
|
158
|
+
product_id: z.string().min(1).max(64),
|
|
159
|
+
/** Human-readable name */
|
|
160
|
+
name: z.string().min(1).max(255),
|
|
161
|
+
/** API key for backend → orchestrator auth (format: orch_prod_{random}) */
|
|
162
|
+
api_key: z.string().min(32),
|
|
163
|
+
/** Signing secrets for JWT tokens */
|
|
164
|
+
secrets: z.object({
|
|
165
|
+
current: z.object({
|
|
166
|
+
secret: z.string().min(32),
|
|
167
|
+
created_at: z.number()
|
|
168
|
+
}),
|
|
169
|
+
previous: z.object({
|
|
170
|
+
secret: z.string().min(32),
|
|
171
|
+
created_at: z.number(),
|
|
172
|
+
expires_at: z.number()
|
|
173
|
+
}).optional()
|
|
174
|
+
}),
|
|
175
|
+
/** Token TTL configuration (minutes) */
|
|
176
|
+
token_config: z.object({
|
|
177
|
+
free_ttl_minutes: z.number().min(1).max(2880).default(15),
|
|
178
|
+
paid_ttl_minutes: z.number().min(1).max(2880).default(240),
|
|
179
|
+
max_ttl_minutes: z.number().min(1).max(2880).default(480)
|
|
180
|
+
}),
|
|
181
|
+
/** Per-product rate limits */
|
|
182
|
+
rate_limits: z.object({
|
|
183
|
+
max_concurrent_sessions: z.number().min(1).default(1e4),
|
|
184
|
+
max_sessions_per_minute: z.number().min(1).default(100),
|
|
185
|
+
max_requests_per_minute: z.number().min(1).default(1e3)
|
|
186
|
+
}),
|
|
187
|
+
/**
|
|
188
|
+
* When true, skip all quota checks and usage metering.
|
|
189
|
+
* Rate limits still enforced (DoS protection).
|
|
190
|
+
* Use for internal/company accounts that don't go through billing.
|
|
191
|
+
*/
|
|
192
|
+
unlimited: z.boolean().default(false),
|
|
193
|
+
/**
|
|
194
|
+
* Admin-only notes for internal tracking.
|
|
195
|
+
* Examples: "Engineering team", "Partner: Acme Corp", "Trial until 2024-03"
|
|
196
|
+
*/
|
|
197
|
+
internal_notes: z.string().max(1e3).optional(),
|
|
198
|
+
/** Optional webhook URL for notifications */
|
|
199
|
+
webhook_url: z.string().url().optional(),
|
|
200
|
+
/** Product status */
|
|
201
|
+
status: z.enum([
|
|
202
|
+
"active",
|
|
203
|
+
"suspended",
|
|
204
|
+
"deleted"
|
|
205
|
+
]).default("active"),
|
|
206
|
+
/** Deployment type: shared (multi-tenant) or customer-hosted (on-prem) */
|
|
207
|
+
deployment_type: z.enum(["shared", "customer-hosted"]).default("shared"),
|
|
208
|
+
/** Customer orchestrator configuration (for on-prem deployments) */
|
|
209
|
+
customer_orchestrator: z.object({
|
|
210
|
+
/** Customer's orchestrator URL (e.g., https://orch.customer.internal) */
|
|
211
|
+
url: z.string().url().startsWith("https://", { message: "Customer orchestrator URL must use HTTPS" }),
|
|
212
|
+
/** Customer's orchestrator API key */
|
|
213
|
+
api_key: z.string().min(32)
|
|
214
|
+
}).optional(),
|
|
215
|
+
/** Timestamps */
|
|
216
|
+
created_at: z.string().datetime(),
|
|
217
|
+
updated_at: z.string().datetime()
|
|
218
|
+
}).refine((data) => {
|
|
219
|
+
if (data.customer_orchestrator && data.deployment_type !== "customer-hosted") return false;
|
|
220
|
+
return true;
|
|
221
|
+
}, {
|
|
222
|
+
message: "customer_orchestrator can only be set when deployment_type is 'customer-hosted'",
|
|
223
|
+
path: ["customer_orchestrator"]
|
|
224
|
+
});
|
|
225
|
+
/**
|
|
226
|
+
* Base token payload (common fields for all scopes).
|
|
227
|
+
*/
|
|
228
|
+
const BaseTokenPayloadSchema = z.object({
|
|
229
|
+
/** Subject: User ID */
|
|
230
|
+
sub: z.string().min(1),
|
|
231
|
+
/** Product ID (used to look up signing secret) */
|
|
232
|
+
pid: z.string().min(1),
|
|
233
|
+
/** Sidecar/Container ID (optional, for direct routing) */
|
|
234
|
+
cid: z.string().optional(),
|
|
235
|
+
/** Token type (always "read" for read tokens) */
|
|
236
|
+
typ: z.literal("read"),
|
|
237
|
+
/** Issued at (Unix timestamp, seconds) */
|
|
238
|
+
iat: z.number(),
|
|
239
|
+
/** Expires at (Unix timestamp, seconds) */
|
|
240
|
+
exp: z.number()
|
|
241
|
+
});
|
|
242
|
+
/**
|
|
243
|
+
* Session-scoped token payload.
|
|
244
|
+
* Grants access to a single session's events.
|
|
245
|
+
*/
|
|
246
|
+
const SessionScopedTokenPayloadSchema = BaseTokenPayloadSchema.extend({
|
|
247
|
+
/** Session ID - required for session-scoped tokens */
|
|
248
|
+
sid: z.string().min(1),
|
|
249
|
+
/** Project ID - must not be present for session-scoped tokens */
|
|
250
|
+
projectId: z.undefined().optional(),
|
|
251
|
+
/** Project IDs - must not be present for session-scoped tokens */
|
|
252
|
+
projectIds: z.undefined().optional()
|
|
253
|
+
});
|
|
254
|
+
/**
|
|
255
|
+
* Project-scoped token payload.
|
|
256
|
+
* Grants access to all sessions within a single project.
|
|
257
|
+
*/
|
|
258
|
+
const ProjectScopedTokenPayloadSchema = BaseTokenPayloadSchema.extend({
|
|
259
|
+
/** Session ID - must not be present for project-scoped tokens */
|
|
260
|
+
sid: z.undefined().optional(),
|
|
261
|
+
/** Project ID - required for project-scoped tokens */
|
|
262
|
+
projectId: z.string().min(1),
|
|
263
|
+
/** Project IDs - must not be present for project-scoped tokens */
|
|
264
|
+
projectIds: z.undefined().optional()
|
|
265
|
+
});
|
|
266
|
+
/**
|
|
267
|
+
* Batch-scoped token payload.
|
|
268
|
+
* Grants access to multiple projects (organization-level access).
|
|
269
|
+
*/
|
|
270
|
+
const BatchScopedTokenPayloadSchema = BaseTokenPayloadSchema.extend({
|
|
271
|
+
/** Session ID - must not be present for batch-scoped tokens */
|
|
272
|
+
sid: z.undefined().optional(),
|
|
273
|
+
/** Project ID - must not be present for batch-scoped tokens */
|
|
274
|
+
projectId: z.undefined().optional(),
|
|
275
|
+
/** Project IDs - required for batch-scoped tokens */
|
|
276
|
+
projectIds: z.array(z.string().min(1)).min(1)
|
|
277
|
+
});
|
|
278
|
+
/**
|
|
279
|
+
* Read token payload (JWT claims for WebSocket auth).
|
|
280
|
+
*
|
|
281
|
+
* Supports three scopes:
|
|
282
|
+
* - Session: sid present (single session)
|
|
283
|
+
* - Project: projectId present (all sessions in project)
|
|
284
|
+
* - Batch: projectIds present (multiple projects)
|
|
285
|
+
*
|
|
286
|
+
* For backwards compatibility, tokens with sid are session-scoped.
|
|
287
|
+
*/
|
|
288
|
+
const ReadTokenPayloadSchema = z.union([
|
|
289
|
+
SessionScopedTokenPayloadSchema,
|
|
290
|
+
ProjectScopedTokenPayloadSchema,
|
|
291
|
+
BatchScopedTokenPayloadSchema
|
|
292
|
+
]);
|
|
293
|
+
/**
|
|
294
|
+
* Session creation request from product backend.
|
|
295
|
+
*/
|
|
296
|
+
const CreateSessionRequestSchema = z.object({
|
|
297
|
+
user_id: z.string().min(1),
|
|
298
|
+
project_ref: z.string().optional(),
|
|
299
|
+
tier: z.enum([
|
|
300
|
+
"free",
|
|
301
|
+
"pro",
|
|
302
|
+
"enterprise"
|
|
303
|
+
]).or(z.literal("paid").transform(() => "pro")).default("free"),
|
|
304
|
+
config: z.object({
|
|
305
|
+
image: z.string().optional(),
|
|
306
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
307
|
+
resources: z.object({
|
|
308
|
+
cpu: z.number().optional(),
|
|
309
|
+
memory: z.string().optional()
|
|
310
|
+
}).optional()
|
|
311
|
+
}).optional()
|
|
312
|
+
});
|
|
313
|
+
/**
|
|
314
|
+
* Message send request from product backend.
|
|
315
|
+
*
|
|
316
|
+
* `metadata` is intentionally free-form (.passthrough): the wire format
|
|
317
|
+
* accepts arbitrary product-specific keys without requiring a schema bump.
|
|
318
|
+
* Only `model` is named today; legacy gateway-credential fields previously
|
|
319
|
+
* declared here were never read internally and have been dropped — any
|
|
320
|
+
* such fields sent by older callers continue to flow through .passthrough.
|
|
321
|
+
*/
|
|
322
|
+
const SendMessageRequestSchema = z.object({
|
|
323
|
+
content: z.string(),
|
|
324
|
+
user_id: z.string().min(1),
|
|
325
|
+
execution_id: z.string().optional(),
|
|
326
|
+
metadata: z.object({ model: z.string().optional() }).passthrough().optional()
|
|
327
|
+
});
|
|
328
|
+
//#endregion
|
|
329
|
+
export { ReadTokenPayloadSchema as a, CallbackAuth as c, RefreshableTokenAuth as d, StaticTokenAuth as f, ProjectScopedTokenPayloadSchema as i, NoAuth as l, CreateSessionRequestSchema as n, SendMessageRequestSchema as o, ProductSchema as r, SessionScopedTokenPayloadSchema as s, BatchScopedTokenPayloadSchema as t, ReadTokenAuth as u };
|
|
330
|
+
|
|
331
|
+
//# sourceMappingURL=types-DC6OJ1um.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-DC6OJ1um.js","names":[],"sources":["../src/auth/shared-providers.ts","../src/auth/types.ts"],"sourcesContent":["/**\n * Shared Auth Providers\n *\n * Browser-safe auth classes shared between index.ts and browser.ts.\n * These classes have no node:crypto dependency and work in all environments.\n */\n\nimport { SDKError } from \"../errors/index.js\";\n\n/** Auth provider interface */\nexport interface AuthProvider {\n /** Get current token (called on each request) */\n getToken(): Promise<string | null>;\n /** Refresh expired token */\n refreshToken?(): Promise<string>;\n /** Called when token is rejected by server */\n onTokenRejected?(error: SDKError): Promise<void>;\n}\n\n/** Simple static token auth */\nexport class StaticTokenAuth implements AuthProvider {\n constructor(private token: string) {}\n\n async getToken(): Promise<string> {\n return this.token;\n }\n\n setToken(token: string): void {\n this.token = token;\n }\n}\n\n/** Token with refresh capability */\nexport class RefreshableTokenAuth implements AuthProvider {\n private accessToken: string;\n private refreshTokenValue: string;\n private expiresAt: number;\n private refreshPromise: Promise<string> | null = null;\n\n constructor(\n private config: {\n accessToken: string;\n refreshToken: string;\n expiresIn: number; // seconds\n onRefresh: (refreshToken: string) => Promise<{\n accessToken: string;\n refreshToken?: string;\n expiresIn: number;\n }>;\n onRefreshFailed?: (error: Error) => void;\n /** Buffer before expiry to trigger refresh (default: 60s) */\n refreshBuffer?: number;\n },\n ) {\n this.accessToken = config.accessToken;\n this.refreshTokenValue = config.refreshToken;\n this.expiresAt = Date.now() + config.expiresIn * 1000;\n }\n\n async getToken(): Promise<string> {\n const buffer = (this.config.refreshBuffer ?? 60) * 1000;\n\n // Proactively refresh if close to expiry\n if (Date.now() > this.expiresAt - buffer) {\n return this.refreshToken();\n }\n\n return this.accessToken;\n }\n\n async refreshToken(): Promise<string> {\n // Deduplicate concurrent refresh calls\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.doRefresh();\n\n try {\n return await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async doRefresh(): Promise<string> {\n try {\n const result = await this.config.onRefresh(this.refreshTokenValue);\n this.accessToken = result.accessToken;\n if (result.refreshToken) {\n this.refreshTokenValue = result.refreshToken;\n }\n this.expiresAt = Date.now() + result.expiresIn * 1000;\n return this.accessToken;\n } catch (error) {\n this.config.onRefreshFailed?.(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw new SDKError(\"Token refresh failed\", {\n code: \"AUTH\",\n retryable: false,\n cause: error instanceof Error ? error : undefined,\n });\n }\n }\n\n async onTokenRejected(error: SDKError): Promise<void> {\n // Force refresh on 401\n if (error.status === 401) {\n this.expiresAt = 0; // Mark as expired\n }\n }\n\n /** Check if token needs refresh */\n isExpired(): boolean {\n return Date.now() > this.expiresAt;\n }\n}\n\n/** No auth (for public endpoints) */\nexport class NoAuth implements AuthProvider {\n async getToken(): Promise<null> {\n return null;\n }\n}\n\n/**\n * Callback-based auth for dynamic token retrieval.\n * Useful when token comes from external source (user session, secure storage).\n */\nexport class CallbackAuth implements AuthProvider {\n constructor(\n private getTokenFn: () => string | null | Promise<string | null>,\n ) {}\n\n async getToken(): Promise<string | null> {\n return this.getTokenFn();\n }\n}\n\n/**\n * Read token auth for WebSocket connections.\n * Wraps a read token with refresh capability.\n */\nexport class ReadTokenAuth implements AuthProvider {\n private token: string;\n private expiresAt: number;\n private refreshPromise: Promise<string> | null = null;\n private expiryWarned = false;\n\n constructor(\n private config: {\n token: string;\n expiresAt: number; // Unix timestamp (seconds)\n onRefresh: () => Promise<{ token: string; expiresAt: number }>;\n onExpiring?: (secondsRemaining: number) => void;\n onRefreshFailed?: (error: Error) => void;\n /** Buffer before expiry to trigger refresh (default: 60s) */\n refreshBuffer?: number;\n /** Buffer before expiry to trigger warning (default: 60s) */\n warningBuffer?: number;\n },\n ) {\n this.token = config.token;\n this.expiresAt = config.expiresAt * 1000; // Convert to ms\n }\n\n async getToken(): Promise<string> {\n const now = Date.now();\n const refreshBuffer = (this.config.refreshBuffer ?? 60) * 1000;\n const warningBuffer = (this.config.warningBuffer ?? 60) * 1000;\n\n // Warn if expiring soon\n if (!this.expiryWarned && now > this.expiresAt - warningBuffer) {\n this.expiryWarned = true;\n const secondsRemaining = Math.floor((this.expiresAt - now) / 1000);\n this.config.onExpiring?.(secondsRemaining);\n }\n\n // Proactively refresh if close to expiry\n if (now > this.expiresAt - refreshBuffer) {\n return this.refreshToken();\n }\n\n return this.token;\n }\n\n async refreshToken(): Promise<string> {\n // Deduplicate concurrent refresh calls\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.doRefresh();\n\n try {\n return await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async doRefresh(): Promise<string> {\n try {\n const result = await this.config.onRefresh();\n this.token = result.token;\n this.expiresAt = result.expiresAt * 1000;\n this.expiryWarned = false;\n return this.token;\n } catch (error) {\n this.config.onRefreshFailed?.(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n /** Check if token is expired */\n isExpired(): boolean {\n return Date.now() > this.expiresAt;\n }\n\n /** Get seconds until expiry */\n getSecondsRemaining(): number {\n return Math.floor((this.expiresAt - Date.now()) / 1000);\n }\n}\n","/**\n * Auth Types\n *\n * Type definitions for multi-tenant authentication.\n */\n\nimport { z } from \"zod\";\n\n/**\n * Product configuration for multi-tenant orchestrator.\n */\nexport const ProductSchema = z\n .object({\n /** Unique product identifier (e.g., \"vibecode\", \"bgagents\") */\n product_id: z.string().min(1).max(64),\n\n /** Human-readable name */\n name: z.string().min(1).max(255),\n\n /** API key for backend → orchestrator auth (format: orch_prod_{random}) */\n api_key: z.string().min(32),\n\n /** Signing secrets for JWT tokens */\n secrets: z.object({\n current: z.object({\n secret: z.string().min(32),\n created_at: z.number(),\n }),\n previous: z\n .object({\n secret: z.string().min(32),\n created_at: z.number(),\n expires_at: z.number(),\n })\n .optional(),\n }),\n\n /** Token TTL configuration (minutes) */\n token_config: z.object({\n free_ttl_minutes: z.number().min(1).max(2880).default(15),\n paid_ttl_minutes: z.number().min(1).max(2880).default(240),\n max_ttl_minutes: z.number().min(1).max(2880).default(480),\n }),\n\n /** Per-product rate limits */\n rate_limits: z.object({\n max_concurrent_sessions: z.number().min(1).default(10000),\n max_sessions_per_minute: z.number().min(1).default(100),\n max_requests_per_minute: z.number().min(1).default(1000),\n }),\n\n /**\n * When true, skip all quota checks and usage metering.\n * Rate limits still enforced (DoS protection).\n * Use for internal/company accounts that don't go through billing.\n */\n unlimited: z.boolean().default(false),\n\n /**\n * Admin-only notes for internal tracking.\n * Examples: \"Engineering team\", \"Partner: Acme Corp\", \"Trial until 2024-03\"\n */\n internal_notes: z.string().max(1000).optional(),\n\n /** Optional webhook URL for notifications */\n webhook_url: z.string().url().optional(),\n\n /** Product status */\n status: z.enum([\"active\", \"suspended\", \"deleted\"]).default(\"active\"),\n\n /** Deployment type: shared (multi-tenant) or customer-hosted (on-prem) */\n deployment_type: z.enum([\"shared\", \"customer-hosted\"]).default(\"shared\"),\n\n /** Customer orchestrator configuration (for on-prem deployments) */\n customer_orchestrator: z\n .object({\n /** Customer's orchestrator URL (e.g., https://orch.customer.internal) */\n url: z.string().url().startsWith(\"https://\", {\n message: \"Customer orchestrator URL must use HTTPS\",\n }),\n /** Customer's orchestrator API key */\n api_key: z.string().min(32),\n })\n .optional(),\n\n /** Timestamps */\n created_at: z.string().datetime(),\n updated_at: z.string().datetime(),\n })\n .refine(\n (data) => {\n if (\n data.customer_orchestrator &&\n data.deployment_type !== \"customer-hosted\"\n ) {\n return false;\n }\n return true;\n },\n {\n message:\n \"customer_orchestrator can only be set when deployment_type is 'customer-hosted'\",\n path: [\"customer_orchestrator\"],\n },\n );\n\nexport type Product = z.infer<typeof ProductSchema>;\n\n/**\n * Token scope types for multi-tenant access control.\n *\n * - \"session\": Access to a single session (requires sid)\n * - \"project\": Access to all sessions within a project (requires projectId)\n * - \"batch\": Access to multiple projects (requires projectIds array)\n */\nexport type TokenScope = \"session\" | \"project\" | \"batch\";\n\n/**\n * Base token payload (common fields for all scopes).\n */\nconst BaseTokenPayloadSchema = z.object({\n /** Subject: User ID */\n sub: z.string().min(1),\n\n /** Product ID (used to look up signing secret) */\n pid: z.string().min(1),\n\n /** Sidecar/Container ID (optional, for direct routing) */\n cid: z.string().optional(),\n\n /** Token type (always \"read\" for read tokens) */\n typ: z.literal(\"read\"),\n\n /** Issued at (Unix timestamp, seconds) */\n iat: z.number(),\n\n /** Expires at (Unix timestamp, seconds) */\n exp: z.number(),\n});\n\n/**\n * Session-scoped token payload.\n * Grants access to a single session's events.\n */\nexport const SessionScopedTokenPayloadSchema = BaseTokenPayloadSchema.extend({\n /** Session ID - required for session-scoped tokens */\n sid: z.string().min(1),\n /** Project ID - must not be present for session-scoped tokens */\n projectId: z.undefined().optional(),\n /** Project IDs - must not be present for session-scoped tokens */\n projectIds: z.undefined().optional(),\n});\n\n/**\n * Project-scoped token payload.\n * Grants access to all sessions within a single project.\n */\nexport const ProjectScopedTokenPayloadSchema = BaseTokenPayloadSchema.extend({\n /** Session ID - must not be present for project-scoped tokens */\n sid: z.undefined().optional(),\n /** Project ID - required for project-scoped tokens */\n projectId: z.string().min(1),\n /** Project IDs - must not be present for project-scoped tokens */\n projectIds: z.undefined().optional(),\n});\n\n/**\n * Batch-scoped token payload.\n * Grants access to multiple projects (organization-level access).\n */\nexport const BatchScopedTokenPayloadSchema = BaseTokenPayloadSchema.extend({\n /** Session ID - must not be present for batch-scoped tokens */\n sid: z.undefined().optional(),\n /** Project ID - must not be present for batch-scoped tokens */\n projectId: z.undefined().optional(),\n /** Project IDs - required for batch-scoped tokens */\n projectIds: z.array(z.string().min(1)).min(1),\n});\n\n/**\n * Read token payload (JWT claims for WebSocket auth).\n *\n * Supports three scopes:\n * - Session: sid present (single session)\n * - Project: projectId present (all sessions in project)\n * - Batch: projectIds present (multiple projects)\n *\n * For backwards compatibility, tokens with sid are session-scoped.\n */\nexport const ReadTokenPayloadSchema = z.union([\n SessionScopedTokenPayloadSchema,\n ProjectScopedTokenPayloadSchema,\n BatchScopedTokenPayloadSchema,\n]);\n\nexport type ReadTokenPayload = z.infer<typeof ReadTokenPayloadSchema>;\nexport type SessionScopedTokenPayload = z.infer<\n typeof SessionScopedTokenPayloadSchema\n>;\nexport type ProjectScopedTokenPayload = z.infer<\n typeof ProjectScopedTokenPayloadSchema\n>;\nexport type BatchScopedTokenPayload = z.infer<\n typeof BatchScopedTokenPayloadSchema\n>;\n\n/**\n * Token validation result.\n */\nexport interface TokenValidationResult {\n valid: boolean;\n payload?: ReadTokenPayload;\n /** Token scope (session, project, or batch) */\n scope?: TokenScope;\n error?: string;\n errorCode?:\n | \"TOKEN_MISSING\"\n | \"TOKEN_INVALID\"\n | \"TOKEN_EXPIRED\"\n | \"TOKEN_WRONG_TYPE\"\n | \"PRODUCT_NOT_FOUND\"\n | \"PRODUCT_SUSPENDED\"\n | \"SIGNATURE_INVALID\";\n}\n\n/**\n * Product secrets structure.\n */\nexport interface ProductSecrets {\n current: {\n secret: string;\n created_at: number;\n };\n previous?: {\n secret: string;\n created_at: number;\n expires_at: number;\n };\n}\n\n/**\n * Minimal product info for token validation (avoids full product lookup).\n */\nexport interface ProductAuthInfo {\n product_id: string;\n secrets: ProductSecrets;\n status: \"active\" | \"suspended\" | \"deleted\";\n}\n\n/**\n * Session creation request from product backend.\n */\nexport const CreateSessionRequestSchema = z.object({\n user_id: z.string().min(1),\n project_ref: z.string().optional(),\n tier: z\n .enum([\"free\", \"pro\", \"enterprise\"])\n .or(z.literal(\"paid\").transform(() => \"pro\" as const))\n .default(\"free\"),\n config: z\n .object({\n image: z.string().optional(),\n env: z.record(z.string(), z.string()).optional(),\n resources: z\n .object({\n cpu: z.number().optional(),\n memory: z.string().optional(),\n })\n .optional(),\n })\n .optional(),\n});\n\nexport type CreateSessionRequest = z.infer<typeof CreateSessionRequestSchema>;\n\n/**\n * Session creation response to product backend.\n */\nexport interface CreateSessionResponse {\n session_id: string;\n sidecar_id: string;\n websocket_url: string;\n}\n\n/**\n * Message send request from product backend.\n *\n * `metadata` is intentionally free-form (.passthrough): the wire format\n * accepts arbitrary product-specific keys without requiring a schema bump.\n * Only `model` is named today; legacy gateway-credential fields previously\n * declared here were never read internally and have been dropped — any\n * such fields sent by older callers continue to flow through .passthrough.\n */\nexport const SendMessageRequestSchema = z.object({\n content: z.string(),\n user_id: z.string().min(1),\n execution_id: z.string().optional(),\n metadata: z\n .object({\n model: z.string().optional(),\n })\n .passthrough()\n .optional(),\n});\n\nexport type SendMessageRequest = z.infer<typeof SendMessageRequestSchema>;\n"],"mappings":"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"}
|