@glinr/theauth 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,641 @@
1
+ import { eq, gte, lte, desc, and, lt } from 'drizzle-orm';
2
+ import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
3
+
4
+ // src/audit/audit.ts
5
+ var users = sqliteTable("kavach_users", {
6
+ id: text("id").primaryKey(),
7
+ email: text("email").notNull().unique(),
8
+ name: text("name"),
9
+ username: text("username").unique(),
10
+ externalId: text("external_id"),
11
+ // ID from external auth (better-auth, Auth.js, etc.)
12
+ externalProvider: text("external_provider"),
13
+ // "better-auth", "authjs", "clerk", etc.
14
+ metadata: text("metadata", { mode: "json" }).$type(),
15
+ // Admin ban fields (populated by admin module)
16
+ banned: integer("banned").notNull().default(0),
17
+ banReason: text("ban_reason"),
18
+ banExpiresAt: integer("ban_expires_at", { mode: "timestamp" }),
19
+ forcePasswordReset: integer("force_password_reset").notNull().default(0),
20
+ emailVerified: integer("email_verified").notNull().default(0),
21
+ // Stripe integration fields (populated by kavach-stripe plugin)
22
+ stripeCustomerId: text("stripe_customer_id").unique(),
23
+ stripeSubscriptionId: text("stripe_subscription_id"),
24
+ stripeSubscriptionStatus: text("stripe_subscription_status"),
25
+ stripePriceId: text("stripe_price_id"),
26
+ stripeCurrentPeriodEnd: integer("stripe_current_period_end", { mode: "timestamp" }),
27
+ stripeCancelAtPeriodEnd: integer("stripe_cancel_at_period_end", { mode: "boolean" }).notNull().default(false),
28
+ // Polar integration fields (populated by kavach-polar plugin)
29
+ polarCustomerId: text("polar_customer_id").unique(),
30
+ polarSubscriptionId: text("polar_subscription_id"),
31
+ polarSubscriptionStatus: text("polar_subscription_status"),
32
+ polarProductId: text("polar_product_id"),
33
+ polarCurrentPeriodEnd: integer("polar_current_period_end", { mode: "timestamp" }),
34
+ polarCancelAtPeriodEnd: integer("polar_cancel_at_period_end", { mode: "boolean" }).notNull().default(false),
35
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
36
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
37
+ });
38
+ var tenants = sqliteTable("kavach_tenants", {
39
+ id: text("id").primaryKey(),
40
+ name: text("name").notNull(),
41
+ slug: text("slug").notNull().unique(),
42
+ settings: text("settings", { mode: "json" }).$type(),
43
+ status: text("status", { enum: ["active", "suspended"] }).notNull().default("active"),
44
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
45
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
46
+ });
47
+ var agents = sqliteTable("kavach_agents", {
48
+ id: text("id").primaryKey(),
49
+ ownerId: text("owner_id").notNull().references(() => users.id),
50
+ tenantId: text("tenant_id").references(() => tenants.id),
51
+ // nullable, for multi-tenant scoping
52
+ name: text("name").notNull(),
53
+ type: text("type", { enum: ["autonomous", "delegated", "service"] }).notNull(),
54
+ status: text("status", { enum: ["active", "revoked", "expired"] }).notNull().default("active"),
55
+ tokenHash: text("token_hash").notNull(),
56
+ // hashed agent token
57
+ tokenPrefix: text("token_prefix").notNull(),
58
+ // first 8 chars for identification
59
+ expiresAt: integer("expires_at", { mode: "timestamp" }),
60
+ lastActiveAt: integer("last_active_at", { mode: "timestamp" }),
61
+ metadata: text("metadata", { mode: "json" }).$type(),
62
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
63
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
64
+ });
65
+ sqliteTable("kavach_permissions", {
66
+ id: text("id").primaryKey(),
67
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
68
+ resource: text("resource").notNull(),
69
+ // e.g. "mcp:github:*", "tool:file_read"
70
+ actions: text("actions", { mode: "json" }).notNull().$type(),
71
+ // ["read", "write", "execute"]
72
+ constraints: text("constraints", { mode: "json" }).$type(),
73
+ // When set, the policy engine consults the ReBAC graph for this permission.
74
+ relation: text("relation"),
75
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
76
+ });
77
+ sqliteTable("kavach_delegation_chains", {
78
+ id: text("id").primaryKey(),
79
+ fromAgentId: text("from_agent_id").notNull().references(() => agents.id),
80
+ toAgentId: text("to_agent_id").notNull().references(() => agents.id),
81
+ permissions: text("permissions", { mode: "json" }).notNull().$type(),
82
+ depth: integer("depth").notNull().default(1),
83
+ maxDepth: integer("max_depth").notNull().default(3),
84
+ status: text("status", { enum: ["active", "revoked", "expired"] }).notNull().default("active"),
85
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
86
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
87
+ });
88
+ var auditLogs = sqliteTable("kavach_audit_logs", {
89
+ id: text("id").primaryKey(),
90
+ agentId: text("agent_id").notNull().references(() => agents.id),
91
+ userId: text("user_id").notNull().references(() => users.id),
92
+ action: text("action").notNull(),
93
+ // "execute", "read", "write", "delete"
94
+ resource: text("resource").notNull(),
95
+ // "mcp:github:create_issue"
96
+ parameters: text("parameters", { mode: "json" }).$type(),
97
+ result: text("result", { enum: ["allowed", "denied", "rate_limited"] }).notNull(),
98
+ reason: text("reason"),
99
+ // why denied/rate_limited
100
+ durationMs: integer("duration_ms").notNull(),
101
+ tokensCost: integer("tokens_cost"),
102
+ ip: text("ip"),
103
+ userAgent: text("user_agent"),
104
+ // True when this audit row corresponds to a policy-engine cache-hit evaluation.
105
+ cacheHit: integer("cache_hit", { mode: "boolean" }).notNull().default(false),
106
+ timestamp: integer("timestamp", { mode: "timestamp" }).notNull()
107
+ });
108
+ sqliteTable("kavach_rate_limits", {
109
+ id: text("id").primaryKey(),
110
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
111
+ resource: text("resource").notNull(),
112
+ windowStart: integer("window_start", { mode: "timestamp" }).notNull(),
113
+ count: integer("count").notNull().default(0)
114
+ });
115
+ sqliteTable("kavach_mcp_servers", {
116
+ id: text("id").primaryKey(),
117
+ name: text("name").notNull(),
118
+ endpoint: text("endpoint").notNull().unique(),
119
+ tools: text("tools", { mode: "json" }).notNull().$type(),
120
+ authRequired: integer("auth_required", { mode: "boolean" }).notNull().default(true),
121
+ rateLimitRpm: integer("rate_limit_rpm"),
122
+ status: text("status", { enum: ["active", "inactive"] }).notNull().default("active"),
123
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
124
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
125
+ });
126
+ sqliteTable("kavach_sessions", {
127
+ id: text("id").primaryKey(),
128
+ userId: text("user_id").notNull().references(() => users.id),
129
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
130
+ metadata: text("metadata", { mode: "json" }).$type(),
131
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
132
+ });
133
+ var oauthClients = sqliteTable("kavach_oauth_clients", {
134
+ id: text("id").primaryKey(),
135
+ clientId: text("client_id").notNull().unique(),
136
+ clientSecret: text("client_secret"),
137
+ // null for public clients
138
+ clientName: text("client_name"),
139
+ clientUri: text("client_uri"),
140
+ redirectUris: text("redirect_uris", { mode: "json" }).notNull().$type(),
141
+ grantTypes: text("grant_types", { mode: "json" }).notNull().$type().default(["authorization_code"]),
142
+ responseTypes: text("response_types", { mode: "json" }).notNull().$type().default(["code"]),
143
+ tokenEndpointAuthMethod: text("token_endpoint_auth_method").notNull().default("client_secret_basic"),
144
+ type: text("type", { enum: ["public", "confidential"] }).notNull().default("confidential"),
145
+ disabled: integer("disabled", { mode: "boolean" }).notNull().default(false),
146
+ metadata: text("metadata", { mode: "json" }).$type(),
147
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
148
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
149
+ });
150
+ sqliteTable("kavach_oauth_access_tokens", {
151
+ id: text("id").primaryKey(),
152
+ accessToken: text("access_token").notNull().unique(),
153
+ refreshToken: text("refresh_token").unique(),
154
+ clientId: text("client_id").notNull().references(() => oauthClients.clientId),
155
+ userId: text("user_id").notNull().references(() => users.id),
156
+ scopes: text("scopes").notNull(),
157
+ // space-separated
158
+ resource: text("resource"),
159
+ // RFC 8707 - audience binding
160
+ accessTokenExpiresAt: integer("access_token_expires_at", { mode: "timestamp" }).notNull(),
161
+ refreshTokenExpiresAt: integer("refresh_token_expires_at", { mode: "timestamp" }),
162
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
163
+ });
164
+ sqliteTable("kavach_oauth_authorization_codes", {
165
+ id: text("id").primaryKey(),
166
+ code: text("code").notNull().unique(),
167
+ clientId: text("client_id").notNull().references(() => oauthClients.clientId),
168
+ userId: text("user_id").notNull().references(() => users.id),
169
+ redirectUri: text("redirect_uri").notNull(),
170
+ scopes: text("scopes").notNull(),
171
+ codeChallenge: text("code_challenge"),
172
+ // PKCE
173
+ codeChallengeMethod: text("code_challenge_method"),
174
+ // "S256"
175
+ resource: text("resource"),
176
+ // RFC 8707
177
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
178
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
179
+ });
180
+ sqliteTable("kavach_budget_policies", {
181
+ id: text("id").primaryKey(),
182
+ agentId: text("agent_id").references(() => agents.id, { onDelete: "cascade" }),
183
+ // nullable
184
+ userId: text("user_id").references(() => users.id),
185
+ // nullable
186
+ tenantId: text("tenant_id").references(() => tenants.id),
187
+ // nullable
188
+ limits: text("limits", { mode: "json" }).notNull().$type(),
189
+ currentUsage: text("current_usage", { mode: "json" }).notNull().$type(),
190
+ action: text("action", { enum: ["warn", "throttle", "block", "revoke"] }).notNull().default("warn"),
191
+ status: text("status", { enum: ["active", "triggered", "disabled"] }).notNull().default("active"),
192
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
193
+ });
194
+ sqliteTable("kavach_agent_cards", {
195
+ id: text("id").primaryKey(),
196
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
197
+ name: text("name").notNull(),
198
+ description: text("description"),
199
+ version: text("version").notNull(),
200
+ protocols: text("protocols", { mode: "json" }).notNull().$type(),
201
+ capabilities: text("capabilities", { mode: "json" }).notNull().$type(),
202
+ authRequirements: text("auth_requirements", { mode: "json" }).notNull().$type(),
203
+ endpoint: text("endpoint"),
204
+ metadata: text("metadata", { mode: "json" }).$type(),
205
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
206
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
207
+ });
208
+ sqliteTable("kavach_approval_requests", {
209
+ id: text("id").primaryKey(),
210
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
211
+ userId: text("user_id").notNull().references(() => users.id),
212
+ action: text("action").notNull(),
213
+ resource: text("resource").notNull(),
214
+ arguments: text("arguments", { mode: "json" }).$type(),
215
+ status: text("status", { enum: ["pending", "approved", "denied", "expired"] }).notNull().default("pending"),
216
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
217
+ respondedAt: integer("responded_at", { mode: "timestamp" }),
218
+ respondedBy: text("responded_by"),
219
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
220
+ });
221
+ sqliteTable("kavach_trust_scores", {
222
+ agentId: text("agent_id").primaryKey().references(() => agents.id, { onDelete: "cascade" }),
223
+ score: integer("score").notNull(),
224
+ level: text("level", {
225
+ enum: ["untrusted", "limited", "standard", "trusted", "elevated"]
226
+ }).notNull(),
227
+ factors: text("factors", { mode: "json" }).notNull().$type(),
228
+ computedAt: integer("computed_at", { mode: "timestamp" }).notNull()
229
+ });
230
+ sqliteTable("kavach_magic_links", {
231
+ id: text("id").primaryKey(),
232
+ email: text("email").notNull(),
233
+ token: text("token").notNull().unique(),
234
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
235
+ used: integer("used", { mode: "boolean" }).notNull().default(false),
236
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
237
+ });
238
+ sqliteTable("kavach_email_otps", {
239
+ id: text("id").primaryKey(),
240
+ email: text("email").notNull(),
241
+ codeHash: text("code_hash").notNull(),
242
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
243
+ attempts: integer("attempts").notNull().default(0),
244
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
245
+ });
246
+ sqliteTable("kavach_totp", {
247
+ userId: text("user_id").primaryKey().references(() => users.id),
248
+ secret: text("secret").notNull(),
249
+ // base32-encoded TOTP secret
250
+ enabled: integer("enabled", { mode: "boolean" }).notNull().default(false),
251
+ backupCodes: text("backup_codes", { mode: "json" }).notNull().$type(),
252
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
253
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
254
+ });
255
+ var organizations = sqliteTable("kavach_organizations", {
256
+ id: text("id").primaryKey(),
257
+ name: text("name").notNull(),
258
+ slug: text("slug").notNull().unique(),
259
+ ownerId: text("owner_id").notNull().references(() => users.id),
260
+ metadata: text("metadata", { mode: "json" }).$type(),
261
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
262
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
263
+ });
264
+ sqliteTable("kavach_org_members", {
265
+ id: text("id").primaryKey(),
266
+ orgId: text("org_id").notNull().references(() => organizations.id, { onDelete: "cascade" }),
267
+ userId: text("user_id").notNull().references(() => users.id),
268
+ role: text("role").notNull().default("member"),
269
+ joinedAt: integer("joined_at", { mode: "timestamp" }).notNull()
270
+ });
271
+ sqliteTable("kavach_org_invitations", {
272
+ id: text("id").primaryKey(),
273
+ orgId: text("org_id").notNull().references(() => organizations.id, { onDelete: "cascade" }),
274
+ email: text("email").notNull(),
275
+ role: text("role").notNull().default("member"),
276
+ invitedBy: text("invited_by").notNull().references(() => users.id),
277
+ status: text("status", { enum: ["pending", "accepted", "expired"] }).notNull().default("pending"),
278
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
279
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
280
+ });
281
+ sqliteTable("kavach_org_roles", {
282
+ id: text("id").primaryKey(),
283
+ orgId: text("org_id").notNull().references(() => organizations.id, { onDelete: "cascade" }),
284
+ name: text("name").notNull(),
285
+ permissions: text("permissions", { mode: "json" }).notNull().$type()
286
+ });
287
+ sqliteTable("kavach_passkey_credentials", {
288
+ id: text("id").primaryKey(),
289
+ userId: text("user_id").notNull().references(() => users.id),
290
+ credentialId: text("credential_id").notNull().unique(),
291
+ publicKey: text("public_key").notNull(),
292
+ // base64url-encoded COSE key
293
+ counter: integer("counter").notNull().default(0),
294
+ deviceName: text("device_name"),
295
+ transports: text("transports"),
296
+ // JSON array, e.g. '["internal","usb"]'
297
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
298
+ lastUsedAt: integer("last_used_at", { mode: "timestamp" }).notNull()
299
+ });
300
+ sqliteTable("kavach_sso_connections", {
301
+ id: text("id").primaryKey(),
302
+ orgId: text("org_id").notNull(),
303
+ providerId: text("provider_id").notNull(),
304
+ type: text("type", { enum: ["saml", "oidc"] }).notNull(),
305
+ domain: text("domain").notNull().unique(),
306
+ enabled: integer("enabled").notNull().default(1),
307
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
308
+ });
309
+ sqliteTable("kavach_api_keys", {
310
+ id: text("id").primaryKey(),
311
+ userId: text("user_id").notNull().references(() => users.id),
312
+ name: text("name").notNull(),
313
+ keyHash: text("key_hash").notNull(),
314
+ keyPrefix: text("key_prefix").notNull(),
315
+ permissions: text("permissions", { mode: "json" }).notNull().$type(),
316
+ expiresAt: integer("expires_at", { mode: "timestamp" }),
317
+ lastUsedAt: integer("last_used_at", { mode: "timestamp" }),
318
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
319
+ });
320
+ sqliteTable("kavach_passkey_challenges", {
321
+ id: text("id").primaryKey(),
322
+ challenge: text("challenge").notNull().unique(),
323
+ userId: text("user_id"),
324
+ // null for discoverable credential flows
325
+ type: text("type", { enum: ["registration", "authentication"] }).notNull(),
326
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
327
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
328
+ });
329
+ sqliteTable("kavach_username_accounts", {
330
+ id: text("id").primaryKey(),
331
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
332
+ username: text("username").notNull().unique(),
333
+ passwordHash: text("password_hash").notNull(),
334
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
335
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
336
+ });
337
+ sqliteTable("kavach_phone_verifications", {
338
+ id: text("id").primaryKey(),
339
+ phoneNumber: text("phone_number").notNull(),
340
+ codeHash: text("code_hash").notNull(),
341
+ attempts: integer("attempts").notNull().default(0),
342
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
343
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
344
+ });
345
+ sqliteTable("kavach_trusted_devices", {
346
+ id: text("id").primaryKey(),
347
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
348
+ fingerprint: text("fingerprint").notNull(),
349
+ // HMAC-SHA256 of stable request headers
350
+ label: text("label").notNull(),
351
+ // human-readable, e.g. "Mac", "iPhone"
352
+ trustedAt: integer("trusted_at", { mode: "timestamp" }).notNull(),
353
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull()
354
+ });
355
+ sqliteTable("kavach_one_time_tokens", {
356
+ id: text("id").primaryKey(),
357
+ tokenHash: text("token_hash").notNull().unique(),
358
+ // SHA-256 hex of the raw token
359
+ purpose: text("purpose", {
360
+ enum: ["email-verify", "password-reset", "invitation", "custom"]
361
+ }).notNull(),
362
+ identifier: text("identifier").notNull(),
363
+ // email, userId, or any caller-supplied key
364
+ metadata: text("metadata", { mode: "json" }).$type(),
365
+ used: integer("used", { mode: "boolean" }).notNull().default(false),
366
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
367
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
368
+ });
369
+ sqliteTable("kavach_login_history", {
370
+ id: text("id").primaryKey(),
371
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
372
+ method: text("method").notNull(),
373
+ // LoginMethod — kept as text to support oauth:{provider} variants
374
+ ip: text("ip"),
375
+ userAgent: text("user_agent"),
376
+ timestamp: integer("timestamp", { mode: "timestamp_ms" }).notNull()
377
+ });
378
+ sqliteTable("kavach_agent_dids", {
379
+ agentId: text("agent_id").primaryKey().references(() => agents.id, { onDelete: "cascade" }),
380
+ did: text("did").notNull().unique(),
381
+ method: text("method", { enum: ["key", "web"] }).notNull(),
382
+ publicKeyJwk: text("public_key_jwk").notNull(),
383
+ // JSON-serialised JWK (public key only)
384
+ didDocument: text("did_document").notNull(),
385
+ // JSON-serialised DID Document
386
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
387
+ });
388
+ sqliteTable("kavach_oidc_clients", {
389
+ id: text("id").primaryKey(),
390
+ clientId: text("client_id").notNull().unique(),
391
+ clientSecretHash: text("client_secret_hash").notNull(),
392
+ // SHA-256 hex of the raw secret
393
+ clientName: text("client_name").notNull(),
394
+ redirectUris: text("redirect_uris", { mode: "json" }).notNull().$type(),
395
+ grantTypes: text("grant_types", { mode: "json" }).notNull().$type(),
396
+ responseTypes: text("response_types", { mode: "json" }).notNull().$type(),
397
+ scopes: text("scopes", { mode: "json" }).notNull().$type(),
398
+ tokenEndpointAuthMethod: text("token_endpoint_auth_method").notNull().default("client_secret_post"),
399
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
400
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
401
+ });
402
+ sqliteTable("kavach_oidc_auth_codes", {
403
+ id: text("id").primaryKey(),
404
+ codeHash: text("code_hash").notNull().unique(),
405
+ // SHA-256 hex of the raw code
406
+ clientId: text("client_id").notNull(),
407
+ userId: text("user_id").notNull(),
408
+ redirectUri: text("redirect_uri").notNull(),
409
+ scopes: text("scopes").notNull(),
410
+ // space-separated
411
+ nonce: text("nonce"),
412
+ codeChallenge: text("code_challenge"),
413
+ // PKCE S256
414
+ codeChallengeMethod: text("code_challenge_method"),
415
+ used: integer("used", { mode: "boolean" }).notNull().default(false),
416
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
417
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
418
+ });
419
+ sqliteTable("kavach_oidc_refresh_tokens", {
420
+ id: text("id").primaryKey(),
421
+ tokenHash: text("token_hash").notNull().unique(),
422
+ // SHA-256 hex of the raw token
423
+ clientId: text("client_id").notNull(),
424
+ userId: text("user_id").notNull(),
425
+ scopes: text("scopes").notNull(),
426
+ // space-separated
427
+ revoked: integer("revoked", { mode: "boolean" }).notNull().default(false),
428
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
429
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
430
+ });
431
+ sqliteTable("kavach_cost_events", {
432
+ id: text("id").primaryKey(),
433
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
434
+ tool: text("tool").notNull(),
435
+ // e.g. 'openai:gpt-4o', 'anthropic:claude-3-5-sonnet', 'mcp:github'
436
+ inputTokens: integer("input_tokens"),
437
+ outputTokens: integer("output_tokens"),
438
+ /** Cost stored as integer microdollars (costUsd × 1_000_000) to avoid float drift */
439
+ costMicros: integer("cost_micros").notNull(),
440
+ currency: text("currency").notNull().default("USD"),
441
+ metadata: text("metadata", { mode: "json" }).$type(),
442
+ delegationChainId: text("delegation_chain_id"),
443
+ // null when not part of a chain
444
+ recordedAt: integer("recorded_at", { mode: "timestamp" }).notNull()
445
+ });
446
+ sqliteTable("kavach_ephemeral_sessions", {
447
+ id: text("id").primaryKey(),
448
+ agentId: text("agent_id").notNull().references(() => agents.id, { onDelete: "cascade" }),
449
+ ownerId: text("owner_id").notNull().references(() => users.id),
450
+ tokenHash: text("token_hash").notNull().unique(),
451
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
452
+ maxActions: integer("max_actions"),
453
+ // null = unlimited
454
+ actionsUsed: integer("actions_used").notNull().default(0),
455
+ status: text("status", { enum: ["active", "expired", "exhausted", "revoked"] }).notNull().default("active"),
456
+ auditGroupId: text("audit_group_id").notNull(),
457
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
458
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
459
+ });
460
+ sqliteTable("kavach_stream_events", {
461
+ id: text("id").primaryKey(),
462
+ type: text("type").notNull(),
463
+ timestamp: integer("timestamp", { mode: "timestamp" }).notNull(),
464
+ data: text("data", { mode: "json" }).notNull().$type(),
465
+ agentId: text("agent_id"),
466
+ userId: text("user_id")
467
+ });
468
+ sqliteTable("kavach_jwt_refresh_tokens", {
469
+ id: text("id").primaryKey(),
470
+ /** SHA-256 hex of the raw refresh token. The raw token is never stored. */
471
+ tokenHash: text("token_hash").notNull().unique(),
472
+ /** The user who owns this session. */
473
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
474
+ /** True once the token has been used in a refresh or explicit revocation. */
475
+ used: integer("used", { mode: "boolean" }).notNull().default(false),
476
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
477
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
478
+ });
479
+ sqliteTable("kavach_rebac_resources", {
480
+ id: text("id").notNull().primaryKey(),
481
+ type: text("type").notNull(),
482
+ // 'org', 'workspace', 'project', 'document', etc.
483
+ parentId: text("parent_id"),
484
+ parentType: text("parent_type"),
485
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
486
+ });
487
+ sqliteTable("kavach_rebac_relationships", {
488
+ id: text("id").primaryKey(),
489
+ subjectType: text("subject_type").notNull(),
490
+ // 'user', 'agent', 'team', 'role'
491
+ subjectId: text("subject_id").notNull(),
492
+ relation: text("relation").notNull(),
493
+ // 'owner', 'editor', 'viewer', 'member', 'parent'
494
+ objectType: text("object_type").notNull(),
495
+ objectId: text("object_id").notNull(),
496
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
497
+ });
498
+ sqliteTable("kavach_federation_instances", {
499
+ id: text("id").primaryKey(),
500
+ instanceId: text("instance_id").notNull().unique(),
501
+ instanceUrl: text("instance_url").notNull(),
502
+ publicKeyJwk: text("public_key_jwk"),
503
+ // JSON-serialised JWK (public key only)
504
+ trustLevel: text("trust_level", { enum: ["full", "limited", "verify-only"] }).notNull().default("verify-only"),
505
+ discoveredAt: integer("discovered_at", { mode: "timestamp" }),
506
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
507
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull()
508
+ });
509
+ sqliteTable("kavach_federation_tokens", {
510
+ id: text("id").primaryKey(),
511
+ tokenJti: text("token_jti").notNull().unique(),
512
+ // JWT ID for dedup
513
+ agentId: text("agent_id").notNull(),
514
+ sourceInstanceId: text("source_instance_id").notNull(),
515
+ targetInstanceId: text("target_instance_id"),
516
+ direction: text("direction", { enum: ["issued", "received"] }).notNull(),
517
+ permissions: text("permissions", { mode: "json" }).notNull().$type(),
518
+ trustScore: integer("trust_score"),
519
+ // stored as integer 0-100
520
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
521
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
522
+ });
523
+ var refreshTokenFamilies = sqliteTable("kavach_refresh_token_families", {
524
+ id: text("id").primaryKey(),
525
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
526
+ /** Absolute session expiry — no rotation can extend beyond this date. */
527
+ absoluteExpiresAt: integer("absolute_expires_at", { mode: "timestamp" }).notNull(),
528
+ /** 0 = active, 1 = revoked (reuse detection or explicit logout). */
529
+ revoked: integer("revoked").notNull().default(0),
530
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
531
+ });
532
+ sqliteTable("kavach_refresh_tokens", {
533
+ id: text("id").primaryKey(),
534
+ familyId: text("family_id").notNull().references(() => refreshTokenFamilies.id, { onDelete: "cascade" }),
535
+ /** SHA-256 hash of the opaque token — never store the raw token. */
536
+ tokenHash: text("token_hash").notNull().unique(),
537
+ /** 0 = unused, 1 = already consumed (one-time use). */
538
+ used: integer("used").notNull().default(0),
539
+ expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
540
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull()
541
+ });
542
+
543
+ // src/audit/audit.ts
544
+ function createAuditModule(config) {
545
+ const { db } = config;
546
+ async function query(filter) {
547
+ const conditions = [];
548
+ if (filter.agentId) conditions.push(eq(auditLogs.agentId, filter.agentId));
549
+ if (filter.userId) conditions.push(eq(auditLogs.userId, filter.userId));
550
+ if (filter.since) conditions.push(gte(auditLogs.timestamp, filter.since));
551
+ if (filter.until) conditions.push(lte(auditLogs.timestamp, filter.until));
552
+ if (filter.result) conditions.push(eq(auditLogs.result, filter.result));
553
+ let q = db.select().from(auditLogs).orderBy(desc(auditLogs.timestamp)).$dynamic();
554
+ if (conditions.length > 0) {
555
+ q = q.where(and(...conditions));
556
+ }
557
+ if (filter.limit) {
558
+ q = q.limit(filter.limit);
559
+ }
560
+ if (filter.offset) {
561
+ q = q.offset(filter.offset);
562
+ }
563
+ const rows = await q;
564
+ return rows.filter((row) => {
565
+ if (filter.actions && filter.actions.length > 0) {
566
+ return filter.actions.includes(row.action);
567
+ }
568
+ return true;
569
+ }).map(toAuditEntry);
570
+ }
571
+ async function exportLogs(options) {
572
+ const entries = await query({
573
+ since: options.since,
574
+ until: options.until,
575
+ limit: 1e4
576
+ // cap exports
577
+ });
578
+ if (options.format === "json") {
579
+ return JSON.stringify(entries, null, 2);
580
+ }
581
+ const headers = [
582
+ "id",
583
+ "agentId",
584
+ "userId",
585
+ "action",
586
+ "resource",
587
+ "result",
588
+ "reason",
589
+ "durationMs",
590
+ "tokensCost",
591
+ "timestamp"
592
+ ];
593
+ const csvRows = [headers.join(",")];
594
+ for (const entry of entries) {
595
+ csvRows.push(
596
+ [
597
+ entry.id,
598
+ entry.agentId,
599
+ entry.userId,
600
+ entry.action,
601
+ entry.resource,
602
+ entry.result,
603
+ `"${entry.reason ?? ""}"`,
604
+ entry.durationMs,
605
+ entry.tokensCost ?? "",
606
+ entry.timestamp.toISOString()
607
+ ].join(",")
608
+ );
609
+ }
610
+ return csvRows.join("\n");
611
+ }
612
+ async function cleanup(options) {
613
+ const cutoff = new Date(Date.now() - options.retentionDays * 24 * 60 * 60 * 1e3);
614
+ const toDelete = await db.select({ id: auditLogs.id }).from(auditLogs).where(lt(auditLogs.timestamp, cutoff));
615
+ if (toDelete.length === 0) {
616
+ return { deleted: 0 };
617
+ }
618
+ await db.delete(auditLogs).where(lt(auditLogs.timestamp, cutoff));
619
+ return { deleted: toDelete.length };
620
+ }
621
+ return { query, export: exportLogs, cleanup };
622
+ }
623
+ function toAuditEntry(row) {
624
+ return {
625
+ id: row.id,
626
+ agentId: row.agentId,
627
+ userId: row.userId,
628
+ action: row.action,
629
+ resource: row.resource,
630
+ parameters: row.parameters ?? {},
631
+ result: row.result,
632
+ reason: row.reason ?? void 0,
633
+ durationMs: row.durationMs,
634
+ tokensCost: row.tokensCost ?? void 0,
635
+ timestamp: row.timestamp
636
+ };
637
+ }
638
+
639
+ export { createAuditModule };
640
+ //# sourceMappingURL=index.js.map
641
+ //# sourceMappingURL=index.js.map