kavachos 0.1.0 → 0.1.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.
Files changed (46) hide show
  1. package/dist/a2a/index.d.ts +1 -1
  2. package/dist/a2a/index.js +7 -2
  3. package/dist/a2a/index.js.map +1 -1
  4. package/dist/agent/index.d.ts +2 -2
  5. package/dist/agent/index.js +789 -4
  6. package/dist/agent/index.js.map +1 -1
  7. package/dist/audit/index.d.ts +1 -1
  8. package/dist/audit/index.js +635 -3
  9. package/dist/audit/index.js.map +1 -1
  10. package/dist/auth/index.d.ts +599 -3
  11. package/dist/auth/index.js +14668 -4
  12. package/dist/auth/index.js.map +1 -1
  13. package/dist/crypto/index.js +184 -2
  14. package/dist/crypto/index.js.map +1 -1
  15. package/dist/index.d.ts +247 -4
  16. package/dist/index.js +16598 -157
  17. package/dist/index.js.map +1 -1
  18. package/dist/mcp/index.js +19 -2
  19. package/dist/mcp/index.js.map +1 -1
  20. package/dist/permission/index.d.ts +2 -2
  21. package/dist/permission/index.js +790 -4
  22. package/dist/permission/index.js.map +1 -1
  23. package/dist/redirect/index.js +290 -3
  24. package/dist/redirect/index.js.map +1 -1
  25. package/dist/{types-6D7iJvGD.d.ts → types-5Ua5KlPc.d.ts} +218 -4
  26. package/dist/vc/index.js +542 -3
  27. package/dist/vc/index.js.map +1 -1
  28. package/package.json +29 -13
  29. package/dist/chunk-IEOOSOJ4.js +0 -12558
  30. package/dist/chunk-IEOOSOJ4.js.map +0 -1
  31. package/dist/chunk-IKTOSJ4O.js +0 -214
  32. package/dist/chunk-IKTOSJ4O.js.map +0 -1
  33. package/dist/chunk-KDL6A76K.js +0 -569
  34. package/dist/chunk-KDL6A76K.js.map +0 -1
  35. package/dist/chunk-NSBPE2FW.js +0 -15
  36. package/dist/chunk-NSBPE2FW.js.map +0 -1
  37. package/dist/chunk-NSTER7KE.js +0 -538
  38. package/dist/chunk-NSTER7KE.js.map +0 -1
  39. package/dist/chunk-QCRHJMDX.js +0 -186
  40. package/dist/chunk-QCRHJMDX.js.map +0 -1
  41. package/dist/chunk-VHKZARMM.js +0 -251
  42. package/dist/chunk-VHKZARMM.js.map +0 -1
  43. package/dist/chunk-Y3OWAJHK.js +0 -101
  44. package/dist/chunk-Y3OWAJHK.js.map +0 -1
  45. package/dist/chunk-YARXM6MQ.js +0 -288
  46. package/dist/chunk-YARXM6MQ.js.map +0 -1
