kavachos 0.0.3 → 0.0.5

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 (41) hide show
  1. package/dist/a2a/index.d.ts +2341 -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 -3
  5. package/dist/agent/index.js +3 -2
  6. package/dist/audit/index.d.ts +2 -2
  7. package/dist/audit/index.js +2 -2
  8. package/dist/auth/index.d.ts +490 -92
  9. package/dist/auth/index.js +3 -2
  10. package/dist/chunk-3AZDFCQF.js +186 -0
  11. package/dist/chunk-3AZDFCQF.js.map +1 -0
  12. package/dist/{chunk-SJGSPIAD.js → chunk-4CANWZWP.js} +3 -3
  13. package/dist/{chunk-SJGSPIAD.js.map → chunk-4CANWZWP.js.map} +1 -1
  14. package/dist/{chunk-KL6XW4S4.js → chunk-62P5FJ34.js} +2375 -633
  15. package/dist/chunk-62P5FJ34.js.map +1 -0
  16. package/dist/chunk-ELGG2VW2.js +538 -0
  17. package/dist/chunk-ELGG2VW2.js.map +1 -0
  18. package/dist/{chunk-5DT4DN4Y.js → chunk-IS5FRKIS.js} +13 -13
  19. package/dist/chunk-IS5FRKIS.js.map +1 -0
  20. package/dist/{chunk-V66UUIA7.js → chunk-KNNJ4COO.js} +92 -3
  21. package/dist/chunk-KNNJ4COO.js.map +1 -0
  22. package/dist/{chunk-OVGNZ5OX.js → chunk-O7VQ2LQE.js} +6 -6
  23. package/dist/chunk-O7VQ2LQE.js.map +1 -0
  24. package/dist/index.d.ts +138 -5
  25. package/dist/index.js +564 -29
  26. package/dist/index.js.map +1 -1
  27. package/dist/mcp/index.d.ts +2 -2
  28. package/dist/mcp/index.js +11 -15
  29. package/dist/mcp/index.js.map +1 -1
  30. package/dist/permission/index.d.ts +3 -3
  31. package/dist/permission/index.js +3 -2
  32. package/dist/{types-Xk83hv4O.d.ts → types-BTui0HQU.d.ts} +1763 -98
  33. package/dist/vc/index.d.ts +800 -0
  34. package/dist/vc/index.js +5 -0
  35. package/dist/vc/index.js.map +1 -0
  36. package/package.json +17 -1
  37. package/dist/chunk-5DT4DN4Y.js.map +0 -1
  38. package/dist/chunk-KL6XW4S4.js.map +0 -1
  39. package/dist/chunk-OVGNZ5OX.js.map +0 -1
  40. package/dist/chunk-V66UUIA7.js.map +0 -1
  41. package/dist/{types-mwupB57A.d.ts → types-BuHrZcjE.d.ts} +2 -2
package/dist/index.js CHANGED
@@ -1,16 +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';
1
+ import { createAgentModule } from './chunk-IS5FRKIS.js';
2
+ export { createAgentModule } from './chunk-IS5FRKIS.js';
3
+ import { createSessionManager, createMagicLinkModule, createEmailOtpModule, createTotpModule, createPasskeyModule, createOrgModule, createSsoModule, createAdminModule, createApiKeyManagerModule, createUsernameAuthModule, createOneTimeTokenModule, createPasswordResetModule, createEmailVerificationModule, createPhoneAuthModule, createCaptchaModule, createWebhookModule } from './chunk-62P5FJ34.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-62P5FJ34.js';
5
+ import { createPermissionEngine } from './chunk-O7VQ2LQE.js';
6
+ export { createPermissionEngine, getPermissionTemplate, permissionTemplates } from './chunk-O7VQ2LQE.js';
7
+ import { createAuditModule } from './chunk-4CANWZWP.js';
8
+ export { createAuditModule } from './chunk-4CANWZWP.js';
9
+ import { schema_exports, approvalRequests, sessions, delegationChains, agentDids, mcpServers, budgetPolicies, agents, permissions, auditLogs, tenants, trustScores } from './chunk-KNNJ4COO.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-KNNJ4COO.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-ELGG2VW2.js';
12
+ import { generateId } from './chunk-3AZDFCQF.js';
13
+ export { constantTimeEqual, fromBase64Url, fromHex, generateId, hmacSha1Raw, hmacSha256, hmacSha256Raw, importHmacKey, pbkdf2Hash, pbkdf2Verify, randomBytes, randomBytesHex, sha1, sha256, sha256Raw, toBase64Url, toHex } from './chunk-3AZDFCQF.js';
11
14
  import './chunk-PZ5AY32C.js';
12
15
  import { eq, and, lt, ne, or, isNull, gte } from 'drizzle-orm';
13
- import { randomUUID } from 'crypto';
14
16
  import BetterSqlite3 from 'better-sqlite3';
