astro-sessionkit 0.1.16 → 0.1.18

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.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAW,cAAc,EAAC,MAAM,SAAS,CAAC;AAMpG,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,GAAG;QAC3C,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IACF,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7E,eAAe,CAAC,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;IACnD,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;CAClB;AAoBD,wBAAgB,SAAS,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAuG5D;AAKD,wBAAgB,SAAS,IAAI,cAAc,CAE1C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAW,cAAc,EAAC,MAAM,SAAS,CAAC;AAOpG,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,GAAG;QAC3C,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IACF,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7E,eAAe,CAAC,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;IACnD,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;CAClB;AAoBD,wBAAgB,SAAS,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAiG5D;AAKD,wBAAgB,SAAS,IAAI,cAAc,CAE1C"}
@@ -1,4 +1,5 @@
1
1
  import { isValidRedirectPath, isValidPattern } from './validation.js';
2
+ import { warn } from './logger.js';
2
3
 
3
4
  const DEFAULT_CONFIG = {
4
5
  loginPath: "/login",
@@ -46,21 +47,15 @@ function setConfig(userConfig) {
46
47
  const anyAccess = userConfig.access;
47
48
  if (anyAccess.globalProtect !== undefined && userConfig.globalProtect === undefined) {
48
49
  newConfig.globalProtect = anyAccess.globalProtect;
49
- if (process.env.NODE_ENV !== 'production') {
50
- console.warn('[SessionKit] Deprecation: globalProtect should be at the top level of configuration, not inside "access".');
51
- }
50
+ warn('Deprecation: globalProtect should be at the top level of configuration, not inside "access".');
52
51
  }
53
52
  if (anyAccess.exclude !== undefined && userConfig.exclude === undefined) {
54
53
  newConfig.exclude = anyAccess.exclude;
55
- if (process.env.NODE_ENV !== 'production') {
56
- console.warn('[SessionKit] Deprecation: exclude should be at the top level of configuration, not inside "access".');
57
- }
54
+ warn('Deprecation: exclude should be at the top level of configuration, not inside "access".');
58
55
  }
59
56
  if (anyAccess.debug !== undefined && userConfig.debug === undefined) {
60
57
  newConfig.debug = anyAccess.debug;
61
- if (process.env.NODE_ENV !== 'production') {
62
- console.warn('[SessionKit] Deprecation: debug should be at the top level of configuration, not inside "access".');
63
- }
58
+ warn('Deprecation: debug should be at the top level of configuration, not inside "access".');
64
59
  }
65
60
  }
66
61
  newConfig.runWithContext = userConfig.runWithContext;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sources":["../../src/core/config.ts"],"sourcesContent":["// ============================================================================\n// Configuration Store\n// ============================================================================\n\nimport type {SessionKitConfig, AccessHooks, ProtectionRule, Session, SessionContext} from \"./types\";\nimport {isValidPattern, isValidRedirectPath} from \"./validation\";\n\n/**\n * Internal config with defaults applied\n */\nexport interface ResolvedConfig {\n loginPath: string;\n protect: ProtectionRule[];\n access: Required<Omit<AccessHooks, \"check\">> & {\n check?: AccessHooks[\"check\"];\n };\n runWithContext?: <T>(context: SessionContext, fn: () => T) => T | Promise<T>;\n getContextStore?: () => SessionContext | undefined;\n setContextStore?: (context: SessionContext) => void;\n globalProtect: boolean;\n exclude: string[];\n debug: boolean;\n}\n\nconst DEFAULT_CONFIG: ResolvedConfig = {\n loginPath: \"/login\",\n protect: [],\n access: {\n getRole: (session: Session | null) => session?.role ?? null,\n getPermissions: (session: Session | null) => session?.permissions ?? [],\n check: undefined,\n },\n globalProtect: false,\n exclude: [],\n debug: false,\n};\n\nlet config: ResolvedConfig = { ...DEFAULT_CONFIG };\n\n/**\n * Set configuration (called by integration)\n */\nexport function setConfig(userConfig: SessionKitConfig): void {\n // Start with default config\n const newConfig: ResolvedConfig = { ...DEFAULT_CONFIG };\n\n // Validate and set loginPath\n if (userConfig.loginPath !== undefined) {\n if (!isValidRedirectPath(userConfig.loginPath)) {\n throw new Error(\n `[SessionKit] Invalid loginPath: \"${userConfig.loginPath}\". Must start with / and be less than 500 characters.`\n );\n }\n newConfig.loginPath = userConfig.loginPath;\n }\n\n // Validate protection rules\n if (userConfig.protect) {\n for (const rule of userConfig.protect) {\n // Validate pattern\n if (!isValidPattern(rule.pattern)) {\n throw new Error(\n `[SessionKit] Invalid pattern: \"${rule.pattern}\". ` +\n `Patterns must start with / and be less than 1000 characters.`\n );\n }\n\n // Validate redirectTo if present\n if (rule.redirectTo && !isValidRedirectPath(rule.redirectTo)) {\n throw new Error(\n `[SessionKit] Invalid redirectTo: \"${rule.redirectTo}\". ` +\n `Must start with / and be less than 500 characters.`\n );\n }\n }\n newConfig.protect = [...userConfig.protect];\n }\n\n // Validate context store getter/setter pair\n if ((userConfig.getContextStore && !userConfig.setContextStore) || (!userConfig.getContextStore && userConfig.setContextStore)) {\n throw new Error(\n '[SessionKit] Both getContextStore and setContextStore must be provided together if using custom context storage.'\n );\n }\n\n // Set access hooks\n if (userConfig.access) {\n newConfig.access = {\n getRole: userConfig.access.getRole ?? DEFAULT_CONFIG.access.getRole,\n getPermissions: userConfig.access.getPermissions ?? DEFAULT_CONFIG.access.getPermissions,\n check: userConfig.access.check,\n };\n\n // Migration/Safety: If user misplaced globalProtect/exclude/debug in access object,\n // we honor them but warn about it.\n const anyAccess = userConfig.access as any;\n if (anyAccess.globalProtect !== undefined && userConfig.globalProtect === undefined) {\n newConfig.globalProtect = anyAccess.globalProtect;\n if (process.env.NODE_ENV !== 'production') {\n console.warn('[SessionKit] Deprecation: globalProtect should be at the top level of configuration, not inside \"access\".');\n }\n }\n if (anyAccess.exclude !== undefined && userConfig.exclude === undefined) {\n newConfig.exclude = anyAccess.exclude;\n if (process.env.NODE_ENV !== 'production') {\n console.warn('[SessionKit] Deprecation: exclude should be at the top level of configuration, not inside \"access\".');\n }\n }\n if (anyAccess.debug !== undefined && userConfig.debug === undefined) {\n newConfig.debug = anyAccess.debug;\n if (process.env.NODE_ENV !== 'production') {\n console.warn('[SessionKit] Deprecation: debug should be at the top level of configuration, not inside \"access\".');\n }\n }\n }\n\n // Set context hooks\n newConfig.runWithContext = userConfig.runWithContext;\n newConfig.getContextStore = userConfig.getContextStore;\n newConfig.setContextStore = userConfig.setContextStore;\n \n if (userConfig.globalProtect !== undefined) {\n newConfig.globalProtect = userConfig.globalProtect;\n }\n\n if (userConfig.exclude !== undefined) {\n for (const pattern of userConfig.exclude) {\n if (!isValidPattern(pattern)) {\n throw new Error(\n `[SessionKit] Invalid exclude pattern: \"${pattern}\". ` +\n `Patterns must start with / and be less than 1000 characters.`\n );\n }\n }\n newConfig.exclude = [...userConfig.exclude];\n } else if (newConfig.exclude.length === 0) {\n newConfig.exclude = [...DEFAULT_CONFIG.exclude];\n }\n\n if (userConfig.debug !== undefined) {\n newConfig.debug = userConfig.debug;\n }\n\n // Atomic update\n config = Object.freeze(newConfig);\n}\n\n/**\n * Get current configuration\n */\nexport function getConfig(): ResolvedConfig {\n return config;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sources":["../../src/core/config.ts"],"sourcesContent":["// ============================================================================\n// Configuration Store\n// ============================================================================\n\nimport type {SessionKitConfig, AccessHooks, ProtectionRule, Session, SessionContext} from \"./types\";\nimport {isValidPattern, isValidRedirectPath} from \"./validation\";\nimport * as logger from \"./logger\";\n\n/**\n * Internal config with defaults applied\n */\nexport interface ResolvedConfig {\n loginPath: string;\n protect: ProtectionRule[];\n access: Required<Omit<AccessHooks, \"check\">> & {\n check?: AccessHooks[\"check\"];\n };\n runWithContext?: <T>(context: SessionContext, fn: () => T) => T | Promise<T>;\n getContextStore?: () => SessionContext | undefined;\n setContextStore?: (context: SessionContext) => void;\n globalProtect: boolean;\n exclude: string[];\n debug: boolean;\n}\n\nconst DEFAULT_CONFIG: ResolvedConfig = {\n loginPath: \"/login\",\n protect: [],\n access: {\n getRole: (session: Session | null) => session?.role ?? null,\n getPermissions: (session: Session | null) => session?.permissions ?? [],\n check: undefined,\n },\n globalProtect: false,\n exclude: [],\n debug: false,\n};\n\nlet config: ResolvedConfig = { ...DEFAULT_CONFIG };\n\n/**\n * Set configuration (called by integration)\n */\nexport function setConfig(userConfig: SessionKitConfig): void {\n // Start with default config\n const newConfig: ResolvedConfig = { ...DEFAULT_CONFIG };\n\n // Validate and set loginPath\n if (userConfig.loginPath !== undefined) {\n if (!isValidRedirectPath(userConfig.loginPath)) {\n throw new Error(\n `[SessionKit] Invalid loginPath: \"${userConfig.loginPath}\". Must start with / and be less than 500 characters.`\n );\n }\n newConfig.loginPath = userConfig.loginPath;\n }\n\n // Validate protection rules\n if (userConfig.protect) {\n for (const rule of userConfig.protect) {\n // Validate pattern\n if (!isValidPattern(rule.pattern)) {\n throw new Error(\n `[SessionKit] Invalid pattern: \"${rule.pattern}\". ` +\n `Patterns must start with / and be less than 1000 characters.`\n );\n }\n\n // Validate redirectTo if present\n if (rule.redirectTo && !isValidRedirectPath(rule.redirectTo)) {\n throw new Error(\n `[SessionKit] Invalid redirectTo: \"${rule.redirectTo}\". ` +\n `Must start with / and be less than 500 characters.`\n );\n }\n }\n newConfig.protect = [...userConfig.protect];\n }\n\n // Validate context store getter/setter pair\n if ((userConfig.getContextStore && !userConfig.setContextStore) || (!userConfig.getContextStore && userConfig.setContextStore)) {\n throw new Error(\n '[SessionKit] Both getContextStore and setContextStore must be provided together if using custom context storage.'\n );\n }\n\n // Set access hooks\n if (userConfig.access) {\n newConfig.access = {\n getRole: userConfig.access.getRole ?? DEFAULT_CONFIG.access.getRole,\n getPermissions: userConfig.access.getPermissions ?? DEFAULT_CONFIG.access.getPermissions,\n check: userConfig.access.check,\n };\n\n // Migration/Safety: If user misplaced globalProtect/exclude/debug in access object,\n // we honor them but warn about it.\n const anyAccess = userConfig.access as any;\n if (anyAccess.globalProtect !== undefined && userConfig.globalProtect === undefined) {\n newConfig.globalProtect = anyAccess.globalProtect;\n logger.warn('Deprecation: globalProtect should be at the top level of configuration, not inside \"access\".');\n }\n if (anyAccess.exclude !== undefined && userConfig.exclude === undefined) {\n newConfig.exclude = anyAccess.exclude;\n logger.warn('Deprecation: exclude should be at the top level of configuration, not inside \"access\".');\n }\n if (anyAccess.debug !== undefined && userConfig.debug === undefined) {\n newConfig.debug = anyAccess.debug;\n logger.warn('Deprecation: debug should be at the top level of configuration, not inside \"access\".');\n }\n }\n\n // Set context hooks\n newConfig.runWithContext = userConfig.runWithContext;\n newConfig.getContextStore = userConfig.getContextStore;\n newConfig.setContextStore = userConfig.setContextStore;\n \n if (userConfig.globalProtect !== undefined) {\n newConfig.globalProtect = userConfig.globalProtect;\n }\n\n if (userConfig.exclude !== undefined) {\n for (const pattern of userConfig.exclude) {\n if (!isValidPattern(pattern)) {\n throw new Error(\n `[SessionKit] Invalid exclude pattern: \"${pattern}\". ` +\n `Patterns must start with / and be less than 1000 characters.`\n );\n }\n }\n newConfig.exclude = [...userConfig.exclude];\n } else if (newConfig.exclude.length === 0) {\n newConfig.exclude = [...DEFAULT_CONFIG.exclude];\n }\n\n if (userConfig.debug !== undefined) {\n newConfig.debug = userConfig.debug;\n }\n\n // Atomic update\n config = Object.freeze(newConfig);\n}\n\n/**\n * Get current configuration\n */\nexport function getConfig(): ResolvedConfig {\n return config;\n}\n"],"names":["logger.warn"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"guardMiddleware.d.ts","sourceRoot":"","sources":["../../src/core/guardMiddleware.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,iBAAiB,EAAC,MAAM,OAAO,CAAC;AAyEzD,wBAAgB,qBAAqB,IAAI,iBAAiB,CAqDzD"}
1
+ {"version":3,"file":"guardMiddleware.d.ts","sourceRoot":"","sources":["../../src/core/guardMiddleware.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,iBAAiB,EAAC,MAAM,OAAO,CAAC;AAsEzD,wBAAgB,qBAAqB,IAAI,iBAAiB,CA8DzD"}
@@ -2,6 +2,7 @@ import { getContextStore } from './context.js';
2
2
  import { getConfig } from './config.js';
3
3
  import { matchesPattern } from './matcher.js';
4
4
  import { isValidSessionStructure } from './validation.js';
5
+ import { debug, error } from './logger.js';
5
6
 
6
7
  async function checkRule(rule, session) {
7
8
  const { access } = getConfig();
@@ -9,10 +10,8 @@ async function checkRule(rule, session) {
9
10
  try {
10
11
  return await access.check(rule, session);
11
12
  }
12
- catch (error) {
13
- if (process.env.NODE_ENV !== 'production') {
14
- console.error('[SessionKit] Error in custom access check hook:', error);
15
- }
13
+ catch (error$1) {
14
+ error('Error in custom access check hook:', error$1);
16
15
  return false;
17
16
  }
18
17
  }
@@ -20,10 +19,8 @@ async function checkRule(rule, session) {
20
19
  try {
21
20
  return await rule.allow(session);
22
21
  }
23
- catch (error) {
24
- if (process.env.NODE_ENV !== 'production') {
25
- console.error('[SessionKit] Error in custom rule allow function:', error);
26
- }
22
+ catch (error$1) {
23
+ error('Error in custom rule allow function:', error$1);
27
24
  return false;
28
25
  }
29
26
  }
@@ -64,25 +61,32 @@ function createGuardMiddleware() {
64
61
  const sessionContext = getContextStore();
65
62
  const session = sessionContext?.session ?? null;
66
63
  const rule = protect.find((r) => matchesPattern(r.pattern, pathname));
64
+ debug(`[Guard] Pathname: ${pathname}, Found rule: ${rule ? JSON.stringify(rule) : 'none'}, GlobalProtect: ${globalProtect}`);
67
65
  if (!rule) {
68
66
  if (globalProtect) {
69
67
  if (exclude.some((pattern) => matchesPattern(pattern, pathname))) {
68
+ debug(`[GlobalProtect] Skipping ${pathname} because it matches an exclude pattern`);
70
69
  return next();
71
70
  }
72
71
  if (pathname === loginPath) {
72
+ debug(`[GlobalProtect] Skipping ${pathname} because it is the loginPath`);
73
73
  return next();
74
74
  }
75
75
  if (!session || !isValidSessionStructure(session)) {
76
+ debug(`[GlobalProtect] Redirecting to ${loginPath} because session is ${session ? 'invalid' : 'missing'}`);
76
77
  return context.redirect(loginPath);
77
78
  }
78
79
  }
80
+ debug(`[GlobalProtect] Allowing ${pathname} because session is valid or globalProtect is false`);
79
81
  return next();
80
82
  }
81
83
  const allowed = await checkRule(rule, session);
82
84
  if (!allowed) {
83
85
  const redirectTo = rule.redirectTo ?? loginPath;
86
+ debug(`[Guard] Redirecting to ${redirectTo} because access was denied by rule:`, rule);
84
87
  return context.redirect(redirectTo);
85
88
  }
89
+ debug(`[Guard] Allowing ${pathname} because access was granted by rule:`, rule);
86
90
  return next();
87
91
  };
88
92
  }
@@ -1 +1 @@
1
- {"version":3,"file":"guardMiddleware.js","sources":["../../src/core/guardMiddleware.ts"],"sourcesContent":["// ============================================================================\n// Route Guard Middleware - Enforces protection rules\n// ============================================================================\n\nimport type {APIContext, MiddlewareHandler} from \"astro\";\nimport { getContextStore } from \"./context\";\nimport { getConfig } from \"./config\";\nimport { matchesPattern } from \"./matcher\";\nimport type { ProtectionRule, Session } from \"./types\";\nimport { isValidSessionStructure } from \"./validation\";\n\n/**\n * Check if session satisfies a protection rule\n */\nasync function checkRule(rule: ProtectionRule, session: Session | null): Promise<boolean> {\n const { access } = getConfig();\n\n // Custom check overrides everything\n if (access.check) {\n try {\n return await access.check(rule, session);\n } catch (error) {\n if (process.env.NODE_ENV !== 'production') {\n console.error('[SessionKit] Error in custom access check hook:', error);\n }\n return false;\n }\n }\n\n // Custom allow function\n if (\"allow\" in rule) {\n try {\n return await rule.allow(session);\n } catch (error) {\n if (process.env.NODE_ENV !== 'production') {\n console.error('[SessionKit] Error in custom rule allow function:', error);\n }\n return false;\n }\n }\n\n // Must be authenticated and have a valid session structure for all other checks\n if (!session || !isValidSessionStructure(session)) {\n return false;\n }\n\n // Single role check\n if (\"role\" in rule) {\n const userRole = access.getRole(session);\n return userRole === rule.role;\n }\n\n // Multiple roles check (user must have ONE of these)\n if (\"roles\" in rule) {\n const userRole = access.getRole(session);\n return userRole !== null && rule.roles.includes(userRole);\n }\n\n // Single permission check\n if (\"permission\" in rule) {\n const userPermissions = access.getPermissions(session);\n return userPermissions.includes(rule.permission);\n }\n\n // Multiple permissions check (user must have ALL of these)\n if (\"permissions\" in rule) {\n const userPermissions = access.getPermissions(session);\n return rule.permissions.every((p) => userPermissions.includes(p));\n }\n\n // No specific rule matched - allow by default\n return true;\n}\n\n/**\n * Create route guard middleware\n */\nexport function createGuardMiddleware(): MiddlewareHandler {\n return async (context : APIContext, next) => {\n const { protect, loginPath, globalProtect, exclude } = getConfig();\n \n // No rules configured and no global protect - skip\n if (protect.length === 0 && !globalProtect) {\n return next();\n }\n\n let pathname: string;\n try {\n pathname = new URL(context.request.url).pathname;\n } catch {\n // Fallback if URL is invalid (unlikely in Astro)\n pathname = \"/\";\n }\n const sessionContext = getContextStore();\n const session = sessionContext?.session ?? null;\n\n // Find matching rule\n const rule = protect.find((r) => matchesPattern(r.pattern, pathname));\n \n // No matching rule - check global protection\n if (!rule) {\n if (globalProtect) {\n // Skip if path is in exclude list\n if (exclude.some((pattern) => matchesPattern(pattern, pathname))) {\n return next();\n }\n \n // Skip if it's the login page itself (to avoid redirect loops)\n if (pathname === loginPath) {\n return next();\n }\n\n // Require valid session\n if (!session || !isValidSessionStructure(session)) {\n return context.redirect(loginPath);\n }\n }\n return next();\n }\n\n // Check if access is allowed\n const allowed = await checkRule(rule, session);\n\n if (!allowed) {\n const redirectTo = rule.redirectTo ?? loginPath;\n return context.redirect(redirectTo);\n }\n\n return next();\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guardMiddleware.js","sources":["../../src/core/guardMiddleware.ts"],"sourcesContent":["// ============================================================================\n// Route Guard Middleware - Enforces protection rules\n// ============================================================================\n\nimport type {APIContext, MiddlewareHandler} from \"astro\";\nimport { getContextStore } from \"./context\";\nimport { getConfig } from \"./config\";\nimport { matchesPattern } from \"./matcher\";\nimport type { ProtectionRule, Session } from \"./types\";\nimport { isValidSessionStructure } from \"./validation\";\nimport * as logger from \"./logger\";\n\n/**\n * Check if session satisfies a protection rule\n */\nasync function checkRule(rule: ProtectionRule, session: Session | null): Promise<boolean> {\n const { access } = getConfig();\n\n // Custom check overrides everything\n if (access.check) {\n try {\n return await access.check(rule, session);\n } catch (error) {\n logger.error('Error in custom access check hook:', error);\n return false;\n }\n }\n\n // Custom allow function\n if (\"allow\" in rule) {\n try {\n return await rule.allow(session);\n } catch (error) {\n logger.error('Error in custom rule allow function:', error);\n return false;\n }\n }\n\n // Must be authenticated and have a valid session structure for all other checks\n if (!session || !isValidSessionStructure(session)) {\n return false;\n }\n\n // Single role check\n if (\"role\" in rule) {\n const userRole = access.getRole(session);\n return userRole === rule.role;\n }\n\n // Multiple roles check (user must have ONE of these)\n if (\"roles\" in rule) {\n const userRole = access.getRole(session);\n return userRole !== null && rule.roles.includes(userRole);\n }\n\n // Single permission check\n if (\"permission\" in rule) {\n const userPermissions = access.getPermissions(session);\n return userPermissions.includes(rule.permission);\n }\n\n // Multiple permissions check (user must have ALL of these)\n if (\"permissions\" in rule) {\n const userPermissions = access.getPermissions(session);\n return rule.permissions.every((p) => userPermissions.includes(p));\n }\n\n // No specific rule matched - allow by default\n return true;\n}\n\n/**\n * Create route guard middleware\n */\nexport function createGuardMiddleware(): MiddlewareHandler {\n return async (context : APIContext, next) => {\n const { protect, loginPath, globalProtect, exclude } = getConfig();\n \n // No rules configured and no global protect - skip\n if (protect.length === 0 && !globalProtect) {\n return next();\n }\n\n let pathname: string;\n try {\n pathname = new URL(context.request.url).pathname;\n } catch {\n // Fallback if URL is invalid (unlikely in Astro)\n pathname = \"/\";\n }\n const sessionContext = getContextStore();\n const session = sessionContext?.session ?? null;\n\n // Find matching rule\n const rule = protect.find((r) => matchesPattern(r.pattern, pathname));\n \n logger.debug(`[Guard] Pathname: ${pathname}, Found rule: ${rule ? JSON.stringify(rule) : 'none'}, GlobalProtect: ${globalProtect}`);\n\n // No matching rule - check global protection\n if (!rule) {\n if (globalProtect) {\n // Skip if path is in exclude list\n if (exclude.some((pattern) => matchesPattern(pattern, pathname))) {\n logger.debug(`[GlobalProtect] Skipping ${pathname} because it matches an exclude pattern`);\n return next();\n }\n \n // Skip if it's the login page itself (to avoid redirect loops)\n if (pathname === loginPath) {\n logger.debug(`[GlobalProtect] Skipping ${pathname} because it is the loginPath`);\n return next();\n }\n\n // Require valid session\n if (!session || !isValidSessionStructure(session)) {\n logger.debug(`[GlobalProtect] Redirecting to ${loginPath} because session is ${session ? 'invalid' : 'missing'}`);\n return context.redirect(loginPath);\n }\n }\n \n logger.debug(`[GlobalProtect] Allowing ${pathname} because session is valid or globalProtect is false`);\n return next();\n }\n\n // Check if access is allowed\n const allowed = await checkRule(rule, session);\n\n if (!allowed) {\n const redirectTo = rule.redirectTo ?? loginPath;\n logger.debug(`[Guard] Redirecting to ${redirectTo} because access was denied by rule:`, rule);\n return context.redirect(redirectTo);\n }\n\n logger.debug(`[Guard] Allowing ${pathname} because access was granted by rule:`, rule);\n return next();\n };\n}\n"],"names":["error","logger.error","logger.debug"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export declare function debug(message: string, ...args: any[]): void;
2
2
  export declare function error(message: string, ...args: any[]): void;
3
3
  export declare function warn(message: string, ...args: any[]): void;
4
+ export declare function info(message: string, ...args: any[]): void;
4
5
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAKA,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAK3D;AAKD,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAK3D;AAKD,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAK1D"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAKA,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAK3D;AAKD,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAK3D;AAKD,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAK1D;AAKD,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAK1D"}
@@ -1,5 +1,17 @@
1
1
  import { getConfig } from './config.js';
2
2
 
3
+ function debug(message, ...args) {
4
+ const { debug } = getConfig();
5
+ if (debug) {
6
+ console.debug(`[SessionKit] ${message}`, ...args);
7
+ }
8
+ }
9
+ function error(message, ...args) {
10
+ const { debug } = getConfig();
11
+ if (debug || process.env.NODE_ENV !== 'production') {
12
+ console.error(`[SessionKit] ${message}`, ...args);
13
+ }
14
+ }
3
15
  function warn(message, ...args) {
4
16
  const { debug } = getConfig();
5
17
  if (debug || process.env.NODE_ENV !== 'production') {
@@ -7,5 +19,5 @@ function warn(message, ...args) {
7
19
  }
8
20
  }
9
21
 
10
- export { warn };
22
+ export { debug, error, warn };
11
23
  //# sourceMappingURL=logger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sources":["../../src/core/logger.ts"],"sourcesContent":["import { getConfig } from \"./config\";\n\n/**\n * Log message if debug mode is enabled\n */\nexport function debug(message: string, ...args: any[]): void {\n const { debug } = getConfig();\n if (debug) {\n console.debug(`[SessionKit] ${message}`, ...args);\n }\n}\n\n/**\n * Log error message. Always logs unless in production, but can be forced via debug flag.\n */\nexport function error(message: string, ...args: any[]): void {\n const { debug } = getConfig();\n if (debug || process.env.NODE_ENV !== 'production') {\n console.error(`[SessionKit] ${message}`, ...args);\n }\n}\n\n/**\n * Log warning message. Always logs unless in production, but can be forced via debug flag.\n */\nexport function warn(message: string, ...args: any[]): void {\n const { debug } = getConfig();\n if (debug || process.env.NODE_ENV !== 'production') {\n console.warn(`[SessionKit] ${message}`, ...args);\n }\n}\n"],"names":[],"mappings":";;SAyBgB,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW,EAAA;AAClD,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE;IAC7B,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QAClD,OAAO,CAAC,IAAI,CAAC,CAAA,aAAA,EAAgB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC;IAClD;AACF;;;;"}
1
+ {"version":3,"file":"logger.js","sources":["../../src/core/logger.ts"],"sourcesContent":["import { getConfig } from \"./config\";\n\n/**\n * Log message if debug mode is enabled\n */\nexport function debug(message: string, ...args: any[]): void {\n const { debug } = getConfig();\n if (debug) {\n console.debug(`[SessionKit] ${message}`, ...args);\n }\n}\n\n/**\n * Log error message. Always logs unless in production, but can be forced via debug flag.\n */\nexport function error(message: string, ...args: any[]): void {\n const { debug } = getConfig();\n if (debug || process.env.NODE_ENV !== 'production') {\n console.error(`[SessionKit] ${message}`, ...args);\n }\n}\n\n/**\n * Log warning message. Always logs unless in production, but can be forced via debug flag.\n */\nexport function warn(message: string, ...args: any[]): void {\n const { debug } = getConfig();\n if (debug || process.env.NODE_ENV !== 'production') {\n console.warn(`[SessionKit] ${message}`, ...args);\n }\n}\n\n/**\n * Log info message. Always logs unless in production, but can be forced via debug flag.\n */\nexport function info(message: string, ...args: any[]): void {\n const { debug } = getConfig();\n if (debug || process.env.NODE_ENV !== 'production') {\n console.log(`[SessionKit] ${message}`, ...args);\n }\n}\n"],"names":[],"mappings":";;SAKgB,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW,EAAA;AACnD,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE;IAC7B,IAAI,KAAK,EAAE;QACT,OAAO,CAAC,KAAK,CAAC,CAAA,aAAA,EAAgB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC;IACnD;AACF;SAKgB,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW,EAAA;AACnD,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE;IAC7B,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QAClD,OAAO,CAAC,KAAK,CAAC,CAAA,aAAA,EAAgB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC;IACnD;AACF;SAKgB,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW,EAAA;AAClD,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE;IAC7B,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QAClD,OAAO,CAAC,IAAI,CAAC,CAAA,aAAA,EAAgB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC;IAClD;AACF;;;;"}
@@ -1,7 +1,7 @@
1
1
  import { runWithContext } from './context.js';
2
2
  import { isValidSessionStructure } from './validation.js';
3
3
  import { getConfig } from './config.js';
4
- import { warn } from './logger.js';
4
+ import { warn, error } from './logger.js';
5
5
 
6
6
  const SESSION_KEY = "__session__";
7
7
  const sessionMiddleware = async (context, next) => {
@@ -27,8 +27,8 @@ const sessionMiddleware = async (context, next) => {
27
27
  else if (config.setContextStore) {
28
28
  config.setContextStore({ session });
29
29
  }
30
- else if (process.env.NODE_ENV !== 'production') {
31
- console.error('[SessionKit] getContextStore returned undefined, cannot set session');
30
+ else {
31
+ error('getContextStore returned undefined, cannot set session');
32
32
  }
33
33
  return next();
34
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sessionMiddleware.js","sources":["../../src/core/sessionMiddleware.ts"],"sourcesContent":["// ============================================================================\n// Session Middleware - Loads session into AsyncLocalStorage\n// ============================================================================\n\nimport type {MiddlewareHandler} from \"astro\";\nimport {runWithContext as defaultRunWithContext} from \"./context\";\nimport {isValidSessionStructure} from \"./validation\";\nimport type {Session} from \"./types\";\nimport {getConfig} from \"./config\";\nimport {warn} from \"./logger\";\n\n/**\n * Session key used to store session in context.session\n */\nconst SESSION_KEY = \"__session__\";\n\n/**\n * Main session middleware\n *\n * Reads session from context.session.get('__session__') and makes it available\n * throughout the request via AsyncLocalStorage\n */\nexport const sessionMiddleware: MiddlewareHandler = async (context, next) => {\n // Get session from context.session store\n const rawSession = context.session?.get<Session>(SESSION_KEY) ?? null;\n\n // Validate session structure if present\n let session: Session | null = null;\n\n if (rawSession) {\n if (isValidSessionStructure(rawSession)) {\n session = rawSession;\n } else {\n // Invalid session structure - log warning and treat as unauthenticated\n warn(\n 'Invalid session structure detected. Session will be ignored. ' +\n 'Ensure context.session.set(\"__session__\", ...) has the correct structure. ' +\n 'Received: ' + JSON.stringify(rawSession)\n );\n session = null;\n }\n }\n\n // Run the rest of the request chain with session context\n const config = getConfig();\n\n // If getContextStore is provided, but runWithContext is NOT,\n // we assume the user is managing the context at a superior level\n // and we should NOT wrap the call in our default runner.\n if (config.getContextStore && !config.runWithContext) {\n // Initialize context store if setter is provided\n const store = config.getContextStore();\n if (store) {\n store.session = session;\n } else if (config.setContextStore) {\n config.setContextStore({session});\n } else if (process.env.NODE_ENV !== 'production') {\n console.error('[SessionKit] getContextStore returned undefined, cannot set session');\n }\n return next();\n }\n\n const runner = config.runWithContext ?? defaultRunWithContext;\n return runner({session}, () => next());\n};"],"names":["defaultRunWithContext"],"mappings":";;;;;AAcA,MAAM,WAAW,GAAG,aAAa;AAQ1B,MAAM,iBAAiB,GAAsB,OAAO,OAAO,EAAE,IAAI,KAAI;AAExE,IAAA,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAU,WAAW,CAAC,IAAI,IAAI;IAGrE,IAAI,OAAO,GAAmB,IAAI;IAElC,IAAI,UAAU,EAAE;AACZ,QAAA,IAAI,uBAAuB,CAAC,UAAU,CAAC,EAAE;YACrC,OAAO,GAAG,UAAU;QACxB;aAAO;AAEH,YAAA,IAAI,CACA,+DAA+D;gBAC/D,4EAA4E;gBAC5E,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAC5C;YACD,OAAO,GAAG,IAAI;QAClB;IACJ;AAGA,IAAA,MAAM,MAAM,GAAG,SAAS,EAAE;IAK1B,IAAI,MAAM,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;AAElD,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,EAAE;QACtC,IAAI,KAAK,EAAE;AACP,YAAA,KAAK,CAAC,OAAO,GAAG,OAAO;QAC3B;AAAO,aAAA,IAAI,MAAM,CAAC,eAAe,EAAE;AAC/B,YAAA,MAAM,CAAC,eAAe,CAAC,EAAC,OAAO,EAAC,CAAC;QACrC;aAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;AAC9C,YAAA,OAAO,CAAC,KAAK,CAAC,qEAAqE,CAAC;QACxF;QACA,OAAO,IAAI,EAAE;IACjB;AAEA,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,IAAIA,cAAqB;AAC7D,IAAA,OAAO,MAAM,CAAC,EAAC,OAAO,EAAC,EAAE,MAAM,IAAI,EAAE,CAAC;AAC1C;;;;"}
1
+ {"version":3,"file":"sessionMiddleware.js","sources":["../../src/core/sessionMiddleware.ts"],"sourcesContent":["// ============================================================================\n// Session Middleware - Loads session into AsyncLocalStorage\n// ============================================================================\n\nimport type {MiddlewareHandler} from \"astro\";\nimport {runWithContext as defaultRunWithContext} from \"./context\";\nimport {isValidSessionStructure} from \"./validation\";\nimport type {Session} from \"./types\";\nimport {getConfig} from \"./config\";\nimport * as logger from \"./logger\";\n\n/**\n * Session key used to store session in context.session\n */\nconst SESSION_KEY = \"__session__\";\n\n/**\n * Main session middleware\n *\n * Reads session from context.session.get('__session__') and makes it available\n * throughout the request via AsyncLocalStorage\n */\nexport const sessionMiddleware: MiddlewareHandler = async (context, next) => {\n // Get session from context.session store\n const rawSession = context.session?.get<Session>(SESSION_KEY) ?? null;\n\n // Validate session structure if present\n let session: Session | null = null;\n\n if (rawSession) {\n if (isValidSessionStructure(rawSession)) {\n session = rawSession;\n } else {\n // Invalid session structure - log warning and treat as unauthenticated\n logger.warn(\n 'Invalid session structure detected. Session will be ignored. ' +\n 'Ensure context.session.set(\"__session__\", ...) has the correct structure. ' +\n 'Received: ' + JSON.stringify(rawSession)\n );\n session = null;\n }\n }\n\n // Run the rest of the request chain with session context\n const config = getConfig();\n\n // If getContextStore is provided, but runWithContext is NOT,\n // we assume the user is managing the context at a superior level\n // and we should NOT wrap the call in our default runner.\n if (config.getContextStore && !config.runWithContext) {\n // Initialize context store if setter is provided\n const store = config.getContextStore();\n if (store) {\n store.session = session;\n } else if (config.setContextStore) {\n config.setContextStore({session});\n } else {\n logger.error('getContextStore returned undefined, cannot set session');\n }\n return next();\n }\n\n const runner = config.runWithContext ?? defaultRunWithContext;\n return runner({session}, () => next());\n};"],"names":["logger.warn","logger.error","defaultRunWithContext"],"mappings":";;;;;AAcA,MAAM,WAAW,GAAG,aAAa;AAQ1B,MAAM,iBAAiB,GAAsB,OAAO,OAAO,EAAE,IAAI,KAAI;AAExE,IAAA,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAU,WAAW,CAAC,IAAI,IAAI;IAGrE,IAAI,OAAO,GAAmB,IAAI;IAElC,IAAI,UAAU,EAAE;AACZ,QAAA,IAAI,uBAAuB,CAAC,UAAU,CAAC,EAAE;YACrC,OAAO,GAAG,UAAU;QACxB;aAAO;YAEHA,IAAW,CACP,+DAA+D;gBAC/D,4EAA4E;gBAC5E,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAC5C;YACD,OAAO,GAAG,IAAI;QAClB;IACJ;AAGA,IAAA,MAAM,MAAM,GAAG,SAAS,EAAE;IAK1B,IAAI,MAAM,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;AAElD,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,EAAE;QACtC,IAAI,KAAK,EAAE;AACP,YAAA,KAAK,CAAC,OAAO,GAAG,OAAO;QAC3B;AAAO,aAAA,IAAI,MAAM,CAAC,eAAe,EAAE;AAC/B,YAAA,MAAM,CAAC,eAAe,CAAC,EAAC,OAAO,EAAC,CAAC;QACrC;aAAO;AACH,YAAAC,KAAY,CAAC,wDAAwD,CAAC;QAC1E;QACA,OAAO,IAAI,EAAE;IACjB;AAEA,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,IAAIC,cAAqB;AAC7D,IAAA,OAAO,MAAM,CAAC,EAAC,OAAO,EAAC,EAAE,MAAM,IAAI,EAAE,CAAC;AAC1C;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-sessionkit",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Simple session access and route protection for Astro applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type {SessionKitConfig, AccessHooks, ProtectionRule, Session, SessionContext} from "./types";
6
6
  import {isValidPattern, isValidRedirectPath} from "./validation";
7
+ import * as logger from "./logger";
7
8
 
8
9
  /**
9
10
  * Internal config with defaults applied
@@ -96,21 +97,15 @@ export function setConfig(userConfig: SessionKitConfig): void {
96
97
  const anyAccess = userConfig.access as any;
97
98
  if (anyAccess.globalProtect !== undefined && userConfig.globalProtect === undefined) {
98
99
  newConfig.globalProtect = anyAccess.globalProtect;
99
- if (process.env.NODE_ENV !== 'production') {
100
- console.warn('[SessionKit] Deprecation: globalProtect should be at the top level of configuration, not inside "access".');
101
- }
100
+ logger.warn('Deprecation: globalProtect should be at the top level of configuration, not inside "access".');
102
101
  }
103
102
  if (anyAccess.exclude !== undefined && userConfig.exclude === undefined) {
104
103
  newConfig.exclude = anyAccess.exclude;
105
- if (process.env.NODE_ENV !== 'production') {
106
- console.warn('[SessionKit] Deprecation: exclude should be at the top level of configuration, not inside "access".');
107
- }
104
+ logger.warn('Deprecation: exclude should be at the top level of configuration, not inside "access".');
108
105
  }
109
106
  if (anyAccess.debug !== undefined && userConfig.debug === undefined) {
110
107
  newConfig.debug = anyAccess.debug;
111
- if (process.env.NODE_ENV !== 'production') {
112
- console.warn('[SessionKit] Deprecation: debug should be at the top level of configuration, not inside "access".');
113
- }
108
+ logger.warn('Deprecation: debug should be at the top level of configuration, not inside "access".');
114
109
  }
115
110
  }
116
111
 
@@ -8,6 +8,7 @@ import { getConfig } from "./config";
8
8
  import { matchesPattern } from "./matcher";
9
9
  import type { ProtectionRule, Session } from "./types";
10
10
  import { isValidSessionStructure } from "./validation";
11
+ import * as logger from "./logger";
11
12
 
12
13
  /**
13
14
  * Check if session satisfies a protection rule
@@ -20,9 +21,7 @@ async function checkRule(rule: ProtectionRule, session: Session | null): Promise
20
21
  try {
21
22
  return await access.check(rule, session);
22
23
  } catch (error) {
23
- if (process.env.NODE_ENV !== 'production') {
24
- console.error('[SessionKit] Error in custom access check hook:', error);
25
- }
24
+ logger.error('Error in custom access check hook:', error);
26
25
  return false;
27
26
  }
28
27
  }
@@ -32,9 +31,7 @@ async function checkRule(rule: ProtectionRule, session: Session | null): Promise
32
31
  try {
33
32
  return await rule.allow(session);
34
33
  } catch (error) {
35
- if (process.env.NODE_ENV !== 'production') {
36
- console.error('[SessionKit] Error in custom rule allow function:', error);
37
- }
34
+ logger.error('Error in custom rule allow function:', error);
38
35
  return false;
39
36
  }
40
37
  }
@@ -97,24 +94,31 @@ export function createGuardMiddleware(): MiddlewareHandler {
97
94
  // Find matching rule
98
95
  const rule = protect.find((r) => matchesPattern(r.pattern, pathname));
99
96
 
97
+ logger.debug(`[Guard] Pathname: ${pathname}, Found rule: ${rule ? JSON.stringify(rule) : 'none'}, GlobalProtect: ${globalProtect}`);
98
+
100
99
  // No matching rule - check global protection
101
100
  if (!rule) {
102
101
  if (globalProtect) {
103
102
  // Skip if path is in exclude list
104
103
  if (exclude.some((pattern) => matchesPattern(pattern, pathname))) {
104
+ logger.debug(`[GlobalProtect] Skipping ${pathname} because it matches an exclude pattern`);
105
105
  return next();
106
106
  }
107
107
 
108
108
  // Skip if it's the login page itself (to avoid redirect loops)
109
109
  if (pathname === loginPath) {
110
+ logger.debug(`[GlobalProtect] Skipping ${pathname} because it is the loginPath`);
110
111
  return next();
111
112
  }
112
113
 
113
114
  // Require valid session
114
115
  if (!session || !isValidSessionStructure(session)) {
116
+ logger.debug(`[GlobalProtect] Redirecting to ${loginPath} because session is ${session ? 'invalid' : 'missing'}`);
115
117
  return context.redirect(loginPath);
116
118
  }
117
119
  }
120
+
121
+ logger.debug(`[GlobalProtect] Allowing ${pathname} because session is valid or globalProtect is false`);
118
122
  return next();
119
123
  }
120
124
 
@@ -123,9 +127,11 @@ export function createGuardMiddleware(): MiddlewareHandler {
123
127
 
124
128
  if (!allowed) {
125
129
  const redirectTo = rule.redirectTo ?? loginPath;
130
+ logger.debug(`[Guard] Redirecting to ${redirectTo} because access was denied by rule:`, rule);
126
131
  return context.redirect(redirectTo);
127
132
  }
128
133
 
134
+ logger.debug(`[Guard] Allowing ${pathname} because access was granted by rule:`, rule);
129
135
  return next();
130
136
  };
131
137
  }
@@ -29,3 +29,13 @@ export function warn(message: string, ...args: any[]): void {
29
29
  console.warn(`[SessionKit] ${message}`, ...args);
30
30
  }
31
31
  }
32
+
33
+ /**
34
+ * Log info message. Always logs unless in production, but can be forced via debug flag.
35
+ */
36
+ export function info(message: string, ...args: any[]): void {
37
+ const { debug } = getConfig();
38
+ if (debug || process.env.NODE_ENV !== 'production') {
39
+ console.log(`[SessionKit] ${message}`, ...args);
40
+ }
41
+ }
@@ -7,7 +7,7 @@ import {runWithContext as defaultRunWithContext} from "./context";
7
7
  import {isValidSessionStructure} from "./validation";
8
8
  import type {Session} from "./types";
9
9
  import {getConfig} from "./config";
10
- import {warn} from "./logger";
10
+ import * as logger from "./logger";
11
11
 
12
12
  /**
13
13
  * Session key used to store session in context.session
@@ -32,7 +32,7 @@ export const sessionMiddleware: MiddlewareHandler = async (context, next) => {
32
32
  session = rawSession;
33
33
  } else {
34
34
  // Invalid session structure - log warning and treat as unauthenticated
35
- warn(
35
+ logger.warn(
36
36
  'Invalid session structure detected. Session will be ignored. ' +
37
37
  'Ensure context.session.set("__session__", ...) has the correct structure. ' +
38
38
  'Received: ' + JSON.stringify(rawSession)
@@ -54,8 +54,8 @@ export const sessionMiddleware: MiddlewareHandler = async (context, next) => {
54
54
  store.session = session;
55
55
  } else if (config.setContextStore) {
56
56
  config.setContextStore({session});
57
- } else if (process.env.NODE_ENV !== 'production') {
58
- console.error('[SessionKit] getContextStore returned undefined, cannot set session');
57
+ } else {
58
+ logger.error('getContextStore returned undefined, cannot set session');
59
59
  }
60
60
  return next();
61
61
  }