kavachos 0.0.4 → 0.0.6

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 (44) hide show
  1. package/dist/a2a/index.d.ts +2340 -0
  2. package/dist/a2a/index.js +821 -0
  3. package/dist/a2a/index.js.map +1 -0
  4. package/dist/agent/index.d.ts +3 -4
  5. package/dist/agent/index.js +4 -3
  6. package/dist/audit/index.d.ts +2 -3
  7. package/dist/audit/index.js +3 -3
  8. package/dist/auth/index.d.ts +490 -93
  9. package/dist/auth/index.js +4 -3
  10. package/dist/{chunk-KL6XW4S4.js → chunk-FKVAXCNJ.js} +2375 -633
  11. package/dist/chunk-FKVAXCNJ.js.map +1 -0
  12. package/dist/{chunk-5DT4DN4Y.js → chunk-IKTOSJ4O.js} +13 -13
  13. package/dist/chunk-IKTOSJ4O.js.map +1 -0
  14. package/dist/{chunk-V66UUIA7.js → chunk-KDL6A76K.js} +93 -4
  15. package/dist/chunk-KDL6A76K.js.map +1 -0
  16. package/dist/chunk-NSBPE2FW.js +15 -0
  17. package/dist/{chunk-PZ5AY32C.js.map → chunk-NSBPE2FW.js.map} +1 -1
  18. package/dist/chunk-NSTER7KE.js +538 -0
  19. package/dist/chunk-NSTER7KE.js.map +1 -0
  20. package/dist/chunk-QCRHJMDX.js +186 -0
  21. package/dist/chunk-QCRHJMDX.js.map +1 -0
  22. package/dist/{chunk-OVGNZ5OX.js → chunk-VHKZARMM.js} +6 -6
  23. package/dist/chunk-VHKZARMM.js.map +1 -0
  24. package/dist/{chunk-SJGSPIAD.js → chunk-Y3OWAJHK.js} +3 -3
  25. package/dist/{chunk-SJGSPIAD.js.map → chunk-Y3OWAJHK.js.map} +1 -1
  26. package/dist/index.d.ts +138 -6
  27. package/dist/index.js +580 -35
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcp/index.d.ts +2 -2
  30. package/dist/mcp/index.js +12 -16
  31. package/dist/mcp/index.js.map +1 -1
  32. package/dist/permission/index.d.ts +3 -4
  33. package/dist/permission/index.js +4 -3
  34. package/dist/{types-Xk83hv4O.d.ts → types-W8X0PXE7.d.ts} +1764 -99
  35. package/dist/vc/index.d.ts +800 -0
  36. package/dist/vc/index.js +5 -0
  37. package/dist/vc/index.js.map +1 -0
  38. package/package.json +17 -1
  39. package/dist/chunk-5DT4DN4Y.js.map +0 -1
  40. package/dist/chunk-KL6XW4S4.js.map +0 -1
  41. package/dist/chunk-OVGNZ5OX.js.map +0 -1
  42. package/dist/chunk-PZ5AY32C.js +0 -9
  43. package/dist/chunk-V66UUIA7.js.map +0 -1
  44. package/dist/{types-mwupB57A.d.ts → types-BuHrZcjE.d.ts} +2 -2
