@slashfi/agents-sdk 0.4.0 → 0.6.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.
Files changed (65) hide show
  1. package/dist/{auth.d.ts → agent-definitions/auth.d.ts} +36 -2
  2. package/dist/agent-definitions/auth.d.ts.map +1 -0
  3. package/dist/{auth.js → agent-definitions/auth.js} +69 -8
  4. package/dist/agent-definitions/auth.js.map +1 -0
  5. package/dist/agent-definitions/integrations.d.ts +162 -0
  6. package/dist/agent-definitions/integrations.d.ts.map +1 -0
  7. package/dist/agent-definitions/integrations.js +861 -0
  8. package/dist/agent-definitions/integrations.js.map +1 -0
  9. package/dist/agent-definitions/secrets.d.ts +51 -0
  10. package/dist/agent-definitions/secrets.d.ts.map +1 -0
  11. package/dist/agent-definitions/secrets.js +165 -0
  12. package/dist/agent-definitions/secrets.js.map +1 -0
  13. package/dist/agent-definitions/users.d.ts +80 -0
  14. package/dist/agent-definitions/users.d.ts.map +1 -0
  15. package/dist/agent-definitions/users.js +397 -0
  16. package/dist/agent-definitions/users.js.map +1 -0
  17. package/dist/crypto.d.ts +14 -0
  18. package/dist/crypto.d.ts.map +1 -0
  19. package/dist/crypto.js +40 -0
  20. package/dist/crypto.js.map +1 -0
  21. package/dist/define.d.ts +6 -1
  22. package/dist/define.d.ts.map +1 -1
  23. package/dist/define.js +1 -0
  24. package/dist/define.js.map +1 -1
  25. package/dist/index.d.ts +10 -5
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +9 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/jwt.d.ts +2 -0
  30. package/dist/jwt.d.ts.map +1 -1
  31. package/dist/jwt.js.map +1 -1
  32. package/dist/server.d.ts +28 -1
  33. package/dist/server.d.ts.map +1 -1
  34. package/dist/server.js +478 -27
  35. package/dist/server.js.map +1 -1
  36. package/dist/slack-oauth.d.ts +27 -0
  37. package/dist/slack-oauth.d.ts.map +1 -0
  38. package/dist/slack-oauth.js +48 -0
  39. package/dist/slack-oauth.js.map +1 -0
  40. package/dist/types.d.ts +66 -0
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/web-pages.d.ts +8 -0
  43. package/dist/web-pages.d.ts.map +1 -0
  44. package/dist/web-pages.js +169 -0
  45. package/dist/web-pages.js.map +1 -0
  46. package/package.json +2 -1
  47. package/src/{auth.ts → agent-definitions/auth.ts} +134 -15
  48. package/src/agent-definitions/integrations.ts +1209 -0
  49. package/src/agent-definitions/secrets.ts +241 -0
  50. package/src/agent-definitions/users.ts +533 -0
  51. package/src/crypto.ts +71 -0
  52. package/src/define.ts +8 -0
  53. package/src/index.ts +62 -4
  54. package/src/jwt.ts +9 -5
  55. package/src/server.ts +567 -35
  56. package/src/slack-oauth.ts +66 -0
  57. package/src/types.ts +83 -0
  58. package/src/web-pages.ts +178 -0
  59. package/dist/auth.d.ts.map +0 -1
  60. package/dist/auth.js.map +0 -1
  61. package/dist/secrets.d.ts +0 -44
  62. package/dist/secrets.d.ts.map +0 -1
  63. package/dist/secrets.js +0 -106
  64. package/dist/secrets.js.map +0 -1
  65. package/src/secrets.ts +0 -154