15
17
  import { drizzle } from 'drizzle-orm/better-sqlite3';
16
18
  import { generateKeyPair, exportJWK, importJWK, SignJWT, jwtVerify } from 'jose';
@@ -226,7 +228,7 @@ function createApprovalModule(config, db) {
226
228
  const ttlSeconds = config.ttl ?? 300;
227
229
  async function request(input) {
228
230
  const now = /* @__PURE__ */ new Date();
229
- const id = `apr_${randomUUID()}`;
231
+ const id = `apr_${generateId()}`;
230
232
  const expiresAt = new Date(now.getTime() + ttlSeconds * 1e3);
231
233
  await db.insert(approvalRequests).values({
232
234
  id,
@@ -341,8 +343,12 @@ async function createDatabase(config) {
341
343
  const pool = mysql2.createPool(config.url);
342
344
  return drizzle(pool);
343
345
  }
346
+ if (config.provider === "d1") {
347
+ const { drizzle } = await import('drizzle-orm/d1');
348
+ return drizzle(config.binding, { schema: schema_exports });
349
+ }
344
350
  throw new Error(
345
- `KavachOS: unsupported database provider "${config.provider}". Valid values are "sqlite", "postgres", "mysql".`
351
+ `KavachOS: unsupported database provider "${config.provider}". Valid values are "sqlite", "postgres", "mysql", "d1".`
346
352
  );
347
353
  }
348
354
  function createDatabaseSync(config) {
@@ -382,6 +388,7 @@ function buildStatements(provider) {
382
388
  ban_reason TEXT,
383
389
  ban_expires_at ${tsNull},
384
390
  force_password_reset ${bool} NOT NULL DEFAULT ${isPostgres ? "FALSE" : "0"},
391
+ email_verified ${bool} NOT NULL DEFAULT ${isPostgres ? "FALSE" : "0"},
385
392
  stripe_customer_id TEXT UNIQUE,
386
393
  stripe_subscription_id TEXT,
387
394
  stripe_subscription_status TEXT,
@@ -857,6 +864,45 @@ function buildStatements(provider) {
857
864
  expires_at ${ts} NOT NULL,
858
865
  created_at ${ts} NOT NULL
859
866
  )`,
867
+ // ------------------------------------------------------------------
868
+ // kavach_cost_events (per-agent cost attribution)
869
+ // ------------------------------------------------------------------
870
+ `CREATE TABLE ${ifne} kavach_cost_events (
871
+ id TEXT NOT NULL PRIMARY KEY,
872
+ agent_id TEXT NOT NULL REFERENCES kavach_agents(id) ON DELETE CASCADE,
873
+ tool TEXT NOT NULL,
874
+ input_tokens INTEGER,
875
+ output_tokens INTEGER,
876
+ cost_micros INTEGER NOT NULL,
877
+ currency TEXT NOT NULL DEFAULT 'USD',
878
+ metadata ${json},
879
+ delegation_chain_id TEXT,
880
+ recorded_at ${ts} NOT NULL
881
+ )`,
882
+ `CREATE INDEX ${ifne} kavach_cost_events_agent_recorded
883
+ ON kavach_cost_events (agent_id, recorded_at DESC)`,
884
+ `CREATE INDEX ${ifne} kavach_cost_events_chain_id
885
+ ON kavach_cost_events (delegation_chain_id)`,
886
+ // ------------------------------------------------------------------
887
+ // kavach_ephemeral_sessions (short-lived agent credentials)
888
+ // ------------------------------------------------------------------
889
+ `CREATE TABLE ${ifne} kavach_ephemeral_sessions (
890
+ id TEXT NOT NULL PRIMARY KEY,
891
+ agent_id TEXT NOT NULL REFERENCES kavach_agents(id) ON DELETE CASCADE,
892
+ owner_id TEXT NOT NULL REFERENCES kavach_users(id),
893
+ token_hash TEXT NOT NULL UNIQUE,
894
+ expires_at ${ts} NOT NULL,
895
+ max_actions INTEGER,
896
+ actions_used INTEGER NOT NULL DEFAULT 0,
897
+ status TEXT NOT NULL DEFAULT 'active',
898
+ audit_group_id TEXT NOT NULL,
899
+ created_at ${ts} NOT NULL,
900
+ updated_at ${ts} NOT NULL
901
+ )`,
902
+ `CREATE INDEX ${ifne} kavach_ephemeral_sessions_owner_status
903
+ ON kavach_ephemeral_sessions (owner_id, status)`,
904
+ `CREATE INDEX ${ifne} kavach_ephemeral_sessions_expires_at
905
+ ON kavach_ephemeral_sessions (expires_at)`,
860
906
  // ------------------------------------------------------------------
861
907
  // kavach_jwt_refresh_tokens (JWT session plugin — general purpose)
862
908
  // ------------------------------------------------------------------
@@ -869,7 +915,84 @@ function buildStatements(provider) {
869
915
  created_at ${ts} NOT NULL
870
916
  )`,
871
917
  `CREATE INDEX ${ifne} kavach_jwt_refresh_tokens_user_id
872
- ON kavach_jwt_refresh_tokens (user_id)`
918
+ ON kavach_jwt_refresh_tokens (user_id)`,
919
+ // ------------------------------------------------------------------
920
+ // kavach_stream_events (persisted SSE events for replay)
921
+ // ------------------------------------------------------------------
922
+ `CREATE TABLE ${ifne} kavach_stream_events (
923
+ id TEXT NOT NULL PRIMARY KEY,
924
+ type TEXT NOT NULL,
925
+ timestamp ${ts} NOT NULL,
926
+ data ${json} NOT NULL,
927
+ agent_id TEXT,
928
+ user_id TEXT
929
+ )`,
930
+ `CREATE INDEX ${ifne} kavach_stream_events_timestamp
931
+ ON kavach_stream_events (timestamp DESC)`,
932
+ `CREATE INDEX ${ifne} kavach_stream_events_type_timestamp
933
+ ON kavach_stream_events (type, timestamp DESC)`,
934
+ // ------------------------------------------------------------------
935
+ // kavach_rebac_resources (ReBAC resource hierarchy)
936
+ // ------------------------------------------------------------------
937
+ `CREATE TABLE ${ifne} kavach_rebac_resources (
938
+ id TEXT NOT NULL PRIMARY KEY,
939
+ type TEXT NOT NULL,
940
+ parent_id TEXT,
941
+ parent_type TEXT,
942
+ created_at ${ts} NOT NULL
943
+ )`,
944
+ `CREATE INDEX ${ifne} kavach_rebac_resources_parent
945
+ ON kavach_rebac_resources (parent_id, parent_type)`,
946
+ // ------------------------------------------------------------------
947
+ // kavach_rebac_relationships (Zanzibar-style subject-relation-object tuples)
948
+ // ------------------------------------------------------------------
949
+ `CREATE TABLE ${ifne} kavach_rebac_relationships (
950
+ id TEXT NOT NULL PRIMARY KEY,
951
+ subject_type TEXT NOT NULL,
952
+ subject_id TEXT NOT NULL,
953
+ relation TEXT NOT NULL,
954
+ object_type TEXT NOT NULL,
955
+ object_id TEXT NOT NULL,
956
+ created_at ${ts} NOT NULL
957
+ )`,
958
+ `CREATE INDEX ${ifne} kavach_rebac_relationships_subject
959
+ ON kavach_rebac_relationships (subject_type, subject_id)`,
960
+ `CREATE INDEX ${ifne} kavach_rebac_relationships_object
961
+ ON kavach_rebac_relationships (object_type, object_id)`,
962
+ `CREATE UNIQUE INDEX ${ifne} kavach_rebac_relationships_tuple
963
+ ON kavach_rebac_relationships (subject_type, subject_id, relation, object_type, object_id)`,
964
+ // ------------------------------------------------------------------
965
+ // kavach_federation_instances (trusted remote KavachOS instances)
966
+ // ------------------------------------------------------------------
967
+ `CREATE TABLE ${ifne} kavach_federation_instances (
968
+ id TEXT NOT NULL PRIMARY KEY,
969
+ instance_id TEXT NOT NULL UNIQUE,
970
+ instance_url TEXT NOT NULL,
971
+ public_key_jwk TEXT,
972
+ trust_level TEXT NOT NULL DEFAULT 'verify-only',
973
+ discovered_at ${tsNull},
974
+ created_at ${ts} NOT NULL,
975
+ updated_at ${ts} NOT NULL
976
+ )`,
977
+ // ------------------------------------------------------------------
978
+ // kavach_federation_tokens (issued/received federation tokens)
979
+ // ------------------------------------------------------------------
980
+ `CREATE TABLE ${ifne} kavach_federation_tokens (
981
+ id TEXT NOT NULL PRIMARY KEY,
982
+ token_jti TEXT NOT NULL UNIQUE,
983
+ agent_id TEXT NOT NULL,
984
+ source_instance_id TEXT NOT NULL,
985
+ target_instance_id TEXT,
986
+ direction TEXT NOT NULL,
987
+ permissions ${json} NOT NULL,
988
+ trust_score INTEGER,
989
+ expires_at ${ts} NOT NULL,
990
+ created_at ${ts} NOT NULL
991
+ )`,
992
+ `CREATE INDEX ${ifne} kavach_federation_tokens_agent
993
+ ON kavach_federation_tokens (agent_id)`,
994
+ `CREATE INDEX ${ifne} kavach_federation_tokens_source
995
+ ON kavach_federation_tokens (source_instance_id)`
873
996
  // ------------------------------------------------------------------
874
997
  // kavach_users ban columns (ALTER TABLE IF NOT EXISTS — safe no-ops)
875
998
  // These are appended as separate ALTER statements for existing DBs.
@@ -960,7 +1083,7 @@ function createDelegationModule(config) {
960
1083
  `Delegation depth ${currentDepth} exceeds maximum allowed depth of ${maxDepth}. This prevents infinite delegation chains.`
961
1084
  );
962
1085
  }
963
- const id = randomUUID();
1086
+ const id = generateId();
964
1087
  const now = /* @__PURE__ */ new Date();
965
1088
  await db.insert(delegationChains).values({
966
1089
  id,
@@ -2107,7 +2230,7 @@ function isExceeded(limits, usage) {
2107
2230
  }
2108
2231
  function createPolicyModule(db) {
2109
2232
  async function create(input) {
2110
- const id = `pol_${randomUUID().replace(/-/g, "")}`;
2233
+ const id = `pol_${generateId().replace(/-/g, "")}`;
2111
2234
  const now = /* @__PURE__ */ new Date();
2112
2235
  const usage = emptyUsage();
2113
2236
  await db.insert(budgetPolicies).values({
@@ -2262,6 +2385,334 @@ function createPolicyModule(db) {
2262
2385
  }
2263
2386
  return { create, get, list, update, remove, checkBudget, recordUsage, resetDaily, resetMonthly };
2264
2387
  }
2388
+
2389
+ // src/redirect/chain.ts
2390
+ var DEFAULT_COOKIE_NAME = "kavach_redirect";
2391
+ var DEFAULT_MAX_AGE = 600;
2392
+ var DEFAULT_PATH = "/";
2393
+ var DEFAULT_MAX_DEPTH = 10;
2394
+ var DEFAULT_EXCLUDE_PATHS = [
2395
+ "/sign-in",
2396
+ "/sign-up",
2397
+ "/forgot-password",
2398
+ "/reset-password",
2399
+ "/verify-email",
2400
+ "/api/"
2401
+ ];
2402
+ var encoder = new TextEncoder();
2403
+ var decoder = new TextDecoder();
2404
+ function encodeState(state) {
2405
+ const json = JSON.stringify(state);
2406
+ const bytes = encoder.encode(json);
2407
+ let binary = "";
2408
+ for (let i = 0; i < bytes.length; i++) {
2409
+ binary += String.fromCharCode(bytes[i]);
2410
+ }
2411
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2412
+ }
2413
+ function decodeState(encoded) {
2414
+ try {
2415
+ let base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
2416
+ while (base64.length % 4 !== 0) {
2417
+ base64 += "=";
2418
+ }
2419
+ const binary = atob(base64);
2420
+ const bytes = new Uint8Array(binary.length);
2421
+ for (let i = 0; i < binary.length; i++) {
2422
+ bytes[i] = binary.charCodeAt(i);
2423
+ }
2424
+ const json = decoder.decode(bytes);
2425
+ const parsed = JSON.parse(json);
2426
+ if (!isValidChainState(parsed)) return null;
2427
+ return parsed;
2428
+ } catch {
2429
+ return null;
2430
+ }
2431
+ }
2432
+ function isValidChainState(value) {
2433
+ if (typeof value !== "object" || value === null) return false;
2434
+ const obj = value;
2435
+ if (typeof obj.createdAt !== "number") return false;
2436
+ if (!isValidEntry(obj.origin)) return false;
2437
+ if (!Array.isArray(obj.steps)) return false;
2438
+ for (const step of obj.steps) {
2439
+ if (!isValidEntry(step)) return false;
2440
+ }
2441
+ return true;
2442
+ }
2443
+ function isValidEntry(value) {
2444
+ if (typeof value !== "object" || value === null) return false;
2445
+ const obj = value;
2446
+ return typeof obj.id === "string" && typeof obj.path === "string" && typeof obj.query === "object" && obj.query !== null && typeof obj.hash === "string" && typeof obj.createdAt === "number";
2447
+ }
2448
+ function parseCookies(request) {
2449
+ const header = request.headers.get("cookie");
2450
+ if (!header) return {};
2451
+ const cookies = {};
2452
+ for (const pair of header.split(";")) {
2453
+ const eqIdx = pair.indexOf("=");
2454
+ if (eqIdx === -1) continue;
2455
+ const key = pair.slice(0, eqIdx).trim();
2456
+ const val = pair.slice(eqIdx + 1).trim();
2457
+ cookies[key] = val;
2458
+ }
2459
+ return cookies;
2460
+ }
2461
+ function isExcluded(path, excludePaths) {
2462
+ for (const excluded of excludePaths) {
2463
+ if (excluded.endsWith("/")) {
2464
+ if (path.startsWith(excluded) || path === excluded.slice(0, -1)) return true;
2465
+ } else {
2466
+ if (path === excluded) return true;
2467
+ }
2468
+ }
2469
+ return false;
2470
+ }
2471
+ function createRedirectChain(config) {
2472
+ const cookieName = config?.cookieName ?? DEFAULT_COOKIE_NAME;
2473
+ const maxAge = config?.maxAge ?? DEFAULT_MAX_AGE;
2474
+ const defaultPath = config?.defaultPath ?? DEFAULT_PATH;
2475
+ const excludePaths = config?.excludePaths ?? DEFAULT_EXCLUDE_PATHS;
2476
+ const preserveQuery = config?.preserveQuery ?? true;
2477
+ const preserveHash = config?.preserveHash ?? true;
2478
+ const maxDepth = config?.maxDepth ?? DEFAULT_MAX_DEPTH;
2479
+ const cookieOpts = {
2480
+ httpOnly: config?.cookie?.httpOnly ?? true,
2481
+ secure: config?.cookie?.secure ?? true,
2482
+ sameSite: config?.cookie?.sameSite ?? "lax",
2483
+ path: config?.cookie?.path ?? "/",
2484
+ domain: config?.cookie?.domain
2485
+ };
2486
+ let currentState = null;
2487
+ function buildCookieHeader(value, age) {
2488
+ const parts = [`${cookieName}=${value}`, `Path=${cookieOpts.path}`, `Max-Age=${age}`];
2489
+ if (cookieOpts.httpOnly) parts.push("HttpOnly");
2490
+ if (cookieOpts.secure) parts.push("Secure");
2491
+ parts.push(
2492
+ `SameSite=${cookieOpts.sameSite.charAt(0).toUpperCase()}${cookieOpts.sameSite.slice(1)}`
2493
+ );
2494
+ if (cookieOpts.domain) parts.push(`Domain=${cookieOpts.domain}`);
2495
+ return parts.join("; ");
2496
+ }
2497
+ function buildClearCookie() {
2498
+ return buildCookieHeader("", 0);
2499
+ }
2500
+ function serializeAndSetCookie(state) {
2501
+ currentState = state;
2502
+ const encoded = encodeState(state);
2503
+ return buildCookieHeader(encoded, maxAge);
2504
+ }
2505
+ function parseFromRequest(request) {
2506
+ const cookies = parseCookies(request);
2507
+ const raw = cookies[cookieName];
2508
+ if (!raw) return null;
2509
+ const state = decodeState(raw);
2510
+ if (!state) return null;
2511
+ const elapsed = Date.now() - state.createdAt;
2512
+ if (elapsed > maxAge * 1e3) return null;
2513
+ currentState = state;
2514
+ return state;
2515
+ }
2516
+ function createEntryFromUrl(url, label) {
2517
+ let parsed;
2518
+ if (typeof url === "string") {
2519
+ if (url.startsWith("/")) {
2520
+ parsed = new URL(url, "http://localhost");
2521
+ } else {
2522
+ parsed = new URL(url);
2523
+ }
2524
+ } else {
2525
+ parsed = new URL(url.url);
2526
+ }
2527
+ const query = {};
2528
+ if (preserveQuery) {
2529
+ parsed.searchParams.forEach((value, key) => {
2530
+ query[key] = value;
2531
+ });
2532
+ }
2533
+ return {
2534
+ id: generateId(),
2535
+ path: parsed.pathname,
2536
+ query,
2537
+ hash: preserveHash ? parsed.hash.replace(/^#/, "") : "",
2538
+ createdAt: Date.now(),
2539
+ label
2540
+ };
2541
+ }
2542
+ function buildUrlFromEntry(entry) {
2543
+ let url = entry.path;
2544
+ const params = Object.entries(entry.query);
2545
+ if (params.length > 0) {
2546
+ const searchParams = new URLSearchParams();
2547
+ for (const [key, value] of params) {
2548
+ searchParams.set(key, value);
2549
+ }
2550
+ url += `?${searchParams.toString()}`;
2551
+ }
2552
+ if (entry.hash) {
2553
+ url += `#${entry.hash}`;
2554
+ }
2555
+ return url;
2556
+ }
2557
+ const manager = {
2558
+ capture(request) {
2559
+ const existing = parseFromRequest(request);
2560
+ if (existing) {
2561
+ return serializeAndSetCookie(existing);
2562
+ }
2563
+ const entry = createEntryFromUrl(request);
2564
+ if (isExcluded(entry.path, excludePaths)) {
2565
+ entry.path = defaultPath;
2566
+ entry.query = {};
2567
+ entry.hash = "";
2568
+ }
2569
+ const state = {
2570
+ origin: entry,
2571
+ steps: [],
2572
+ createdAt: Date.now()
2573
+ };
2574
+ return serializeAndSetCookie(state);
2575
+ },
2576
+ push(path, options) {
2577
+ if (!currentState) {
2578
+ currentState = {
2579
+ origin: {
2580
+ id: generateId(),
2581
+ path: defaultPath,
2582
+ query: {},
2583
+ hash: "",
2584
+ createdAt: Date.now()
2585
+ },
2586
+ steps: [],
2587
+ createdAt: Date.now()
2588
+ };
2589
+ }
2590
+ if (currentState.steps.length >= maxDepth) {
2591
+ return serializeAndSetCookie(currentState);
2592
+ }
2593
+ const entry = {
2594
+ id: generateId(),
2595
+ path,
2596
+ query: options?.query ?? {},
2597
+ hash: "",
2598
+ createdAt: Date.now(),
2599
+ label: options?.label
2600
+ };
2601
+ currentState.steps.push(entry);
2602
+ return serializeAndSetCookie(currentState);
2603
+ },
2604
+ pop(request) {
2605
+ const state = parseFromRequest(request);
2606
+ if (!state) {
2607
+ return { url: defaultPath, done: true, clearCookie: buildClearCookie() };
2608
+ }
2609
+ if (state.steps.length > 0) {
2610
+ const next = state.steps.shift();
2611
+ const url2 = buildUrlFromEntry(next);
2612
+ if (state.steps.length === 0) {
2613
+ currentState = state;
2614
+ return {
2615
+ url: url2,
2616
+ done: false,
2617
+ clearCookie: null
2618
+ };
2619
+ }
2620
+ return {
2621
+ url: url2,
2622
+ done: false,
2623
+ clearCookie: null
2624
+ };
2625
+ }
2626
+ const url = buildUrlFromEntry(state.origin);
2627
+ currentState = null;
2628
+ return {
2629
+ url,
2630
+ done: true,
2631
+ clearCookie: buildClearCookie()
2632
+ };
2633
+ },
2634
+ peek(request) {
2635
+ const state = parseFromRequest(request);
2636
+ if (!state) return null;
2637
+ if (state.steps.length > 0) {
2638
+ const next = state.steps[0];
2639
+ return {
2640
+ url: buildUrlFromEntry(next),
2641
+ remaining: state.steps.length
2642
+ // +origin is implicit
2643
+ };
2644
+ }
2645
+ return {
2646
+ url: buildUrlFromEntry(state.origin),
2647
+ remaining: 0
2648
+ };
2649
+ },
2650
+ getOrigin(request) {
2651
+ const state = parseFromRequest(request);
2652
+ if (!state) return null;
2653
+ return state.origin;
2654
+ },
2655
+ clear() {
2656
+ currentState = null;
2657
+ return buildClearCookie();
2658
+ },
2659
+ parse(request) {
2660
+ return parseFromRequest(request);
2661
+ },
2662
+ buildUrl(entry) {
2663
+ return buildUrlFromEntry(entry);
2664
+ },
2665
+ createEntry(url, label) {
2666
+ return createEntryFromUrl(url, label);
2667
+ }
2668
+ };
2669
+ return manager;
2670
+ }
2671
+
2672
+ // src/session/freshness.ts
2673
+ var DEFAULT_FRESH_AGE_SECONDS = 300;
2674
+ function createSessionFreshnessModule(config = {}) {
2675
+ const freshAge = config.freshAge ?? DEFAULT_FRESH_AGE_SECONDS;
2676
+ function isFresh(session) {
2677
+ const now = Date.now();
2678
+ const createdAt = session.createdAt.getTime();
2679
+ return now - createdAt < freshAge * 1e3;
2680
+ }
2681
+ function requireFresh(session) {
2682
+ if (isFresh(session)) {
2683
+ const freshUntil = new Date(session.createdAt.getTime() + freshAge * 1e3);
2684
+ return { success: true, data: { freshUntil } };
2685
+ }
2686
+ return {
2687
+ success: false,
2688
+ error: {
2689
+ code: "SESSION_NOT_FRESH",
2690
+ message: "Session is not fresh. Please re-authenticate to perform this action.",
2691
+ details: {
2692
+ createdAt: session.createdAt.toISOString(),
2693
+ freshAge,
2694
+ requiredAfter: new Date(session.createdAt.getTime() + freshAge * 1e3).toISOString()
2695
+ }
2696
+ }
2697
+ };
2698
+ }
2699
+ function guard(session) {
2700
+ if (isFresh(session)) return null;
2701
+ return new Response(
2702
+ JSON.stringify({
2703
+ error: {
2704
+ code: "SESSION_NOT_FRESH",
2705
+ message: "Session is not fresh. Please re-authenticate to perform this action."
2706
+ }
2707
+ }),
2708
+ {
2709
+ status: 403,
2710
+ headers: { "Content-Type": "application/json" }
2711
+ }
2712
+ );
2713
+ }
2714
+ return { isFresh, requireFresh, guard };
2715
+ }
2265
2716
  function slugRegex() {
2266
2717
  return /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2267
2718
  }
@@ -2287,7 +2738,7 @@ function createTenantModule(db) {
2287
2738
  if (existing.length > 0) {
2288
2739
  throw new Error(`Tenant with slug "${input.slug}" already exists.`);
2289
2740
  }
2290
- const id = `tnt_${randomUUID().replace(/-/g, "")}`;
2741
+ const id = `tnt_${generateId().replace(/-/g, "")}`;
2291
2742
  const now = /* @__PURE__ */ new Date();
2292
2743
  const settings = input.settings ?? {};
2293
2744
  await db.insert(tenants).values({
@@ -2529,8 +2980,12 @@ async function createKavach(config) {
2529
2980
  const adminModule = config.admin ? createAdminModule(config.admin, db, sessionManager) : null;
2530
2981
  const apiKeyManagerModule = config.apiKeys ? createApiKeyManagerModule(config.apiKeys, db) : null;
2531
2982
  const usernameModule = config.username && sessionManager ? createUsernameAuthModule(config.username, db, sessionManager) : null;
2983
+ const oneTimeTokenModule = createOneTimeTokenModule({}, db);
2984
+ const passwordResetModule = config.passwordReset && sessionManager ? createPasswordResetModule(config.passwordReset, db, sessionManager, oneTimeTokenModule) : null;
2985
+ const emailVerificationModule = config.emailVerification ? createEmailVerificationModule(config.emailVerification, db, oneTimeTokenModule) : null;
2532
2986
  const phoneModule = config.phone && sessionManager ? createPhoneAuthModule(config.phone, db, sessionManager) : null;
2533
2987
  const captchaModule = config.captcha ? createCaptchaModule(config.captcha) : null;
2988
+ const redirectChain = createRedirectChain(config.redirects);
2534
2989
  const webhookModule = config.webhooks && config.webhooks.length > 0 ? createWebhookModule(config.webhooks) : null;
2535
2990
  const pluginRegistry = await initializePlugins(config.plugins ?? [], db, config);
2536
2991
  const endpointCtx = {
@@ -2673,7 +3128,7 @@ async function createKavach(config) {
2673
3128
  */
2674
3129
  async register(input) {
2675
3130
  const now = /* @__PURE__ */ new Date();
2676
- const id = randomUUID();
3131
+ const id = generateId();
2677
3132
  await db.insert(mcpServers).values({
2678
3133
  id,
2679
3134
  name: input.name,
@@ -2967,6 +3422,65 @@ async function createKavach(config) {
2967
3422
  * ```
2968
3423
  */
2969
3424
  username: usernameModule,
3425
+ /**
3426
+ * Password reset (forgot password + reset password).
3427
+ *
3428
+ * Null when `passwordReset` config was not provided or `auth.session`
3429
+ * is not configured.
3430
+ *
3431
+ * @example
3432
+ * ```typescript
3433
+ * // In your route handler
3434
+ * const response = await kavach.passwordReset?.handleRequest(request);
3435
+ * if (response) return response;
3436
+ *
3437
+ * // Or programmatically
3438
+ * await kavach.passwordReset?.requestReset('alice@example.com');
3439
+ * await kavach.passwordReset?.resetPassword(token, 'new-password');
3440
+ * ```
3441
+ */
3442
+ passwordReset: passwordResetModule,
3443
+ /**
3444
+ * Email address verification.
3445
+ *
3446
+ * Null when `emailVerification` config was not provided.
3447
+ *
3448
+ * @example
3449
+ * ```typescript
3450
+ * // Send a verification email after sign-up
3451
+ * await kavach.emailVerification?.sendVerification(userId, email);
3452
+ *
3453
+ * // Confirm from the link in the email
3454
+ * const result = await kavach.emailVerification?.verify(token);
3455
+ *
3456
+ * // Check status
3457
+ * const verified = await kavach.emailVerification?.isVerified(userId);
3458
+ * ```
3459
+ */
3460
+ emailVerification: emailVerificationModule,
3461
+ /**
3462
+ * One-time tokens (email verify, password reset, invitations, custom).
3463
+ *
3464
+ * Always available. Used internally by password reset but exposed for
3465
+ * custom flows (email verification, invitation links, etc.).
3466
+ */
3467
+ oneTimeTokens: oneTimeTokenModule,
3468
+ /**
3469
+ * Session freshness enforcement for sensitive operations.
3470
+ *
3471
+ * Use as middleware before password changes, passkey registration,
3472
+ * billing updates, or any action that requires a recently-authenticated
3473
+ * session rather than an auto-refreshed one.
3474
+ *
3475
+ * @example
3476
+ * ```typescript
3477
+ * const stale = kavach.sessionFreshness.guard(session);
3478
+ * if (stale) return stale; // 403 SESSION_NOT_FRESH
3479
+ * ```
3480
+ */
3481
+ sessionFreshness: createSessionFreshnessModule(
3482
+ config.sessionFreshness
3483
+ ),
2970
3484
  /**
2971
3485
  * Phone number (SMS OTP) authentication.
2972
3486
  *
@@ -3003,6 +3517,27 @@ async function createKavach(config) {
3003
3517
  * ```
3004
3518
  */
3005
3519
  webhooks: webhookModule,
3520
+ /**
3521
+ * Redirect chain manager.
3522
+ *
3523
+ * Capture the user's original destination before auth redirects, push
3524
+ * intermediate steps (onboarding, email verification), and pop them
3525
+ * back in order. Cookie-based, works across page transitions and tabs.
3526
+ *
3527
+ * @example
3528
+ * ```typescript
3529
+ * // In auth middleware — save where the user was going
3530
+ * const setCookie = kavach.redirects.capture(request);
3531
+ * return new Response(null, { status: 302, headers: { Location: '/sign-in', 'Set-Cookie': setCookie } });
3532
+ *
3533
+ * // After sign-in — send user to their original destination
3534
+ * const { url, clearCookie } = kavach.redirects.pop(request);
3535
+ * const headers: Record<string, string> = { Location: url };
3536
+ * if (clearCookie) headers['Set-Cookie'] = clearCookie;
3537
+ * return new Response(null, { status: 302, headers });
3538
+ * ```
3539
+ */
3540
+ redirects: redirectChain,
3006
3541
  /**
3007
3542
  * Plugin system.
3008
3543
  *
@@ -3479,7 +4014,7 @@ function serializeCookieDeletion(name, options) {
3479
4014
  expires: /* @__PURE__ */ new Date(0)
3480
4015
  });
3481
4016
  }
3482
- function parseCookies(header) {
4017
+ function parseCookies2(header) {
3483
4018
  const result = {};
3484
4019
  if (!header || !header.trim()) return result;
3485
4020
  for (const pair of header.split(";")) {
@@ -3496,10 +4031,10 @@ function parseCookies(header) {
3496
4031
  return result;
3497
4032
  }
3498
4033
  function getCookie(header, name) {
3499
- return parseCookies(header)[name];
4034
+ return parseCookies2(header)[name];
3500
4035
  }
3501
4036
  function parseCookiesFromRequest(request) {
3502
- return parseCookies(request.headers.get("cookie") ?? "");
4037
+ return parseCookies2(request.headers.get("cookie") ?? "");
3503
4038
  }
3504
4039
  function capitalize(s) {
3505
4040
  return s.charAt(0).toUpperCase() + s.slice(1);
@@ -3793,15 +4328,15 @@ function buildSessionMetadata(request, extra) {
3793
4328
  }
3794
4329
 
3795
4330
  // src/webhooks/webhook.ts
3796
- function generateId() {
4331
+ function generateId2() {
3797
4332
  const bytes = new Uint8Array(16);
3798
4333
  crypto.getRandomValues(bytes);
3799
4334
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
3800
4335
  }
3801
4336
  async function signPayload2(secret, body) {
3802
- const encoder = new TextEncoder();
3803
- const keyData = encoder.encode(secret);
3804
- const messageData = encoder.encode(body);
4337
+ const encoder2 = new TextEncoder();
4338
+ const keyData = encoder2.encode(secret);
4339
+ const messageData = encoder2.encode(body);
3805
4340
  const key = await crypto.subtle.importKey(
3806
4341
  "raw",
3807
4342
  keyData,
@@ -3838,7 +4373,7 @@ async function deliverWebhook(url, event, payload, deliveryId, timestamp, signat
3838
4373
  }
3839
4374
  }
3840
4375
  async function dispatchWithRetry(url, event, payload, config) {
3841
- const deliveryId = generateId();
4376
+ const deliveryId = generateId2();
3842
4377
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3843
4378
  const body = JSON.stringify(payload);
3844
4379
  const signature = await signPayload2(config.secret, body);
@@ -3870,7 +4405,7 @@ function createWebhookModule2(config) {
3870
4405
  const subscriptions = /* @__PURE__ */ new Map();
3871
4406
  async function subscribe(url, events) {
3872
4407
  const sub = {
3873
- id: generateId(),
4408
+ id: generateId2(),
3874
4409
  url,
3875
4410
  events,
3876
4411
  active: true,
@@ -3898,7 +4433,7 @@ function createWebhookModule2(config) {
3898
4433
  if (!sub) {
3899
4434
  return { success: false, error: "Subscription not found" };
3900
4435
  }
3901
- const deliveryId = generateId();
4436
+ const deliveryId = generateId2();
3902
4437
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3903
4438
  const pingPayload = { event: "ping", subscriptionId, timestamp };
3904
4439
  const body = JSON.stringify(pingPayload);
@@ -3928,6 +4463,6 @@ async function verifyWebhookSignature(secret, rawBody, signature) {
3928
4463
  return diff === 0;
3929
4464
  }
3930
4465
 
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 };
4466
+ 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
4467
  //# sourceMappingURL=index.js.map
3933
4468
  //# sourceMappingURL=index.js.map