package/dist/index.js CHANGED
@@ -1,18 +1,18 @@
1
- import { createAgentModule } from './chunk-5DT4DN4Y.js';
2
- export { createAgentModule } from './chunk-5DT4DN4Y.js';
3
- import { createSessionManager, createMagicLinkModule, createEmailOtpModule, createTotpModule, createPasskeyModule, createOrgModule, createSsoModule, createAdminModule, createApiKeyManagerModule, createUsernameAuthModule, createPhoneAuthModule, createCaptchaModule, createWebhookModule } from './chunk-KL6XW4S4.js';
4
- export { HibpApiError, HibpBreachedError, OAuthProxyError, OneTapVerifyError, SSO_ERROR, SsoError, additionalFields, admin, anonymousAuth, apiKeys, bearerAuth, createAdditionalFieldsModule, createAdminModule, createAnonymousAuthModule, createApiKeyManagerModule, createCaptchaModule, createCustomSessionModule, createDeviceAuthModule, createEmailOtpModule, createGdprModule, createHibpModule, createJwtSessionModule, createLastLoginModule, createMagicLinkModule, createOAuthProxyModule, createOidcProviderModule, createOneTapModule, createOneTimeTokenModule, createOpenApiModule, createOrgModule, createPasskeyModule, createPhoneAuthModule, createPolarModule, createRateLimiter, createScimModule, createSessionManager, createSiweModule, createSsoModule, createStripeModule, createTotpModule, createTrustedDeviceModule, createUsernameAuthModule, customAuth, customSession, deviceAuth, deviceLabelFromRequest, emailOtp, gdpr, headerAuth, magicLink, oauthProxy, oneTap, organization, passkey, polar, scim, siwe, stripe, twoFactor, withRateLimit } from './chunk-KL6XW4S4.js';
5
- import { createPermissionEngine } from './chunk-OVGNZ5OX.js';
6
- export { createPermissionEngine, getPermissionTemplate, permissionTemplates } from './chunk-OVGNZ5OX.js';
7
- import { createAuditModule } from './chunk-SJGSPIAD.js';
8
- export { createAuditModule } from './chunk-SJGSPIAD.js';
9
- import { schema_exports, approvalRequests, sessions, delegationChains, agentDids, mcpServers, budgetPolicies, agents, permissions, auditLogs, tenants, trustScores } from './chunk-V66UUIA7.js';
10
- export { agentCards, agentDids, agents, apiKeys as apiKeysTable, approvalRequests, auditLogs, budgetPolicies, delegationChains, emailOtps, magicLinks, mcpServers, oauthAccessTokens, oauthAuthorizationCodes, oauthClients, orgInvitations, orgMembers, orgRoles, organizations, passkeyChallenges, passkeyCredentials, permissions, rateLimits, sessions, ssoConnections, tenants, totpRecords, trustScores, users } from './chunk-V66UUIA7.js';
11
- import './chunk-PZ5AY32C.js';
1
+ import { createAgentModule } from './chunk-IKTOSJ4O.js';
2
+ export { createAgentModule } from './chunk-IKTOSJ4O.js';
3
+ import { createSessionManager, createMagicLinkModule, createEmailOtpModule, createTotpModule, createPasskeyModule, createOrgModule, createSsoModule, createAdminModule, createApiKeyManagerModule, createUsernameAuthModule, createOneTimeTokenModule, createPasswordResetModule, createEmailVerificationModule, createPhoneAuthModule, createCaptchaModule, createWebhookModule } from './chunk-FKVAXCNJ.js';
4
+ export { EVENT_TYPES, HibpApiError, HibpBreachedError, OAuthProxyError, OneTapVerifyError, SSO_ERROR, SsoError, additionalFields, admin, anonymousAuth, apiKeys, bearerAuth, createAdditionalFieldsModule, createAdminModule, createAnonymousAuthModule, createApiKeyManagerModule, createCaptchaModule, createCostAttributionModule, createCustomSessionModule, createDeviceAuthModule, createEmailOtpModule, createEmailVerificationModule, createEphemeralSessionModule, createEventStreamModule, createFederationModule, createGdprModule, createHibpModule, createJwtSessionModule, createLastLoginModule, createMagicLinkModule, createOAuthProxyModule, createOidcProviderModule, createOneTapModule, createOneTimeTokenModule, createOpenApiModule, createOrgModule, createPasskeyModule, createPasswordResetModule, createPhoneAuthModule, createPolarModule, createRateLimiter, createReBACModule, createScimModule, createSessionManager, createSiweModule, createSsoModule, createStripeModule, createTotpModule, createTrustedDeviceModule, createUsernameAuthModule, customAuth, customSession, deviceAuth, deviceLabelFromRequest, emailOtp, gdpr, headerAuth, magicLink, oauthProxy, oneTap, organization, passkey, polar, scim, siwe, stripe, twoFactor, withRateLimit } from './chunk-FKVAXCNJ.js';
5
+ import { createPermissionEngine } from './chunk-VHKZARMM.js';
6
+ export { createPermissionEngine, getPermissionTemplate, permissionTemplates } from './chunk-VHKZARMM.js';
7
+ import { createAuditModule } from './chunk-Y3OWAJHK.js';
8
+ export { createAuditModule } from './chunk-Y3OWAJHK.js';
9
+ import { schema_exports, approvalRequests, sessions, delegationChains, agentDids, mcpServers, budgetPolicies, agents, permissions, auditLogs, tenants, trustScores } from './chunk-KDL6A76K.js';
10
+ export { agentCards, agentDids, agents, apiKeys as apiKeysTable, approvalRequests, auditLogs, budgetPolicies, delegationChains, emailOtps, magicLinks, mcpServers, oauthAccessTokens, oauthAuthorizationCodes, oauthClients, orgInvitations, orgMembers, orgRoles, organizations, passkeyChallenges, passkeyCredentials, permissions, rateLimits, sessions, ssoConnections, tenants, totpRecords, trustScores, users } from './chunk-KDL6A76K.js';
11
+ export { CredentialStatusSchema, CredentialSubjectSchema, KAVACH_AGENT_CREDENTIAL, KAVACH_DELEGATION_CREDENTIAL, KAVACH_PERMISSION_CREDENTIAL, ProofSchema, VC_CONTEXT_V1, VC_CONTEXT_V2, VC_TYPE_CREDENTIAL, VC_TYPE_PRESENTATION, VerifiableCredentialSchema, VerifiablePresentationSchema, createVCIssuer, createVCVerifier } from './chunk-NSTER7KE.js';
12
+ import { generateId } from './chunk-QCRHJMDX.js';
13
+ export { constantTimeEqual, fromBase64Url, fromHex, generateId, hmacSha1Raw, hmacSha256, hmacSha256Raw, importHmacKey, pbkdf2Hash, pbkdf2Verify, randomBytes, randomBytesHex, sha1, sha256, sha256Raw, toBase64Url, toHex } from './chunk-QCRHJMDX.js';
14
+ import { __require } from './chunk-NSBPE2FW.js';
12
15
  import { eq, and, lt, ne, or, isNull, gte } from 'drizzle-orm';
13
- import { randomUUID } from 'crypto';
14
- import BetterSqlite3 from 'better-sqlite3';
15
- import { drizzle } from 'drizzle-orm/better-sqlite3';
16
16
  import { generateKeyPair, exportJWK, importJWK, SignJWT, jwtVerify } from 'jose';
17
17
 
18
18
  var DEFAULT_LOOKBACK_DAYS = 30;