@@ -1,6 +1,791 @@
1
- export { createAgentModule } from '../chunk-IKTOSJ4O.js';
2
- import '../chunk-KDL6A76K.js';
3
- import '../chunk-QCRHJMDX.js';
4
- import '../chunk-NSBPE2FW.js';
1
+ import { and, eq } from 'drizzle-orm';
2
+ import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
3
+
4
+ // src/agent/agent.ts
5
+
6
+ // src/crypto/web-crypto.ts
7
+ var HEX_CHARS = "0123456789abcdef";
8
+ function toHex(bytes) {
9
+ let hex = "";
10
+ for (let i = 0; i < bytes.length; i++) {
11
+ const b = bytes[i];
12
+ hex += HEX_CHARS[b >> 4];
13
+ hex += HEX_CHARS[b & 15];
14
+ }
15
+ return hex;
16
+ }
17
+ function toBase64Url(bytes) {
18
+ let binary = "";
19
+ for (let i = 0; i < bytes.length; i++) {
20
+ binary += String.fromCharCode(bytes[i]);
21
+ }
22
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
23
+ }
24
+ function generateId() {
25
+ return globalThis.crypto.randomUUID();
26
+ }
27
+ function randomBytes(length) {
28
+ const bytes = new Uint8Array(length);
29
+ globalThis.crypto.getRandomValues(bytes);
30
+ return bytes;
31
+ }
32
+ var TEXT_ENCODER = new TextEncoder();
33
+ function toBytes(data) {
34
+ if (typeof data === "string") {
35
+ const encoded = TEXT_ENCODER.encode(data);
36
+ return encoded.buffer.slice(
37
+ encoded.byteOffset,
38
+ encoded.byteOffset + encoded.byteLength
39
+ );
40
+ }
41
+ return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
42
+ }
43
+ async function sha256(data) {
44
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", toBytes(data));
45
+ return toHex(new Uint8Array(digest));
46
+ }
47
+ var users = sqliteTable("kavach_users", {
48
+ id: text("id").primaryKey(),
49
+ email: text("email").notNull().unique(),
50
+ name: text("name"),
51
+ username: text("username").unique(),
52
+ externalId: text("external_id"),
53
+ // ID from external auth (better-auth, Auth.js, etc.)
54
+ externalProvider: text("external_provider"),
55
+ // "better-auth", "authjs", "clerk", etc.
56
+ metadata: text("metadata", { mode: "json" }).$type(),
57
+ // Admin ban fields (populated by admin module)
58
+ banned: integer("banned").notNull().default(0),
59
+ banReason: text("ban_reason"),
60
+ banExpiresAt: integer("ban_expires_at", { mode: "timestamp" }),
61
+ forcePasswordReset: integer("force_password_reset").notNull().default(0),
62
+ emailVerified: integer("email_verified").notNull().default(0),
63
+ // Stripe integration fields (populated by kavach-stripe plugin)
64
+ stripeCustomerId: text("stripe_customer_id").unique(),
65
+ stripeSubscriptionId: text("stripe_subscription_id"),
66
+ stripeSubscriptionStatus: text("stripe_subscription_status"),
67
+ stripePriceId: text("stripe_price_id"),
68
+ stripeCurrentPeriodEnd: integer("stripe_current_period_end", { mode: "timestamp" }),
69
+ stripeCancelAtPeriodEnd: integer("stripe_cancel_at_period_end", { mode: "boolean" }).notNull().default(false),
70
+ // Polar integration fields (populated by kavach-polar plugin)
71
+ polarCustomerId: text("polar_customer_id").unique(),
72
+ polarSubscriptionId: text("polar_subscription_id"),
73
+ polarSubscriptionStatus: text("polar_subscription_status"),
74
+ polarProductId: text("polar_product_id"),
75
+ polarCurrentPeriodEnd: integer("polar_current_period_end", { mode: "timestamp" }),
76
+ polarCancelAtPeriodEnd: integer("polar_cancel_at_period_end", { mode: "boolean" }).notNull().default(false),
77
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
78
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
79
+ });
80
+ var tenants = sqliteTable("kavach_tenants", {
81
+ id: text("id").primaryKey(),
82
+ name: text("name").notNull(),
83
+ slug: text("slug").notNull().unique(),
84
+ settings: text("settings", { mode: "json" }).$type(),
85
+ status: text("status", { enum: ["active", "suspended"] }).notNull().default("active"),
86
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
87
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
88
+ });
89
+ var agents = sqliteTable("kavach_agents", {
90
+ id: text("id").primaryKey(),
91
+ ownerId: text("owner_id").notNull().references(() => users.id),
92
+ tenantId: text("tenant_id").references(() => tenants.id),
93
+ // nullable, for multi-tenant scoping
94
+ name: text("name").notNull(),
95
+ type: text("type", { enum: ["autonomous", "delegated", "service"] }).notNull(),
96
+ status: text("status", { enum: ["active", "revoked", "expired"] }).notNull().default("active"),
97
+ tokenHash: text("token_hash").notNull(),
98
+ // hashed agent token
99
+ tokenPrefix: text("token_prefix").notNull(),
100
+ // first 8 chars for identification
101
+ expiresAt: integer("expires_at", { mode: "timestamp" }),
102
+ lastActiveAt: integer("last_active_at", { mode: "timestamp" }),
103
+ metadata: text("metadata", { mode: "json" }).$type(),
104
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
105
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
106
+ });
107
+ var permissions = sqliteTable("kavach_permissions", {
108
+ id: text("id").primaryKey(),
109
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
110
+ resource: text("resource").notNull(),
111
+ // e.g. "mcp:github:*", "tool:file_read"
112
+ actions: text("actions", { mode: "json" }).notNull().$type(),
113
+ // ["read", "write", "execute"]
114
+ constraints: text("constraints", { mode: "json" }).$type(),
115
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
116
+ });
117
+ sqliteTable("kavach_delegation_chains", {
118
+ id: text("id").primaryKey(),
119
+ fromAgentId: text("from_agent_id").notNull().references(() => agents.id),
120
+ toAgentId: text("to_agent_id").notNull().references(() => agents.id),
121
+ permissions: text("permissions", { mode: "json" }).notNull().$type(),
122
+ depth: integer("depth").notNull().default(1),
123
+ maxDepth: integer("max_depth").notNull().default(3),
124
+ status: text("status", { enum: ["active", "revoked", "expired"] }).notNull().default("active"),
125
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
126
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
127
+ });
128
+ sqliteTable("kavach_audit_logs", {
129
+ id: text("id").primaryKey(),
130
+ agentId: text("agent_id").notNull().references(() => agents.id),
131
+ userId: text("user_id").notNull().references(() => users.id),
132
+ action: text("action").notNull(),
133
+ // "execute", "read", "write", "delete"
134
+ resource: text("resource").notNull(),
135
+ // "mcp:github:create_issue"
136
+ parameters: text("parameters", { mode: "json" }).$type(),
137
+ result: text("result", { enum: ["allowed", "denied", "rate_limited"] }).notNull(),
138
+ reason: text("reason"),
139
+ // why denied/rate_limited
140
+ durationMs: integer("duration_ms").notNull(),
141
+ tokensCost: integer("tokens_cost"),
142
+ ip: text("ip"),
143
+ userAgent: text("user_agent"),
144
+ timestamp: integer("timestamp", { mode: "timestamp" }).notNull()
145
+ });
146
+ sqliteTable("kavach_rate_limits", {
147
+ id: text("id").primaryKey(),
148
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
149
+ resource: text("resource").notNull(),
150
+ windowStart: integer("window_start", { mode: "timestamp" }).notNull(),
151
+ count: integer("count").notNull().default(0)
152
+ });
153
+ sqliteTable("kavach_mcp_servers", {
154
+ id: text("id").primaryKey(),
155
+ name: text("name").notNull(),
156
+ endpoint: text("endpoint").notNull().unique(),
157
+ tools: text("tools", { mode: "json" }).notNull().$type(),
158
+ authRequired: integer("auth_required", { mode: "boolean" }).notNull().default(true),
159
+ rateLimitRpm: integer("rate_limit_rpm"),
160
+ status: text("status", { enum: ["active", "inactive"] }).notNull().default("active"),
161
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
162
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
163
+ });
164
+ sqliteTable("kavach_sessions", {
165
+ id: text("id").primaryKey(),
166
+ userId: text("user_id").notNull().references(() => users.id),
167
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
168
+ metadata: text("metadata", { mode: "json" }).$type(),
169
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
170
+ });
171
+ var oauthClients = sqliteTable("kavach_oauth_clients", {
172
+ id: text("id").primaryKey(),
173
+ clientId: text("client_id").notNull().unique(),
174
+ clientSecret: text("client_secret"),
175
+ // null for public clients
176
+ clientName: text("client_name"),
177
+ clientUri: text("client_uri"),
178
+ redirectUris: text("redirect_uris", { mode: "json" }).notNull().$type(),
179
+ grantTypes: text("grant_types", { mode: "json" }).notNull().$type().default(["authorization_code"]),
180
+ responseTypes: text("response_types", { mode: "json" }).notNull().$type().default(["code"]),
181
+ tokenEndpointAuthMethod: text("token_endpoint_auth_method").notNull().default("client_secret_basic"),
182
+ type: text("type", { enum: ["public", "confidential"] }).notNull().default("confidential"),
183
+ disabled: integer("disabled", { mode: "boolean" }).notNull().default(false),
184
+ metadata: text("metadata", { mode: "json" }).$type(),
185
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
186
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
187
+ });
188
+ sqliteTable("kavach_oauth_access_tokens", {
189
+ id: text("id").primaryKey(),
190
+ accessToken: text("access_token").notNull().unique(),
191
+ refreshToken: text("refresh_token").unique(),
192
+ clientId: text("client_id").notNull().references(() => oauthClients.clientId),
193
+ userId: text("user_id").notNull().references(() => users.id),
194
+ scopes: text("scopes").notNull(),
195
+ // space-separated
196
+ resource: text("resource"),
197
+ // RFC 8707 - audience binding
198
+ accessTokenExpiresAt: integer("access_token_expires_at", { mode: "timestamp" }).notNull(),
199
+ refreshTokenExpiresAt: integer("refresh_token_expires_at", { mode: "timestamp" }),
200
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
201
+ });
202
+ sqliteTable("kavach_oauth_authorization_codes", {
203
+ id: text("id").primaryKey(),
204
+ code: text("code").notNull().unique(),
205
+ clientId: text("client_id").notNull().references(() => oauthClients.clientId),
206
+ userId: text("user_id").notNull().references(() => users.id),
207
+ redirectUri: text("redirect_uri").notNull(),
208
+ scopes: text("scopes").notNull(),
209
+ codeChallenge: text("code_challenge"),
210
+ // PKCE
211
+ codeChallengeMethod: text("code_challenge_method"),
212
+ // "S256"
213
+ resource: text("resource"),
214
+ // RFC 8707
215
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
216
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
217
+ });
218
+ sqliteTable("kavach_budget_policies", {
219
+ id: text("id").primaryKey(),
220
+ agentId: text("agent_id").references(() => agents.id, { onDelete: "cascade" }),
221
+ // nullable
222
+ userId: text("user_id").references(() => users.id),
223
+ // nullable
224
+ tenantId: text("tenant_id").references(() => tenants.id),
225
+ // nullable
226
+ limits: text("limits", { mode: "json" }).notNull().$type(),
227
+ currentUsage: text("current_usage", { mode: "json" }).notNull().$type(),
228
+ action: text("action", { enum: ["warn", "throttle", "block", "revoke"] }).notNull().default("warn"),
229
+ status: text("status", { enum: ["active", "triggered", "disabled"] }).notNull().default("active"),
230
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
231
+ });
232
+ sqliteTable("kavach_agent_cards", {
233
+ id: text("id").primaryKey(),
234
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
235
+ name: text("name").notNull(),
236
+ description: text("description"),
237
+ version: text("version").notNull(),
238
+ protocols: text("protocols", { mode: "json" }).notNull().$type(),
239
+ capabilities: text("capabilities", { mode: "json" }).notNull().$type(),
240
+ authRequirements: text("auth_requirements", { mode: "json" }).notNull().$type(),
241
+ endpoint: text("endpoint"),
242
+ metadata: text("metadata", { mode: "json" }).$type(),
243
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
244
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
245
+ });
246
+ sqliteTable("kavach_approval_requests", {
247
+ id: text("id").primaryKey(),
248
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
249
+ userId: text("user_id").notNull().references(() => users.id),
250
+ action: text("action").notNull(),
251
+ resource: text("resource").notNull(),
252
+ arguments: text("arguments", { mode: "json" }).$type(),
253
+ status: text("status", { enum: ["pending", "approved", "denied", "expired"] }).notNull().default("pending"),
254
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
255
+ respondedAt: integer("responded_at", { mode: "timestamp" }),
256
+ respondedBy: text("responded_by"),
257
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
258
+ });
259
+ sqliteTable("kavach_trust_scores", {
260
+ agentId: text("agent_id").primaryKey().references(() => agents.id, { onDelete: "cascade" }),
261
+ score: integer("score").notNull(),
262
+ level: text("level", {
263
+ enum: ["untrusted", "limited", "standard", "trusted", "elevated"]
264
+ }).notNull(),
265
+ factors: text("factors", { mode: "json" }).notNull().$type(),
266
+ computedAt: integer("computed_at", { mode: "timestamp" }).notNull()
267
+ });
268
+ sqliteTable("kavach_magic_links", {
269
+ id: text("id").primaryKey(),
270
+ email: text("email").notNull(),
271
+ token: text("token").notNull().unique(),
272
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
273
+ used: integer("used", { mode: "boolean" }).notNull().default(false),
274
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
275
+ });
276
+ sqliteTable("kavach_email_otps", {
277
+ id: text("id").primaryKey(),
278
+ email: text("email").notNull(),
279
+ codeHash: text("code_hash").notNull(),
280
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
281
+ attempts: integer("attempts").notNull().default(0),
282
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
283
+ });
284
+ sqliteTable("kavach_totp", {
285
+ userId: text("user_id").primaryKey().references(() => users.id),
286
+ secret: text("secret").notNull(),
287
+ // base32-encoded TOTP secret
288
+ enabled: integer("enabled", { mode: "boolean" }).notNull().default(false),
289
+ backupCodes: text("backup_codes", { mode: "json" }).notNull().$type(),
290
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
291
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
292
+ });
293
+ var organizations = sqliteTable("kavach_organizations", {
294
+ id: text("id").primaryKey(),
295
+ name: text("name").notNull(),
296
+ slug: text("slug").notNull().unique(),
297
+ ownerId: text("owner_id").notNull().references(() => users.id),
298
+ metadata: text("metadata", { mode: "json" }).$type(),
299
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
300
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
301
+ });
302
+ sqliteTable("kavach_org_members", {
303
+ id: text("id").primaryKey(),
304
+ orgId: text("org_id").notNull().references(() => organizations.id, { onDelete: "cascade" }),
305
+ userId: text("user_id").notNull().references(() => users.id),
306
+ role: text("role").notNull().default("member"),
307
+ joinedAt: integer("joined_at", { mode: "timestamp" }).notNull()
308
+ });
309
+ sqliteTable("kavach_org_invitations", {
310
+ id: text("id").primaryKey(),
311
+ orgId: text("org_id").notNull().references(() => organizations.id, { onDelete: "cascade" }),
312
+ email: text("email").notNull(),
313
+ role: text("role").notNull().default("member"),
314
+ invitedBy: text("invited_by").notNull().references(() => users.id),
315
+ status: text("status", { enum: ["pending", "accepted", "expired"] }).notNull().default("pending"),
316
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
317
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
318
+ });
319
+ sqliteTable("kavach_org_roles", {
320
+ id: text("id").primaryKey(),
321
+ orgId: text("org_id").notNull().references(() => organizations.id, { onDelete: "cascade" }),
322
+ name: text("name").notNull(),
323
+ permissions: text("permissions", { mode: "json" }).notNull().$type()
324
+ });
325
+ sqliteTable("kavach_passkey_credentials", {
326
+ id: text("id").primaryKey(),
327
+ userId: text("user_id").notNull().references(() => users.id),
328
+ credentialId: text("credential_id").notNull().unique(),
329
+ publicKey: text("public_key").notNull(),
330
+ // base64url-encoded COSE key
331
+ counter: integer("counter").notNull().default(0),
332
+ deviceName: text("device_name"),
333
+ transports: text("transports"),
334
+ // JSON array, e.g. '["internal","usb"]'
335
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
336
+ lastUsedAt: integer("last_used_at", { mode: "timestamp" }).notNull()
337
+ });
338
+ sqliteTable("kavach_sso_connections", {
339
+ id: text("id").primaryKey(),
340
+ orgId: text("org_id").notNull(),
341
+ providerId: text("provider_id").notNull(),
342
+ type: text("type", { enum: ["saml", "oidc"] }).notNull(),
343
+ domain: text("domain").notNull().unique(),
344
+ enabled: integer("enabled").notNull().default(1),
345
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
346
+ });
347
+ sqliteTable("kavach_api_keys", {
348
+ id: text("id").primaryKey(),
349
+ userId: text("user_id").notNull().references(() => users.id),
350
+ name: text("name").notNull(),
351
+ keyHash: text("key_hash").notNull(),
352
+ keyPrefix: text("key_prefix").notNull(),
353
+ permissions: text("permissions", { mode: "json" }).notNull().$type(),
354
+ expiresAt: integer("expires_at", { mode: "timestamp" }),
355
+ lastUsedAt: integer("last_used_at", { mode: "timestamp" }),
356
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
357
+ });
358
+ sqliteTable("kavach_passkey_challenges", {
359
+ id: text("id").primaryKey(),
360
+ challenge: text("challenge").notNull().unique(),
361
+ userId: text("user_id"),
362
+ // null for discoverable credential flows
363
+ type: text("type", { enum: ["registration", "authentication"] }).notNull(),
364
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
365
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
366
+ });
367
+ sqliteTable("kavach_username_accounts", {
368
+ id: text("id").primaryKey(),
369
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
370
+ username: text("username").notNull().unique(),
371
+ passwordHash: text("password_hash").notNull(),
372
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
373
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
374
+ });
375
+ sqliteTable("kavach_phone_verifications", {
376
+ id: text("id").primaryKey(),
377
+ phoneNumber: text("phone_number").notNull(),
378
+ codeHash: text("code_hash").notNull(),
379
+ attempts: integer("attempts").notNull().default(0),
380
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
381
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
382
+ });
383
+ sqliteTable("kavach_trusted_devices", {
384
+ id: text("id").primaryKey(),
385
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
386
+ fingerprint: text("fingerprint").notNull(),
387
+ // HMAC-SHA256 of stable request headers
388
+ label: text("label").notNull(),
389
+ // human-readable, e.g. "Mac", "iPhone"
390
+ trustedAt: integer("trusted_at", { mode: "timestamp" }).notNull(),
391
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull()
392
+ });
393
+ sqliteTable("kavach_one_time_tokens", {
394
+ id: text("id").primaryKey(),
395
+ tokenHash: text("token_hash").notNull().unique(),
396
+ // SHA-256 hex of the raw token
397
+ purpose: text("purpose", {
398
+ enum: ["email-verify", "password-reset", "invitation", "custom"]
399
+ }).notNull(),
400
+ identifier: text("identifier").notNull(),
401
+ // email, userId, or any caller-supplied key
402
+ metadata: text("metadata", { mode: "json" }).$type(),
403
+ used: integer("used", { mode: "boolean" }).notNull().default(false),
404
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
405
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
406
+ });
407
+ sqliteTable("kavach_login_history", {
408
+ id: text("id").primaryKey(),
409
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
410
+ method: text("method").notNull(),
411
+ // LoginMethod — kept as text to support oauth:{provider} variants
412
+ ip: text("ip"),
413
+ userAgent: text("user_agent"),
414
+ timestamp: integer("timestamp", { mode: "timestamp_ms" }).notNull()
415
+ });
416
+ sqliteTable("kavach_agent_dids", {
417
+ agentId: text("agent_id").primaryKey().references(() => agents.id, { onDelete: "cascade" }),
418
+ did: text("did").notNull().unique(),
419
+ method: text("method", { enum: ["key", "web"] }).notNull(),
420
+ publicKeyJwk: text("public_key_jwk").notNull(),
421
+ // JSON-serialised JWK (public key only)
422
+ didDocument: text("did_document").notNull(),
423
+ // JSON-serialised DID Document
424
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
425
+ });
426
+ sqliteTable("kavach_oidc_clients", {
427
+ id: text("id").primaryKey(),
428
+ clientId: text("client_id").notNull().unique(),
429
+ clientSecretHash: text("client_secret_hash").notNull(),
430
+ // SHA-256 hex of the raw secret
431
+ clientName: text("client_name").notNull(),
432
+ redirectUris: text("redirect_uris", { mode: "json" }).notNull().$type(),
433
+ grantTypes: text("grant_types", { mode: "json" }).notNull().$type(),
434
+ responseTypes: text("response_types", { mode: "json" }).notNull().$type(),
435
+ scopes: text("scopes", { mode: "json" }).notNull().$type(),
436
+ tokenEndpointAuthMethod: text("token_endpoint_auth_method").notNull().default("client_secret_post"),
437
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
438
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
439
+ });
440
+ sqliteTable("kavach_oidc_auth_codes", {
441
+ id: text("id").primaryKey(),
442
+ codeHash: text("code_hash").notNull().unique(),
443
+ // SHA-256 hex of the raw code
444
+ clientId: text("client_id").notNull(),
445
+ userId: text("user_id").notNull(),
446
+ redirectUri: text("redirect_uri").notNull(),
447
+ scopes: text("scopes").notNull(),
448
+ // space-separated
449
+ nonce: text("nonce"),
450
+ codeChallenge: text("code_challenge"),
451
+ // PKCE S256
452
+ codeChallengeMethod: text("code_challenge_method"),
453
+ used: integer("used", { mode: "boolean" }).notNull().default(false),
454
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
455
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
456
+ });
457
+ sqliteTable("kavach_oidc_refresh_tokens", {
458
+ id: text("id").primaryKey(),
459
+ tokenHash: text("token_hash").notNull().unique(),
460
+ // SHA-256 hex of the raw token
461
+ clientId: text("client_id").notNull(),
462
+ userId: text("user_id").notNull(),
463
+ scopes: text("scopes").notNull(),
464
+ // space-separated
465
+ revoked: integer("revoked", { mode: "boolean" }).notNull().default(false),
466
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
467
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
468
+ });
469
+ sqliteTable("kavach_cost_events", {
470
+ id: text("id").primaryKey(),
471
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
472
+ tool: text("tool").notNull(),
473
+ // e.g. 'openai:gpt-4o', 'anthropic:claude-3-5-sonnet', 'mcp:github'
474
+ inputTokens: integer("input_tokens"),
475
+ outputTokens: integer("output_tokens"),
476
+ /** Cost stored as integer microdollars (costUsd × 1_000_000) to avoid float drift */
477
+ costMicros: integer("cost_micros").notNull(),
478
+ currency: text("currency").notNull().default("USD"),
479
+ metadata: text("metadata", { mode: "json" }).$type(),
480
+ delegationChainId: text("delegation_chain_id"),
481
+ // null when not part of a chain
482
+ recordedAt: integer("recorded_at", { mode: "timestamp" }).notNull()
483
+ });
484
+ sqliteTable("kavach_ephemeral_sessions", {
485
+ id: text("id").primaryKey(),
486
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
487
+ ownerId: text("owner_id").notNull().references(() => users.id),
488
+ tokenHash: text("token_hash").notNull().unique(),
489
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
490
+ maxActions: integer("max_actions"),
491
+ // null = unlimited
492
+ actionsUsed: integer("actions_used").notNull().default(0),
493
+ status: text("status", { enum: ["active", "expired", "exhausted", "revoked"] }).notNull().default("active"),
494
+ auditGroupId: text("audit_group_id").notNull(),
495
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
496
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
497
+ });
498
+ sqliteTable("kavach_stream_events", {
499
+ id: text("id").primaryKey(),
500
+ type: text("type").notNull(),
501
+ timestamp: integer("timestamp", { mode: "timestamp" }).notNull(),
502
+ data: text("data", { mode: "json" }).notNull().$type(),
503
+ agentId: text("agent_id"),
504
+ userId: text("user_id")
505
+ });
506
+ sqliteTable("kavach_jwt_refresh_tokens", {
507
+ id: text("id").primaryKey(),
508
+ /** SHA-256 hex of the raw refresh token. The raw token is never stored. */
509
+ tokenHash: text("token_hash").notNull().unique(),
510
+ /** The user who owns this session. */
511
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
512
+ /** True once the token has been used in a refresh or explicit revocation. */
513
+ used: integer("used", { mode: "boolean" }).notNull().default(false),
514
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
515
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
516
+ });
517
+ sqliteTable("kavach_rebac_resources", {
518
+ id: text("id").notNull().primaryKey(),
519
+ type: text("type").notNull(),
520
+ // 'org', 'workspace', 'project', 'document', etc.
521
+ parentId: text("parent_id"),
522
+ parentType: text("parent_type"),
523
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
524
+ });
525
+ sqliteTable("kavach_rebac_relationships", {
526
+ id: text("id").primaryKey(),
527
+ subjectType: text("subject_type").notNull(),
528
+ // 'user', 'agent', 'team', 'role'
529
+ subjectId: text("subject_id").notNull(),
530
+ relation: text("relation").notNull(),
531
+ // 'owner', 'editor', 'viewer', 'member', 'parent'
532
+ objectType: text("object_type").notNull(),
533
+ objectId: text("object_id").notNull(),
534
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
535
+ });
536
+ sqliteTable("kavach_federation_instances", {
537
+ id: text("id").primaryKey(),
538
+ instanceId: text("instance_id").notNull().unique(),
539
+ instanceUrl: text("instance_url").notNull(),
540
+ publicKeyJwk: text("public_key_jwk"),
541
+ // JSON-serialised JWK (public key only)
542
+ trustLevel: text("trust_level", { enum: ["full", "limited", "verify-only"] }).notNull().default("verify-only"),
543
+ discoveredAt: integer("discovered_at", { mode: "timestamp" }),
544
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
545
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
546
+ });
547
+ sqliteTable("kavach_federation_tokens", {
548
+ id: text("id").primaryKey(),
549
+ tokenJti: text("token_jti").notNull().unique(),
550
+ // JWT ID for dedup
551
+ agentId: text("agent_id").notNull(),
552
+ sourceInstanceId: text("source_instance_id").notNull(),
553
+ targetInstanceId: text("target_instance_id"),
554
+ direction: text("direction", { enum: ["issued", "received"] }).notNull(),
555
+ permissions: text("permissions", { mode: "json" }).notNull().$type(),
556
+ trustScore: integer("trust_score"),
557
+ // stored as integer 0-100
558
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
559
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
560
+ });
561
+ var refreshTokenFamilies = sqliteTable("kavach_refresh_token_families", {
562
+ id: text("id").primaryKey(),
563
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
564
+ /** Absolute session expiry — no rotation can extend beyond this date. */
565
+ absoluteExpiresAt: integer("absolute_expires_at", { mode: "timestamp" }).notNull(),
566
+ /** 0 = active, 1 = revoked (reuse detection or explicit logout). */
567
+ revoked: integer("revoked").notNull().default(0),
568
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
569
+ });
570
+ sqliteTable("kavach_refresh_tokens", {
571
+ id: text("id").primaryKey(),
572
+ familyId: text("family_id").notNull().references(() => refreshTokenFamilies.id, { onDelete: "cascade" }),
573
+ /** SHA-256 hash of the opaque token — never store the raw token. */
574
+ tokenHash: text("token_hash").notNull().unique(),
575
+ /** 0 = unused, 1 = already consumed (one-time use). */
576
+ used: integer("used").notNull().default(0),
577
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
578
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
579
+ });
580
+
581
+ // src/agent/agent.ts
582
+ async function generateAgentToken() {
583
+ const tokenBytes = randomBytes(32);
584
+ const token = `kv_${toBase64Url(tokenBytes)}`;
585
+ const hash = await sha256(token);
586
+ const prefix = token.slice(0, 11);
587
+ return { token, hash, prefix };
588
+ }
589
+ function parseTokenExpiry(expiry) {
590
+ const now = Date.now();
591
+ const match = expiry.match(/^(\d+)([smhd])$/);
592
+ if (!match) {
593
+ throw new Error(`Invalid token expiry format: ${expiry}. Use format like "24h", "7d", "30m".`);
594
+ }
595
+ const value = Number.parseInt(match[1], 10);
596
+ const unit = match[2];
597
+ const multipliers = {
598
+ s: 1e3,
599
+ m: 60 * 1e3,
600
+ h: 60 * 60 * 1e3,
601
+ d: 24 * 60 * 60 * 1e3
602
+ };
603
+ return new Date(now + value * (multipliers[unit] ?? 0));
604
+ }
605
+ function createAgentModule(config) {
606
+ const { db, maxPerUser, tokenExpiry } = config;
607
+ async function create(input) {
608
+ const existing = await db.select().from(agents).where(and(eq(agents.ownerId, input.ownerId), eq(agents.status, "active")));
609
+ if (existing.length >= maxPerUser) {
610
+ throw new Error(
611
+ `User ${input.ownerId} has reached the maximum of ${maxPerUser} active agents.`
612
+ );
613
+ }
614
+ const id = generateId();
615
+ const { token, hash, prefix } = await generateAgentToken();
616
+ const now = /* @__PURE__ */ new Date();
617
+ const expires = input.expiresAt ?? parseTokenExpiry(tokenExpiry);
618
+ await db.insert(agents).values({
619
+ id,
620
+ ownerId: input.ownerId,
621
+ tenantId: input.tenantId ?? null,
622
+ name: input.name,
623
+ type: input.type,
624
+ status: "active",
625
+ tokenHash: hash,
626
+ tokenPrefix: prefix,
627
+ expiresAt: expires,
628
+ metadata: input.metadata ?? {},
629
+ createdAt: now,
630
+ updatedAt: now
631
+ });
632
+ if (input.permissions.length > 0) {
633
+ await db.insert(permissions).values(
634
+ input.permissions.map((p) => ({
635
+ id: generateId(),
636
+ agentId: id,
637
+ resource: p.resource,
638
+ actions: p.actions,
639
+ constraints: p.constraints ?? null,
640
+ createdAt: now
641
+ }))
642
+ );
643
+ }
644
+ return {
645
+ id,
646
+ ownerId: input.ownerId,
647
+ tenantId: input.tenantId,
648
+ name: input.name,
649
+ type: input.type,
650
+ token,
651
+ permissions: input.permissions,
652
+ status: "active",
653
+ expiresAt: expires,
654
+ createdAt: now,
655
+ updatedAt: now
656
+ };
657
+ }
658
+ async function get(agentId) {
659
+ const rows = await db.select().from(agents).where(eq(agents.id, agentId)).limit(1);
660
+ const agent = rows[0];
661
+ if (!agent) return null;
662
+ const perms = await db.select().from(permissions).where(eq(permissions.agentId, agentId));
663
+ return {
664
+ id: agent.id,
665
+ ownerId: agent.ownerId,
666
+ tenantId: agent.tenantId ?? void 0,
667
+ name: agent.name,
668
+ type: agent.type,
669
+ token: "",
670
+ // never return token after creation
671
+ permissions: perms.map(toPermission),
672
+ status: agent.status,
673
+ expiresAt: agent.expiresAt,
674
+ createdAt: agent.createdAt,
675
+ updatedAt: agent.updatedAt
676
+ };
677
+ }
678
+ async function list(filter) {
679
+ let query = db.select().from(agents).$dynamic();
680
+ const conditions = [];
681
+ if (filter?.userId) conditions.push(eq(agents.ownerId, filter.userId));
682
+ if (filter?.tenantId) conditions.push(eq(agents.tenantId, filter.tenantId));
683
+ if (filter?.status) conditions.push(eq(agents.status, filter.status));
684
+ if (filter?.type) conditions.push(eq(agents.type, filter.type));
685
+ if (conditions.length > 0) {
686
+ query = query.where(and(...conditions));
687
+ }
688
+ const rows = await query;
689
+ const agentIds = rows.map((r) => r.id);
690
+ const permsByAgent = /* @__PURE__ */ new Map();
691
+ for (const id of agentIds) {
692
+ const perms = await db.select().from(permissions).where(eq(permissions.agentId, id));
693
+ permsByAgent.set(id, perms.map(toPermission));
694
+ }
695
+ return rows.map((agent) => ({
696
+ id: agent.id,
697
+ ownerId: agent.ownerId,
698
+ tenantId: agent.tenantId ?? void 0,
699
+ name: agent.name,
700
+ type: agent.type,
701
+ token: "",
702
+ permissions: permsByAgent.get(agent.id) ?? [],
703
+ status: agent.status,
704
+ expiresAt: agent.expiresAt,
705
+ createdAt: agent.createdAt,
706
+ updatedAt: agent.updatedAt
707
+ }));
708
+ }
709
+ async function update(agentId, input) {
710
+ const existing = await get(agentId);
711
+ if (!existing) throw new Error(`Agent ${agentId} not found.`);
712
+ const now = /* @__PURE__ */ new Date();
713
+ await db.update(agents).set({
714
+ name: input.name ?? existing.name,
715
+ expiresAt: input.expiresAt ?? existing.expiresAt,
716
+ metadata: input.metadata,
717
+ updatedAt: now
718
+ }).where(eq(agents.id, agentId));
719
+ if (input.permissions) {
720
+ await db.delete(permissions).where(eq(permissions.agentId, agentId));
721
+ if (input.permissions.length > 0) {
722
+ await db.insert(permissions).values(
723
+ input.permissions.map((p) => ({
724
+ id: generateId(),
725
+ agentId,
726
+ resource: p.resource,
727
+ actions: p.actions,
728
+ constraints: p.constraints ?? null,
729
+ createdAt: now
730
+ }))
731
+ );
732
+ }
733
+ }
734
+ const updated = await get(agentId);
735
+ if (!updated) throw new Error(`Agent ${agentId} disappeared after update.`);
736
+ return updated;
737
+ }
738
+ async function revoke(agentId) {
739
+ const existing = await get(agentId);
740
+ if (!existing) throw new Error(`Agent ${agentId} not found.`);
741
+ await db.update(agents).set({ status: "revoked", updatedAt: /* @__PURE__ */ new Date() }).where(eq(agents.id, agentId));
742
+ }
743
+ async function rotate(agentId) {
744
+ const existing = await get(agentId);
745
+ if (!existing) throw new Error(`Agent ${agentId} not found.`);
746
+ if (existing.status !== "active")
747
+ throw new Error(`Cannot rotate token for ${existing.status} agent.`);
748
+ const { token, hash, prefix } = await generateAgentToken();
749
+ const now = /* @__PURE__ */ new Date();
750
+ await db.update(agents).set({ tokenHash: hash, tokenPrefix: prefix, updatedAt: now }).where(eq(agents.id, agentId));
751
+ return { ...existing, token, updatedAt: now };
752
+ }
753
+ async function validateToken(token) {
754
+ const hash = await sha256(token);
755
+ const rows = await db.select().from(agents).where(eq(agents.tokenHash, hash)).limit(1);
756
+ const agent = rows[0];
757
+ if (!agent) return null;
758
+ if (agent.status !== "active") return null;
759
+ if (agent.expiresAt && agent.expiresAt < /* @__PURE__ */ new Date()) {
760
+ await db.update(agents).set({ status: "expired", updatedAt: /* @__PURE__ */ new Date() }).where(eq(agents.id, agent.id));
761
+ return null;
762
+ }
763
+ await db.update(agents).set({ lastActiveAt: /* @__PURE__ */ new Date() }).where(eq(agents.id, agent.id));
764
+ const perms = await db.select().from(permissions).where(eq(permissions.agentId, agent.id));
765
+ return {
766
+ id: agent.id,
767
+ ownerId: agent.ownerId,
768
+ tenantId: agent.tenantId ?? void 0,
769
+ name: agent.name,
770
+ type: agent.type,
771
+ token: "",
772
+ permissions: perms.map(toPermission),
773
+ status: "active",
774
+ expiresAt: agent.expiresAt,
775
+ createdAt: agent.createdAt,
776
+ updatedAt: agent.updatedAt
777
+ };
778
+ }
779
+ return { create, get, list, update, revoke, rotate, validateToken };
780
+ }
781
+ function toPermission(row) {
782
+ return {
783
+ resource: row.resource,
784
+ actions: row.actions,
785
+ constraints: row.constraints ?? void 0
786
+ };
787
+ }
788
+
789
+ export { createAgentModule };
5
790
  //# sourceMappingURL=index.js.map
6
791
  //# sourceMappingURL=index.js.map