@@ -24,9 +24,9 @@
24
24
  * ```
25
25
  */
26
26
 
27
- import { defineAgent, defineTool } from "./define.js";
28
- import type { AgentDefinition, ToolContext, ToolDefinition } from "./types.js";
29
- import { signJwt } from "./jwt.js";
27
+ import { defineAgent, defineTool } from "../define.js";
28
+ import { signJwt } from "../jwt.js";
29
+ import type { AgentDefinition, ToolContext, ToolDefinition } from "../types.js";
30
30
 
31
31
  // ============================================
32
32
  // Auth Types
@@ -35,6 +35,7 @@ import { signJwt } from "./jwt.js";
35
35
  /** Registered client */
36
36
  export interface AuthClient {
37
37
  clientId: string;
38
+ tenantId?: string;
38
39
  clientSecretHash: string;
39
40
  name: string;
40
41
  scopes: string[];
@@ -68,12 +69,32 @@ export interface AuthIdentity {
68
69
  * Pluggable storage for auth state.
69
70
  * Implement this interface to use Postgres, Redis, SQLite, etc.
70
71
  */
72
+
73
+ /**
74
+ * Tenant - organizational unit for multi-tenant isolation.
75
+ */
76
+ export interface AuthTenant {
77
+ id: string;
78
+ name: string;
79
+ createdAt: number;
80
+ }
81
+
71
82
  export interface AuthStore {
83
+ /** Create a tenant. */
84
+ createTenant(name: string): Promise<{ tenantId: string }>;
85
+
86
+ /** Get tenant by ID. */
87
+ getTenant(tenantId: string): Promise<AuthTenant | null>;
88
+
89
+ /** List tenants. */
90
+ listTenants(): Promise<AuthTenant[]>;
91
+
72
92
  /** Create a new client. Returns the raw (unhashed) secret. */
73
93
  createClient(
74
94
  name: string,
75
95
  scopes: string[],
76
96
  selfRegistered?: boolean,
97
+ tenantId?: string,
77
98
  ): Promise<{ clientId: string; clientSecret: string }>;
78
99
 
79
100
  /** Validate client credentials. Returns client if valid, null otherwise. */
@@ -102,6 +123,28 @@ export interface AuthStore {
102
123
 
103
124
  /** Revoke a specific token. */
104
125
  revokeToken(tokenString: string): Promise<boolean>;
126
+
127
+ /** Register a user under a tenant. Returns a refresh token. */
128
+ registerUser?(
129
+ tenantId: string,
130
+ userId: string,
131
+ clientId: string,
132
+ ): Promise<{ refreshToken: string }>;
133
+
134
+ /** Validate a refresh token. Returns user info. */
135
+ validateRefreshToken?(
136
+ refreshToken: string,
137
+ ): Promise<{ tenantId: string; userId: string; clientId: string } | null>;
138
+
139
+ /** Rotate a refresh token. */
140
+ rotateRefreshToken?(
141
+ oldToken: string,
142
+ ): Promise<{
143
+ refreshToken: string;
144
+ tenantId: string;
145
+ userId: string;
146
+ clientId: string;
147
+ } | null>;
105
148
  }
106
149
 
107
150
  // ============================================
@@ -127,8 +170,6 @@ function generateSecret(): string {
127
170
  return secret;
128
171
  }
129
172
 
130
-
131
-
132
173
  /** Simple hash for storing secrets (not for production - use bcrypt/argon2) */
133
174
  async function hashSecret(secret: string): Promise<string> {
134
175
  const encoder = new TextEncoder();
@@ -144,17 +185,33 @@ async function hashSecret(secret: string): Promise<string> {
144
185
  * Suitable for development and testing. Use a persistent store for production.
145
186
  */
146
187
  export function createMemoryAuthStore(): AuthStore {
188
+ const tenants = new Map<string, AuthTenant>();
147
189
  const clients = new Map<string, AuthClient>();
148
190
  const tokens = new Map<string, AuthToken>();
149
191
 
150
192
  return {
151
- async createClient(name, scopes, selfRegistered) {
193
+ async createTenant(name) {
194
+ const id = `tenant_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
195
+ tenants.set(id, { id, name, createdAt: Date.now() });
196
+ return { tenantId: id };
197
+ },
198
+
199
+ async getTenant(tenantId) {
200
+ return tenants.get(tenantId) ?? null;
201
+ },
202
+
203
+ async listTenants() {
204
+ return Array.from(tenants.values());
205
+ },
206
+
207
+ async createClient(name, scopes, selfRegistered, tenantId) {
152
208
  const clientId = generateId("ag_");
153
209
  const clientSecret = generateSecret();
154
210
  const secretHash = await hashSecret(clientSecret);
155
211
 
156
212
  clients.set(clientId, {
157
213
  clientId,
214
+ tenantId,
158
215
  clientSecretHash: secretHash,
159
216
  name,
160
217
  scopes,
@@ -195,7 +252,9 @@ export function createMemoryAuthStore(): AuthStore {
195
252
  if (!client) return null;
196
253
  const clientSecret = generateSecret();
197
254
  client.clientSecretHash = await hashSecret(clientSecret);
198
- return { clientSecret };
255
+ return {
256
+ clientSecret: { $agent_type: "secret", value: clientSecret },
257
+ } as any;
199
258
  },
200
259
 
201
260
  async storeToken(token) {
@@ -266,6 +325,24 @@ export function createAuthAgent(
266
325
 
267
326
  // --- Public Tools ---
268
327
 
328
+ const createTenantTool = defineTool({
329
+ name: "create_tenant",
330
+ description:
331
+ "Create a new tenant (organizational unit). All clients and resources are scoped to a tenant.",
332
+ visibility: "public" as const,
333
+ inputSchema: {
334
+ type: "object" as const,
335
+ properties: {
336
+ name: { type: "string" as const, description: "Tenant name" },
337
+ },
338
+ required: ["name"],
339
+ },
340
+ execute: async (input: { name: string }) => {
341
+ const result = await store.createTenant(input.name);
342
+ return { tenantId: result.tenantId, name: input.name };
343
+ },
344
+ });
345
+
269
346
  const tokenTool = defineTool({
270
347
  name: "token",
271
348
  description:
@@ -286,16 +363,47 @@ export function createAuthAgent(
286
363
  },
287
364
  execute: async (input: {
288
365
  grantType: string;
289
- clientId: string;
290
- clientSecret: string;
366
+ clientId?: string;
367
+ clientSecret?: string;
368
+ userId?: string;
369
+ refreshToken?: string;
291
370
  }) => {
371
+ if (input.grantType === "refresh_token") {
372
+ if (!input.refreshToken)
373
+ throw new Error("refreshToken is required for refresh_token grant");
374
+ if (!store.rotateRefreshToken)
375
+ throw new Error("Refresh tokens not supported by this store");
376
+ const result = await store.rotateRefreshToken(input.refreshToken);
377
+ if (!result) throw new Error("Invalid or expired refresh token");
378
+ const now = Math.floor(Date.now() / 1000);
379
+ const jwt = await signJwt(
380
+ {
381
+ sub: result.clientId,
382
+ name: result.userId,
383
+ tenantId: result.tenantId,
384
+ scopes: [],
385
+ iat: now,
386
+ exp: now + tokenTtl,
387
+ },
388
+ (await store.getClient(result.clientId))?.clientSecretHash ?? "",
389
+ );
390
+ return {
391
+ accessToken: { $agent_type: "secret", value: jwt },
392
+ refreshToken: { $agent_type: "secret", value: result.refreshToken },
393
+ tokenType: "bearer",
394
+ expiresIn: tokenTtl,
395
+ } as any;
396
+ }
397
+
292
398
  if (input.grantType !== "client_credentials") {
293
- throw new Error("Unsupported grant type. Use 'client_credentials'.");
399
+ throw new Error(
400
+ "Unsupported grant type. Use 'client_credentials' or 'refresh_token'.",
401
+ );
294
402
  }
295
403
 
296
404
  const client = await store.validateClient(
297
- input.clientId,
298
- input.clientSecret,
405
+ input.clientId!,
406
+ input.clientSecret!,
299
407
  );
300
408
  if (!client) {
301
409
  throw new Error("Invalid client credentials");
@@ -306,6 +414,7 @@ export function createAuthAgent(
306
414
  {
307
415
  sub: client.clientId,
308
416
  name: client.name,
417
+ tenantId: client.tenantId,
309
418
  scopes: client.scopes,
310
419
  iat: now,
311
420
  exp: now + tokenTtl,
@@ -314,7 +423,7 @@ export function createAuthAgent(
314
423
  );
315
424
 
316
425
  return {
317
- accessToken: jwt,
426
+ accessToken: { $agent_type: "secret", value: jwt },
318
427
  tokenType: "bearer",
319
428
  expiresIn: tokenTtl,
320
429
  scopes: client.scopes,
@@ -355,7 +464,11 @@ export function createAuthAgent(
355
464
  },
356
465
  required: ["name"],
357
466
  },
358
- execute: async (input: { name: string; scopes?: string[] }) => {
467
+ execute: async (input: {
468
+ name: string;
469
+ tenantId: string;
470
+ scopes?: string[];
471
+ }) => {
359
472
  let scopes = input.scopes ?? [];
360
473
 
361
474
  // If registration scopes are restricted, filter
@@ -367,9 +480,14 @@ export function createAuthAgent(
367
480
  input.name,
368
481
  scopes,
369
482
  true,
483
+ input.tenantId,
370
484
  );
371
485
 
372
- return { clientId, clientSecret, scopes };
486
+ return {
487
+ clientId,
488
+ clientSecret: { $agent_type: "secret", value: clientSecret },
489
+ scopes,
490
+ } as any;
373
491
  },
374
492
  });
375
493
 
@@ -457,6 +575,7 @@ export function createAuthAgent(
457
575
  // --- Assemble tools ---
458
576
 
459
577
  const tools = [
578
+ createTenantTool,
460
579
  tokenTool,
461
580
  whoamiTool,
462
581
  ...(allowRegistration ? [registerTool] : []),