@@ -226,7 +226,7 @@ function createApprovalModule(config, db) {
226
226
  const ttlSeconds = config.ttl ?? 300;
227
227
  async function request(input) {
228
228
  const now = /* @__PURE__ */ new Date();
229
- const id = `apr_${randomUUID()}`;
229
+ const id = `apr_${generateId()}`;
230
230
  const expiresAt = new Date(now.getTime() + ttlSeconds * 1e3);
231
231
  await db.insert(approvalRequests).values({
232
232
  id,
@@ -314,12 +314,20 @@ function createApprovalModule(config, db) {
314
314
  cleanup
315
315
  };
316
316
  }
317
+
318
+ // src/db/database.ts
317
319
  async function createDatabase(config) {
318
320
  if (config.provider === "sqlite") {
321
+ const BetterSqlite3 = (await import('better-sqlite3').catch(() => {
322
+ throw new Error(
323
+ 'KavachOS: provider "sqlite" requires the "better-sqlite3" package. Install it with: npm install better-sqlite3'
324
+ );
325
+ })).default;
326
+ const { drizzle: drizzleSqlite } = await import('drizzle-orm/better-sqlite3');
319
327
  const sqlite = new BetterSqlite3(config.url);
320
328
  sqlite.pragma("journal_mode = WAL");
321
329
  sqlite.pragma("foreign_keys = ON");
322
- return drizzle(sqlite, { schema: schema_exports });
330
+ return drizzleSqlite(sqlite, { schema: schema_exports });
323
331
  }
324
332
  if (config.provider === "postgres") {
325
333
  const { Pool } = await import('pg').catch(() => {
@@ -341,8 +349,12 @@ async function createDatabase(config) {
341
349
  const pool = mysql2.createPool(config.url);
342
350
  return drizzle(pool);
343
351
  }
352
+ if (config.provider === "d1") {
353
+ const { drizzle } = await import('drizzle-orm/d1');
354
+ return drizzle(config.binding, { schema: schema_exports });
355
+ }
344
356
  throw new Error(
345
- `KavachOS: unsupported database provider "${config.provider}". Valid values are "sqlite", "postgres", "mysql".`
357
+ `KavachOS: unsupported database provider "${config.provider}". Valid values are "sqlite", "postgres", "mysql", "d1".`
346
358
  );
347
359
  }
348
360
  function createDatabaseSync(config) {
@@ -351,10 +363,14 @@ function createDatabaseSync(config) {
351
363
  `createDatabaseSync() only supports SQLite. Use the async createDatabase() for provider "${config.provider}".`
352
364
  );
353
365
  }
354
- const sqlite = new BetterSqlite3(config.url);
366
+ const { createRequire } = __require("module");
367
+ const req = createRequire(import.meta.url);
368
+ const BetterSqlite3Mod = req("better-sqlite3");
369
+ const { drizzle: drizzleSqliteMod } = req("drizzle-orm/better-sqlite3");
370
+ const sqlite = new BetterSqlite3Mod(config.url);
355
371
  sqlite.pragma("journal_mode = WAL");
356
372
  sqlite.pragma("foreign_keys = ON");
357
- return drizzle(sqlite, { schema: schema_exports });
373
+ return drizzleSqliteMod(sqlite, { schema: schema_exports });
358
374
  }
359
375
 
360
376
  // src/db/migrations.ts
@@ -382,6 +398,7 @@ function buildStatements(provider) {
382
398
  ban_reason TEXT,
383
399
  ban_expires_at ${tsNull},
384
400
  force_password_reset ${bool} NOT NULL DEFAULT ${isPostgres ? "FALSE" : "0"},
401
+ email_verified ${bool} NOT NULL DEFAULT ${isPostgres ? "FALSE" : "0"},
385
402
  stripe_customer_id TEXT UNIQUE,
386
403
  stripe_subscription_id TEXT,
387
404
  stripe_subscription_status TEXT,
@@ -857,6 +874,45 @@ function buildStatements(provider) {
857
874
  expires_at ${ts} NOT NULL,
858
875
  created_at ${ts} NOT NULL
859
876
  )`,
877
+ // ------------------------------------------------------------------
878
+ // kavach_cost_events (per-agent cost attribution)
879
+ // ------------------------------------------------------------------
880
+ `CREATE TABLE ${ifne} kavach_cost_events (
881
+ id TEXT NOT NULL PRIMARY KEY,
882
+ agent_id TEXT NOT NULL REFERENCES kavach_agents(id) ON DELETE CASCADE,
883
+ tool TEXT NOT NULL,
884
+ input_tokens INTEGER,
885
+ output_tokens INTEGER,
886
+ cost_micros INTEGER NOT NULL,
887
+ currency TEXT NOT NULL DEFAULT 'USD',
888
+ metadata ${json},
889
+ delegation_chain_id TEXT,
890
+ recorded_at ${ts} NOT NULL
891
+ )`,
892
+ `CREATE INDEX ${ifne} kavach_cost_events_agent_recorded
893
+ ON kavach_cost_events (agent_id, recorded_at DESC)`,
894
+ `CREATE INDEX ${ifne} kavach_cost_events_chain_id
895
+ ON kavach_cost_events (delegation_chain_id)`,
896
+ // ------------------------------------------------------------------
897
+ // kavach_ephemeral_sessions (short-lived agent credentials)
898
+ // ------------------------------------------------------------------
899
+ `CREATE TABLE ${ifne} kavach_ephemeral_sessions (
900
+ id TEXT NOT NULL PRIMARY KEY,
901
+ agent_id TEXT NOT NULL REFERENCES kavach_agents(id) ON DELETE CASCADE,
902
+ owner_id TEXT NOT NULL REFERENCES kavach_users(id),
903
+ token_hash TEXT NOT NULL UNIQUE,
904
+ expires_at ${ts} NOT NULL,
905
+ max_actions INTEGER,
906
+ actions_used INTEGER NOT NULL DEFAULT 0,
907
+ status TEXT NOT NULL DEFAULT 'active',
908
+ audit_group_id TEXT NOT NULL,
909
+ created_at ${ts} NOT NULL,
910
+ updated_at ${ts} NOT NULL
911
+ )`,
912
+ `CREATE INDEX ${ifne} kavach_ephemeral_sessions_owner_status
913
+ ON kavach_ephemeral_sessions (owner_id, status)`,
914
+ `CREATE INDEX ${ifne} kavach_ephemeral_sessions_expires_at
915
+ ON kavach_ephemeral_sessions (expires_at)`,
860
916
  // ------------------------------------------------------------------
861
917
  // kavach_jwt_refresh_tokens (JWT session plugin — general purpose)
862
918
  // ------------------------------------------------------------------
@@ -869,7 +925,84 @@ function buildStatements(provider) {
869
925
  created_at ${ts} NOT NULL
870
926
  )`,
871
927
  `CREATE INDEX ${ifne} kavach_jwt_refresh_tokens_user_id
872
- ON kavach_jwt_refresh_tokens (user_id)`
928
+ ON kavach_jwt_refresh_tokens (user_id)`,
929
+ // ------------------------------------------------------------------
930
+ // kavach_stream_events (persisted SSE events for replay)
931
+ // ------------------------------------------------------------------
932
+ `CREATE TABLE ${ifne} kavach_stream_events (
933
+ id TEXT NOT NULL PRIMARY KEY,
934
+ type TEXT NOT NULL,
935
+ timestamp ${ts} NOT NULL,
936
+ data ${json} NOT NULL,
937
+ agent_id TEXT,
938
+ user_id TEXT
939
+ )`,
940
+ `CREATE INDEX ${ifne} kavach_stream_events_timestamp
941
+ ON kavach_stream_events (timestamp DESC)`,
942
+ `CREATE INDEX ${ifne} kavach_stream_events_type_timestamp
943
+ ON kavach_stream_events (type, timestamp DESC)`,
944
+ // ------------------------------------------------------------------
945
+ // kavach_rebac_resources (ReBAC resource hierarchy)
946
+ // ------------------------------------------------------------------
947
+ `CREATE TABLE ${ifne} kavach_rebac_resources (
948
+ id TEXT NOT NULL PRIMARY KEY,
949
+ type TEXT NOT NULL,
950
+ parent_id TEXT,
951
+ parent_type TEXT,
952
+ created_at ${ts} NOT NULL
953
+ )`,
954
+ `CREATE INDEX ${ifne} kavach_rebac_resources_parent
955
+ ON kavach_rebac_resources (parent_id, parent_type)`,
956
+ // ------------------------------------------------------------------
957
+ // kavach_rebac_relationships (Zanzibar-style subject-relation-object tuples)
958
+ // ------------------------------------------------------------------
959
+ `CREATE TABLE ${ifne} kavach_rebac_relationships (
960
+ id TEXT NOT NULL PRIMARY KEY,
961
+ subject_type TEXT NOT NULL,
962
+ subject_id TEXT NOT NULL,
963
+ relation TEXT NOT NULL,
964
+ object_type TEXT NOT NULL,
965
+ object_id TEXT NOT NULL,
966
+ created_at ${ts} NOT NULL
967
+ )`,
968
+ `CREATE INDEX ${ifne} kavach_rebac_relationships_subject
969
+ ON kavach_rebac_relationships (subject_type, subject_id)`,
970
+ `CREATE INDEX ${ifne} kavach_rebac_relationships_object
971
+ ON kavach_rebac_relationships (object_type, object_id)`,
972
+ `CREATE UNIQUE INDEX ${ifne} kavach_rebac_relationships_tuple
973
+ ON kavach_rebac_relationships (subject_type, subject_id, relation, object_type, object_id)`,
974
+ // ------------------------------------------------------------------
975
+ // kavach_federation_instances (trusted remote KavachOS instances)
976
+ // ------------------------------------------------------------------
977
+ `CREATE TABLE ${ifne} kavach_federation_instances (
978
+ id TEXT NOT NULL PRIMARY KEY,
979
+ instance_id TEXT NOT NULL UNIQUE,
980
+ instance_url TEXT NOT NULL,
981
+ public_key_jwk TEXT,
982
+ trust_level TEXT NOT NULL DEFAULT 'verify-only',
983
+ discovered_at ${tsNull},
984
+ created_at ${ts} NOT NULL,
985
+ updated_at ${ts} NOT NULL
986
+ )`,
987
+ // ------------------------------------------------------------------
988
+ // kavach_federation_tokens (issued/received federation tokens)
989
+ // ------------------------------------------------------------------
990
+ `CREATE TABLE ${ifne} kavach_federation_tokens (
991
+ id TEXT NOT NULL PRIMARY KEY,
992
+ token_jti TEXT NOT NULL UNIQUE,
993
+ agent_id TEXT NOT NULL,
994
+ source_instance_id TEXT NOT NULL,
995
+ target_instance_id TEXT,
996
+ direction TEXT NOT NULL,
997
+ permissions ${json} NOT NULL,
998
+ trust_score INTEGER,
999
+ expires_at ${ts} NOT NULL,
1000
+ created_at ${ts} NOT NULL
1001
+ )`,
1002
+ `CREATE INDEX ${ifne} kavach_federation_tokens_agent
1003
+ ON kavach_federation_tokens (agent_id)`,
1004
+ `CREATE INDEX ${ifne} kavach_federation_tokens_source
1005
+ ON kavach_federation_tokens (source_instance_id)`
873
1006
  // ------------------------------------------------------------------
874
1007
  // kavach_users ban columns (ALTER TABLE IF NOT EXISTS — safe no-ops)
875
1008
  // These are appended as separate ALTER statements for existing DBs.
@@ -960,7 +1093,7 @@ function createDelegationModule(config) {
960
1093
  `Delegation depth ${currentDepth} exceeds maximum allowed depth of ${maxDepth}. This prevents infinite delegation chains.`
961
1094
  );
962
1095
  }
963
- const id = randomUUID();
1096
+ const id = generateId();
964
1097
  const now = /* @__PURE__ */ new Date();
965
1098
  await db.insert(delegationChains).values({
966
1099
  id,
@@ -2107,7 +2240,7 @@ function isExceeded(limits, usage) {
2107
2240
  }
2108
2241
  function createPolicyModule(db) {
2109
2242
  async function create(input) {
2110
- const id = `pol_${randomUUID().replace(/-/g, "")}`;
2243
+ const id = `pol_${generateId().replace(/-/g, "")}`;
2111
2244
  const now = /* @__PURE__ */ new Date();
2112
2245
  const usage = emptyUsage();
2113
2246
  await db.insert(budgetPolicies).values({
@@ -2262,6 +2395,334 @@ function createPolicyModule(db) {
2262
2395
  }
2263
2396
  return { create, get, list, update, remove, checkBudget, recordUsage, resetDaily, resetMonthly };
2264
2397
  }
2398
+
2399
+ // src/redirect/chain.ts
2400
+ var DEFAULT_COOKIE_NAME = "kavach_redirect";
2401
+ var DEFAULT_MAX_AGE = 600;
2402
+ var DEFAULT_PATH = "/";
2403
+ var DEFAULT_MAX_DEPTH = 10;
2404
+ var DEFAULT_EXCLUDE_PATHS = [
2405
+ "/sign-in",
2406
+ "/sign-up",
2407
+ "/forgot-password",
2408
+ "/reset-password",
2409
+ "/verify-email",
2410
+ "/api/"
2411
+ ];
2412
+ var encoder = new TextEncoder();
2413
+ var decoder = new TextDecoder();
2414
+ function encodeState(state) {
2415
+ const json = JSON.stringify(state);
2416
+ const bytes = encoder.encode(json);
2417
+ let binary = "";
2418
+ for (let i = 0; i < bytes.length; i++) {
2419
+ binary += String.fromCharCode(bytes[i]);
2420
+ }
2421
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2422
+ }
2423
+ function decodeState(encoded) {
2424
+ try {
2425
+ let base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
2426
+ while (base64.length % 4 !== 0) {
2427
+ base64 += "=";
2428
+ }
2429
+ const binary = atob(base64);
2430
+ const bytes = new Uint8Array(binary.length);
2431
+ for (let i = 0; i < binary.length; i++) {
2432
+ bytes[i] = binary.charCodeAt(i);
2433
+ }
2434
+ const json = decoder.decode(bytes);
2435
+ const parsed = JSON.parse(json);
2436
+ if (!isValidChainState(parsed)) return null;
2437
+ return parsed;
2438
+ } catch {
2439
+ return null;
2440
+ }
2441
+ }
2442
+ function isValidChainState(value) {
2443
+ if (typeof value !== "object" || value === null) return false;
2444
+ const obj = value;
2445
+ if (typeof obj.createdAt !== "number") return false;
2446
+ if (!isValidEntry(obj.origin)) return false;
2447
+ if (!Array.isArray(obj.steps)) return false;
2448
+ for (const step of obj.steps) {
2449
+ if (!isValidEntry(step)) return false;
2450
+ }
2451
+ return true;
2452
+ }
2453
+ function isValidEntry(value) {
2454
+ if (typeof value !== "object" || value === null) return false;
2455
+ const obj = value;
2456
+ return typeof obj.id === "string" && typeof obj.path === "string" && typeof obj.query === "object" && obj.query !== null && typeof obj.hash === "string" && typeof obj.createdAt === "number";
2457
+ }
2458
+ function parseCookies(request) {
2459
+ const header = request.headers.get("cookie");
2460
+ if (!header) return {};
2461
+ const cookies = {};
2462
+ for (const pair of header.split(";")) {
2463
+ const eqIdx = pair.indexOf("=");
2464
+ if (eqIdx === -1) continue;
2465
+ const key = pair.slice(0, eqIdx).trim();
2466
+ const val = pair.slice(eqIdx + 1).trim();
2467
+ cookies[key] = val;
2468
+ }
2469
+ return cookies;
2470
+ }
2471
+ function isExcluded(path, excludePaths) {
2472
+ for (const excluded of excludePaths) {
2473
+ if (excluded.endsWith("/")) {
2474
+ if (path.startsWith(excluded) || path === excluded.slice(0, -1)) return true;
2475
+ } else {
2476
+ if (path === excluded) return true;
2477
+ }
2478
+ }
2479
+ return false;
2480
+ }
2481
+ function createRedirectChain(config) {
2482
+ const cookieName = config?.cookieName ?? DEFAULT_COOKIE_NAME;
2483
+ const maxAge = config?.maxAge ?? DEFAULT_MAX_AGE;
2484
+ const defaultPath = config?.defaultPath ?? DEFAULT_PATH;
2485
+ const excludePaths = config?.excludePaths ?? DEFAULT_EXCLUDE_PATHS;
2486
+ const preserveQuery = config?.preserveQuery ?? true;
2487
+ const preserveHash = config?.preserveHash ?? true;
2488
+ const maxDepth = config?.maxDepth ?? DEFAULT_MAX_DEPTH;
2489
+ const cookieOpts = {
2490
+ httpOnly: config?.cookie?.httpOnly ?? true,
2491
+ secure: config?.cookie?.secure ?? true,
2492
+ sameSite: config?.cookie?.sameSite ?? "lax",
2493
+ path: config?.cookie?.path ?? "/",
2494
+ domain: config?.cookie?.domain
2495
+ };
2496
+ let currentState = null;
2497
+ function buildCookieHeader(value, age) {
2498
+ const parts = [`${cookieName}=${value}`, `Path=${cookieOpts.path}`, `Max-Age=${age}`];
2499
+ if (cookieOpts.httpOnly) parts.push("HttpOnly");
2500
+ if (cookieOpts.secure) parts.push("Secure");
2501
+ parts.push(
2502
+ `SameSite=${cookieOpts.sameSite.charAt(0).toUpperCase()}${cookieOpts.sameSite.slice(1)}`
2503
+ );
2504
+ if (cookieOpts.domain) parts.push(`Domain=${cookieOpts.domain}`);
2505
+ return parts.join("; ");
2506
+ }
2507
+ function buildClearCookie() {
2508
+ return buildCookieHeader("", 0);
2509
+ }
2510
+ function serializeAndSetCookie(state) {
2511
+ currentState = state;
2512
+ const encoded = encodeState(state);
2513
+ return buildCookieHeader(encoded, maxAge);
2514
+ }
2515
+ function parseFromRequest(request) {
2516
+ const cookies = parseCookies(request);
2517
+ const raw = cookies[cookieName];
2518
+ if (!raw) return null;
2519
+ const state = decodeState(raw);
2520
+ if (!state) return null;
2521
+ const elapsed = Date.now() - state.createdAt;
2522
+ if (elapsed > maxAge * 1e3) return null;
2523
+ currentState = state;
2524
+ return state;
2525
+ }
2526
+ function createEntryFromUrl(url, label) {
2527
+ let parsed;
2528
+ if (typeof url === "string") {
2529
+ if (url.startsWith("/")) {
2530
+ parsed = new URL(url, "http://localhost");
2531
+ } else {
2532
+ parsed = new URL(url);
2533
+ }
2534
+ } else {
2535
+ parsed = new URL(url.url);
2536
+ }
2537
+ const query = {};
2538
+ if (preserveQuery) {
2539
+ parsed.searchParams.forEach((value, key) => {
2540
+ query[key] = value;
2541
+ });
2542
+ }
2543
+ return {
2544
+ id: generateId(),
2545
+ path: parsed.pathname,
2546
+ query,
2547
+ hash: preserveHash ? parsed.hash.replace(/^#/, "") : "",
2548
+ createdAt: Date.now(),
2549
+ label
2550
+ };
2551
+ }
2552
+ function buildUrlFromEntry(entry) {
2553
+ let url = entry.path;
2554
+ const params = Object.entries(entry.query);
2555
+ if (params.length > 0) {
2556
+ const searchParams = new URLSearchParams();
2557
+ for (const [key, value] of params) {
2558
+ searchParams.set(key, value);
2559
+ }
2560
+ url += `?${searchParams.toString()}`;
2561
+ }
2562
+ if (entry.hash) {
2563
+ url += `#${entry.hash}`;
2564
+ }
2565
+ return url;
2566
+ }
2567
+ const manager = {
2568
+ capture(request) {
2569
+ const existing = parseFromRequest(request);
2570
+ if (existing) {
2571
+ return serializeAndSetCookie(existing);
2572
+ }
2573
+ const entry = createEntryFromUrl(request);
2574
+ if (isExcluded(entry.path, excludePaths)) {
2575
+ entry.path = defaultPath;
2576
+ entry.query = {};
2577
+ entry.hash = "";
2578
+ }
2579
+ const state = {
2580
+ origin: entry,
2581
+ steps: [],
2582
+ createdAt: Date.now()
2583
+ };
2584
+ return serializeAndSetCookie(state);
2585
+ },
2586
+ push(path, options) {
2587
+ if (!currentState) {
2588
+ currentState = {
2589
+ origin: {
2590
+ id: generateId(),
2591
+ path: defaultPath,
2592
+ query: {},
2593
+ hash: "",
2594
+ createdAt: Date.now()
2595
+ },
2596
+ steps: [],
2597
+ createdAt: Date.now()
2598
+ };
2599
+ }
2600
+ if (currentState.steps.length >= maxDepth) {
2601
+ return serializeAndSetCookie(currentState);
2602
+ }
2603
+ const entry = {
2604
+ id: generateId(),
2605
+ path,
2606
+ query: options?.query ?? {},
2607
+ hash: "",
2608
+ createdAt: Date.now(),
2609
+ label: options?.label
2610
+ };
2611
+ currentState.steps.push(entry);
2612
+ return serializeAndSetCookie(currentState);
2613
+ },
2614
+ pop(request) {
2615
+ const state = parseFromRequest(request);
2616
+ if (!state) {
2617
+ return { url: defaultPath, done: true, clearCookie: buildClearCookie() };
2618
+ }
2619
+ if (state.steps.length > 0) {
2620
+ const next = state.steps.shift();
2621
+ const url2 = buildUrlFromEntry(next);
2622
+ if (state.steps.length === 0) {
2623
+ currentState = state;
2624
+ return {
2625
+ url: url2,
2626
+ done: false,
2627
+ clearCookie: null
2628
+ };
2629
+ }
2630
+ return {
2631
+ url: url2,
2632
+ done: false,
2633
+ clearCookie: null
2634
+ };
2635
+ }
2636
+ const url = buildUrlFromEntry(state.origin);
2637
+ currentState = null;
2638
+ return {
2639
+ url,
2640
+ done: true,
2641
+ clearCookie: buildClearCookie()
2642
+ };
2643
+ },
2644
+ peek(request) {
2645
+ const state = parseFromRequest(request);
2646
+ if (!state) return null;
2647
+ if (state.steps.length > 0) {
2648
+ const next = state.steps[0];
2649
+ return {
2650
+ url: buildUrlFromEntry(next),
2651
+ remaining: state.steps.length
2652
+ // +origin is implicit
2653
+ };
2654
+ }
2655
+ return {
2656
+ url: buildUrlFromEntry(state.origin),
2657
+ remaining: 0
2658
+ };
2659
+ },
2660
+ getOrigin(request) {
2661
+ const state = parseFromRequest(request);
2662
+ if (!state) return null;
2663
+ return state.origin;
2664
+ },
2665
+ clear() {
2666
+ currentState = null;
2667
+ return buildClearCookie();
2668
+ },
2669
+ parse(request) {
2670
+ return parseFromRequest(request);
2671
+ },
2672
+ buildUrl(entry) {
2673
+ return buildUrlFromEntry(entry);
2674
+ },
2675
+ createEntry(url, label) {
2676
+ return createEntryFromUrl(url, label);
2677
+ }
2678
+ };
2679
+ return manager;
2680
+ }
2681
+
2682
+ // src/session/freshness.ts
2683
+ var DEFAULT_FRESH_AGE_SECONDS = 300;
2684
+ function createSessionFreshnessModule(config = {}) {
2685
+ const freshAge = config.freshAge ?? DEFAULT_FRESH_AGE_SECONDS;
2686
+ function isFresh(session) {
2687
+ const now = Date.now();
2688
+ const createdAt = session.createdAt.getTime();
2689
+ return now - createdAt < freshAge * 1e3;
2690
+ }
2691
+ function requireFresh(session) {
2692
+ if (isFresh(session)) {
2693
+ const freshUntil = new Date(session.createdAt.getTime() + freshAge * 1e3);
2694
+ return { success: true, data: { freshUntil } };
2695
+ }
2696
+ return {
2697
+ success: false,
2698
+ error: {
2699
+ code: "SESSION_NOT_FRESH",
2700
+ message: "Session is not fresh. Please re-authenticate to perform this action.",
2701
+ details: {
2702
+ createdAt: session.createdAt.toISOString(),
2703
+ freshAge,
2704
+ requiredAfter: new Date(session.createdAt.getTime() + freshAge * 1e3).toISOString()
2705
+ }
2706
+ }
2707
+ };
2708
+ }
2709
+ function guard(session) {
2710
+ if (isFresh(session)) return null;
2711
+ return new Response(
2712
+ JSON.stringify({
2713
+ error: {
2714
+ code: "SESSION_NOT_FRESH",
2715
+ message: "Session is not fresh. Please re-authenticate to perform this action."
2716
+ }
2717
+ }),
2718
+ {
2719
+ status: 403,
2720
+ headers: { "Content-Type": "application/json" }
2721
+ }
2722
+ );
2723
+ }
2724
+ return { isFresh, requireFresh, guard };
2725
+ }
2265
2726
  function slugRegex() {
2266
2727
  return /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2267
2728
  }
@@ -2287,7 +2748,7 @@ function createTenantModule(db) {
2287
2748
  if (existing.length > 0) {
2288
2749
  throw new Error(`Tenant with slug "${input.slug}" already exists.`);
2289
2750
  }
2290
- const id = `tnt_${randomUUID().replace(/-/g, "")}`;
2751
+ const id = `tnt_${generateId().replace(/-/g, "")}`;
2291
2752
  const now = /* @__PURE__ */ new Date();
2292
2753
  const settings = input.settings ?? {};
2293
2754
  await db.insert(tenants).values({
@@ -2529,8 +2990,12 @@ async function createKavach(config) {
2529
2990
  const adminModule = config.admin ? createAdminModule(config.admin, db, sessionManager) : null;
2530
2991
  const apiKeyManagerModule = config.apiKeys ? createApiKeyManagerModule(config.apiKeys, db) : null;
2531
2992
  const usernameModule = config.username && sessionManager ? createUsernameAuthModule(config.username, db, sessionManager) : null;
2993
+ const oneTimeTokenModule = createOneTimeTokenModule({}, db);
2994
+ const passwordResetModule = config.passwordReset && sessionManager ? createPasswordResetModule(config.passwordReset, db, sessionManager, oneTimeTokenModule) : null;
2995
+ const emailVerificationModule = config.emailVerification ? createEmailVerificationModule(config.emailVerification, db, oneTimeTokenModule) : null;
2532
2996
  const phoneModule = config.phone && sessionManager ? createPhoneAuthModule(config.phone, db, sessionManager) : null;
2533
2997
  const captchaModule = config.captcha ? createCaptchaModule(config.captcha) : null;
2998
+ const redirectChain = createRedirectChain(config.redirects);
2534
2999
  const webhookModule = config.webhooks && config.webhooks.length > 0 ? createWebhookModule(config.webhooks) : null;
2535
3000
  const pluginRegistry = await initializePlugins(config.plugins ?? [], db, config);
2536
3001
  const endpointCtx = {
@@ -2673,7 +3138,7 @@ async function createKavach(config) {
2673
3138
  */
2674
3139
  async register(input) {
2675
3140
  const now = /* @__PURE__ */ new Date();
2676
- const id = randomUUID();
3141
+ const id = generateId();
2677
3142
  await db.insert(mcpServers).values({
2678
3143
  id,
2679
3144
  name: input.name,
@@ -2967,6 +3432,65 @@ async function createKavach(config) {
2967
3432
  * ```
2968
3433
  */
2969
3434
  username: usernameModule,
3435
+ /**
3436
+ * Password reset (forgot password + reset password).
3437
+ *
3438
+ * Null when `passwordReset` config was not provided or `auth.session`
3439
+ * is not configured.
3440
+ *
3441
+ * @example
3442
+ * ```typescript
3443
+ * // In your route handler
3444
+ * const response = await kavach.passwordReset?.handleRequest(request);
3445
+ * if (response) return response;
3446
+ *
3447
+ * // Or programmatically
3448
+ * await kavach.passwordReset?.requestReset('alice@example.com');
3449
+ * await kavach.passwordReset?.resetPassword(token, 'new-password');
3450
+ * ```
3451
+ */
3452
+ passwordReset: passwordResetModule,
3453
+ /**
3454
+ * Email address verification.
3455
+ *
3456
+ * Null when `emailVerification` config was not provided.
3457
+ *
3458
+ * @example
3459
+ * ```typescript
3460
+ * // Send a verification email after sign-up
3461
+ * await kavach.emailVerification?.sendVerification(userId, email);
3462
+ *
3463
+ * // Confirm from the link in the email
3464
+ * const result = await kavach.emailVerification?.verify(token);
3465
+ *
3466
+ * // Check status
3467
+ * const verified = await kavach.emailVerification?.isVerified(userId);
3468
+ * ```
3469
+ */
3470
+ emailVerification: emailVerificationModule,
3471
+ /**
3472
+ * One-time tokens (email verify, password reset, invitations, custom).
3473
+ *
3474
+ * Always available. Used internally by password reset but exposed for
3475
+ * custom flows (email verification, invitation links, etc.).
3476
+ */
3477
+ oneTimeTokens: oneTimeTokenModule,
3478
+ /**
3479
+ * Session freshness enforcement for sensitive operations.
3480
+ *
3481
+ * Use as middleware before password changes, passkey registration,
3482
+ * billing updates, or any action that requires a recently-authenticated
3483
+ * session rather than an auto-refreshed one.
3484
+ *
3485
+ * @example
3486
+ * ```typescript
3487
+ * const stale = kavach.sessionFreshness.guard(session);
3488
+ * if (stale) return stale; // 403 SESSION_NOT_FRESH
3489
+ * ```
3490
+ */
3491
+ sessionFreshness: createSessionFreshnessModule(
3492
+ config.sessionFreshness
3493
+ ),
2970
3494
  /**
2971
3495
  * Phone number (SMS OTP) authentication.
2972
3496
  *
@@ -3003,6 +3527,27 @@ async function createKavach(config) {
3003
3527
  * ```
3004
3528
  */
3005
3529
  webhooks: webhookModule,
3530
+ /**
3531
+ * Redirect chain manager.
3532
+ *
3533
+ * Capture the user's original destination before auth redirects, push
3534
+ * intermediate steps (onboarding, email verification), and pop them
3535
+ * back in order. Cookie-based, works across page transitions and tabs.
3536
+ *
3537
+ * @example
3538
+ * ```typescript
3539
+ * // In auth middleware — save where the user was going
3540
+ * const setCookie = kavach.redirects.capture(request);
3541
+ * return new Response(null, { status: 302, headers: { Location: '/sign-in', 'Set-Cookie': setCookie } });
3542
+ *
3543
+ * // After sign-in — send user to their original destination
3544
+ * const { url, clearCookie } = kavach.redirects.pop(request);
3545
+ * const headers: Record<string, string> = { Location: url };
3546
+ * if (clearCookie) headers['Set-Cookie'] = clearCookie;
3547
+ * return new Response(null, { status: 302, headers });
3548
+ * ```
3549
+ */
3550
+ redirects: redirectChain,
3006
3551
  /**
3007
3552
  * Plugin system.
3008
3553
  *
@@ -3479,7 +4024,7 @@ function serializeCookieDeletion(name, options) {
3479
4024
  expires: /* @__PURE__ */ new Date(0)
3480
4025
  });
3481
4026
  }
3482
- function parseCookies(header) {
4027
+ function parseCookies2(header) {
3483
4028
  const result = {};
3484
4029
  if (!header || !header.trim()) return result;
3485
4030
  for (const pair of header.split(";")) {
@@ -3496,10 +4041,10 @@ function parseCookies(header) {
3496
4041
  return result;
3497
4042
  }
3498
4043
  function getCookie(header, name) {
3499
- return parseCookies(header)[name];
4044
+ return parseCookies2(header)[name];
3500
4045
  }
3501
4046
  function parseCookiesFromRequest(request) {
3502
- return parseCookies(request.headers.get("cookie") ?? "");
4047
+ return parseCookies2(request.headers.get("cookie") ?? "");
3503
4048
  }
3504
4049
  function capitalize(s) {
3505
4050
  return s.charAt(0).toUpperCase() + s.slice(1);
@@ -3793,15 +4338,15 @@ function buildSessionMetadata(request, extra) {
3793
4338
  }
3794
4339
 
3795
4340
  // src/webhooks/webhook.ts
3796
- function generateId() {
4341
+ function generateId2() {
3797
4342
  const bytes = new Uint8Array(16);
3798
4343
  crypto.getRandomValues(bytes);
3799
4344
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
3800
4345
  }
3801
4346
  async function signPayload2(secret, body) {
3802
- const encoder = new TextEncoder();
3803
- const keyData = encoder.encode(secret);
3804
- const messageData = encoder.encode(body);
4347
+ const encoder2 = new TextEncoder();
4348
+ const keyData = encoder2.encode(secret);
4349
+ const messageData = encoder2.encode(body);
3805
4350
  const key = await crypto.subtle.importKey(
3806
4351
  "raw",
3807
4352
  keyData,
@@ -3838,7 +4383,7 @@ async function deliverWebhook(url, event, payload, deliveryId, timestamp, signat
3838
4383
  }
3839
4384
  }
3840
4385
  async function dispatchWithRetry(url, event, payload, config) {
3841
- const deliveryId = generateId();
4386
+ const deliveryId = generateId2();
3842
4387
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3843
4388
  const body = JSON.stringify(payload);
3844
4389
  const signature = await signPayload2(config.secret, body);
@@ -3870,7 +4415,7 @@ function createWebhookModule2(config) {
3870
4415
  const subscriptions = /* @__PURE__ */ new Map();
3871
4416
  async function subscribe(url, events) {
3872
4417
  const sub = {
3873
- id: generateId(),
4418
+ id: generateId2(),
3874
4419
  url,
3875
4420
  events,
3876
4421
  active: true,
@@ -3898,7 +4443,7 @@ function createWebhookModule2(config) {
3898
4443
  if (!sub) {
3899
4444
  return { success: false, error: "Subscription not found" };
3900
4445
  }
3901
- const deliveryId = generateId();
4446
+ const deliveryId = generateId2();
3902
4447
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3903
4448
  const pingPayload = { event: "ping", subscriptionId, timestamp };
3904
4449
  const body = JSON.stringify(pingPayload);
@@ -3928,6 +4473,6 @@ async function verifyWebhookSignature(secret, rawBody, signature) {
3928
4473
  return diff === 0;
3929
4474
  }
3930
4475
 
3931
- export { MultiSessionLimitError, buildDidDocument, buildSessionMetadata, classifyViolation, createApprovalModule, createCookieSessionManager, createDatabase, createDatabaseSync, createDelegationModule, createDidModule, createEmailTemplates, createI18n, createKavach, createMultiSessionModule, createPluginRouter, createPolicyModule, createPresentation, createPrivilegeAnalyzer, createTables, createTenantModule, createTrustModule, createWebhookModule2 as createWebhookModule, de, en, es, fr, generateCsrfToken, generateDidKey, generateDidWeb, generateOpenAPISpec, getCookie, getDidWebUrl, initializePlugins, ja, parseCookies, parseCookiesFromRequest, resolveDidKey, resolveDidWeb, serializeCookie, serializeCookieDeletion, signPayload, validateCsrfToken, validateOrigin, verifyPayload, verifyPresentation, verifyWebhookSignature, zh };
4476
+ export { MultiSessionLimitError, buildDidDocument, buildSessionMetadata, classifyViolation, createApprovalModule, createCookieSessionManager, createDatabase, createDatabaseSync, createDelegationModule, createDidModule, createEmailTemplates, createI18n, createKavach, createMultiSessionModule, createPluginRouter, createPolicyModule, createPresentation, createPrivilegeAnalyzer, createRedirectChain, createSessionFreshnessModule, createTables, createTenantModule, createTrustModule, createWebhookModule2 as createWebhookModule, de, en, es, fr, generateCsrfToken, generateDidKey, generateDidWeb, generateOpenAPISpec, getCookie, getDidWebUrl, initializePlugins, ja, parseCookies2 as parseCookies, parseCookiesFromRequest, resolveDidKey, resolveDidWeb, serializeCookie, serializeCookieDeletion, signPayload, validateCsrfToken, validateOrigin, verifyPayload, verifyPresentation, verifyWebhookSignature, zh };
3932
4477
  //# sourceMappingURL=index.js.map
3933
4478
  //# sourceMappingURL=index.js.map