@eventuras/fides-auth-store 0.1.3 → 0.2.0

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.
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createStore } from "@xstate/store";
2
2
  import { Logger } from "@eventuras/logger";
3
- import { configureLogger } from "@eventuras/fides-auth/logger";
3
+ import { configureLogger, createLogger } from "@eventuras/fides-auth/logger";
4
+ import { SESSION_EVENT } from "@eventuras/fides-auth/session-events";
4
5
  //#region src/store.ts
5
6
  /**
6
7
  * Default configuration values
@@ -248,10 +249,17 @@ function startSessionMonitor(store, checkAuthStatus, config = {}) {
248
249
  ...DEFAULT_CONFIG,
249
250
  ...config
250
251
  };
251
- const logger = Logger.create({
252
+ const logger = createLogger({
252
253
  namespace: finalConfig.loggerNamespace,
253
254
  context: { component: "SessionMonitor" }
254
255
  });
256
+ const emit = (event) => {
257
+ try {
258
+ finalConfig.onEvent?.(event);
259
+ } catch (error) {
260
+ logger.warn({ error: String(error) }, "onEvent callback threw");
261
+ }
262
+ };
255
263
  logger.debug({ interval: finalConfig.interval }, "Starting session monitor");
256
264
  let isActive = true;
257
265
  let timeoutId = null;
@@ -262,6 +270,10 @@ function startSessionMonitor(store, checkAuthStatus, config = {}) {
262
270
  logger.debug({ authenticated: result.authenticated }, "Session monitor check");
263
271
  if (!result.authenticated) {
264
272
  logger.info("Session monitor detected unauthenticated state - session ended");
273
+ emit({
274
+ event: SESSION_EVENT.REJECTED,
275
+ source: "session-monitor"
276
+ });
265
277
  store.send({ type: "sessionExpired" });
266
278
  if (finalConfig.onSessionExpired) finalConfig.onSessionExpired();
267
279
  return;
@@ -274,6 +286,11 @@ function startSessionMonitor(store, checkAuthStatus, config = {}) {
274
286
  const err = error;
275
287
  if (err?.code === "OAUTH_RESPONSE_BODY_ERROR" && err?.error === "invalid_grant") {
276
288
  logger.info("Session monitor detected expired refresh token - user session ended");
289
+ emit({
290
+ event: SESSION_EVENT.REJECTED,
291
+ source: "session-monitor",
292
+ reason: "refresh_failed"
293
+ });
277
294
  store.send({ type: "sessionExpired" });
278
295
  if (finalConfig.onSessionExpired) finalConfig.onSessionExpired();
279
296
  return;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/store.ts","../src/session-monitor.ts","../src/configure-logger.ts"],"sourcesContent":["import { createStore } from '@xstate/store';\nimport { Logger } from '@eventuras/logger';\nimport type { SessionUser, AuthStatus } from './types';\n\n/**\n * Authentication store context\n */\nexport type AuthStoreContext = {\n user: SessionUser | null;\n isAdmin: boolean;\n isAuthenticated: boolean;\n error: string | null;\n lastChecked: Date | null;\n isInitializing: boolean;\n};\n\n/**\n * Configuration for the auth store\n */\nexport type AuthStoreConfig = {\n /**\n * Function to check current authentication status\n */\n checkAuthStatus: () => Promise<AuthStatus>;\n\n /**\n * Optional configuration\n */\n config?: {\n /**\n * Role name that indicates admin access\n * @default 'Admin'\n */\n adminRole?: string;\n\n /**\n * Namespace for logger\n * @default 'fides-auth-next:store'\n */\n loggerNamespace?: string;\n };\n};\n\n/**\n * Default configuration values\n */\nconst DEFAULT_CONFIG = {\n adminRole: 'Admin',\n loggerNamespace: 'fides:auth-store',\n};\n\n/**\n * Creates an authentication store with XState Store\n *\n * @param options - Configuration for the auth store\n * @returns Configured XState store\n *\n * @example\n * ```typescript\n * const authStore = createAuthStore({\n * checkAuthStatus: async () => getAuthStatus(),\n * config: {\n * adminRole: 'Admin',\n * loggerNamespace: 'myapp:auth',\n * }\n * });\n * ```\n */\nexport function createAuthStore(options: AuthStoreConfig) {\n const config = { ...DEFAULT_CONFIG, ...options.config };\n const logger = Logger.create({\n namespace: config.loggerNamespace,\n context: { component: 'AuthStore' },\n });\n\n /**\n * Initial context values\n */\n const initialContext: AuthStoreContext = {\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: null,\n lastChecked: null,\n isInitializing: true,\n };\n\n /**\n * Create the store with events\n */\n const store = createStore(\n {\n context: initialContext,\n on: {\n /**\n * Initialize authentication - check current status\n */\n initialize: () => ({\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: null,\n lastChecked: null,\n isInitializing: true,\n }),\n\n /**\n * Authentication check succeeded\n */\n authSuccess: (_context: AuthStoreContext, event: { user: SessionUser; }) => {\n logger.info({ user: event.user.roles }, 'User authenticated');\n return {\n user: event.user,\n isAdmin: event.user.roles?.includes(config.adminRole) ?? false,\n isAuthenticated: true,\n error: null,\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * Authentication check failed - not authenticated\n */\n authFailed: (_context: AuthStoreContext, event: { error?: string; } = {}) => {\n logger.info('User not authenticated');\n return {\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: event.error || null,\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * Session expired\n */\n sessionExpired: () => {\n logger.warn('Session expired');\n return {\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: 'Session expired',\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * User logged out\n */\n logout: () => {\n logger.info('User logged out');\n return {\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: null,\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * Login success\n */\n loginSuccess: (_context: AuthStoreContext, event: { user: SessionUser; }) => {\n logger.info({ user: event.user.email }, 'Login successful');\n return {\n user: event.user,\n isAdmin: event.user.roles?.includes(config.adminRole) ?? false,\n isAuthenticated: true,\n error: null,\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * Update last checked timestamp\n */\n updateLastChecked: (context: AuthStoreContext) => ({\n ...context,\n lastChecked: new Date(),\n }),\n\n /**\n * Set error\n */\n setError: (context: AuthStoreContext, event: { error: string; }) => ({\n ...context,\n error: event.error,\n }),\n\n /**\n * Clear error\n */\n clearError: (context: AuthStoreContext) => ({\n ...context,\n error: null,\n }),\n },\n }\n );\n\n return store;\n}\n\n/**\n * Helper function to initialize auth by checking status\n */\nexport async function initializeAuth(\n store: ReturnType<typeof createAuthStore>,\n checkAuthStatus: () => Promise<AuthStatus>\n) {\n const logger = Logger.create({\n namespace: 'fides:auth-store',\n context: { component: 'initializeAuth' },\n });\n\n logger.debug('Initializing authentication');\n store.send({ type: 'initialize' });\n\n try {\n const result = await checkAuthStatus();\n logger.debug({ authenticated: result.authenticated }, 'Auth status checked');\n\n if (result.authenticated && result.user) {\n store.send({ type: 'authSuccess', user: result.user });\n } else {\n store.send({ type: 'authFailed' });\n }\n } catch (error) {\n logger.debug({ error }, 'Auth check returned no session');\n store.send({ type: 'authFailed' });\n }\n}\n\n/**\n * Helper function to check auth status and update store\n */\nexport async function checkAuth(\n store: ReturnType<typeof createAuthStore>,\n checkAuthStatus: () => Promise<AuthStatus>\n) {\n const logger = Logger.create({\n namespace: 'fides:auth-store',\n context: { component: 'checkAuth' },\n });\n\n logger.debug('Checking authentication status');\n\n try {\n const result = await checkAuthStatus();\n logger.debug({ authenticated: result.authenticated }, 'Auth status checked');\n\n if (result.authenticated && result.user) {\n store.send({ type: 'authSuccess', user: result.user });\n } else {\n store.send({ type: 'authFailed' });\n }\n\n store.send({ type: 'updateLastChecked' });\n } catch (error) {\n // Check if this is an expected invalid_grant error (expired refresh token)\n const err = error as { code?: string; error?: string; error_description?: string; };\n const isInvalidGrant =\n err?.code === 'OAUTH_RESPONSE_BODY_ERROR' && err?.error === 'invalid_grant';\n\n if (isInvalidGrant) {\n // This is expected during logout or session expiry - log at info level\n logger.info('Session ended - refresh token expired or invalid');\n store.send({ type: 'sessionExpired' });\n } else {\n // Unexpected error during auth check - log with details\n const errorDetails: Record<string, unknown> = {\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n\n // Extract OAuth error details if present\n if (error && typeof error === 'object') {\n const oauthError = error as any;\n if (oauthError.code) errorDetails.code = oauthError.code;\n if (oauthError.error) errorDetails.error = oauthError.error;\n if (oauthError.error_description)\n errorDetails.error_description = oauthError.error_description;\n if (oauthError.status) errorDetails.status = oauthError.status;\n }\n\n logger.error(errorDetails, 'Auth check error');\n store.send({\n type: 'authFailed',\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n}\n","import { Logger } from '@eventuras/logger';\nimport type { createAuthStore } from './store';\nimport type { AuthStatus } from './types';\n\n/**\n * Configuration for session monitoring\n */\nexport type SessionMonitorConfig = {\n /**\n * Interval in milliseconds for session monitoring polling\n * @default 30000 (30 seconds)\n */\n interval?: number;\n\n /**\n * Namespace for logger\n * @default 'fides:session-monitor'\n */\n loggerNamespace?: string;\n\n /**\n * Callback when session expires\n */\n onSessionExpired?: () => void;\n\n /**\n * Callback when session check fails\n */\n onError?: (error: Error) => void;\n};\n\nconst DEFAULT_CONFIG = {\n interval: 30_000, // 30 seconds\n loggerNamespace: 'fides:session-monitor',\n};\n\n/**\n * Creates a session monitor that polls auth status at regular intervals\n *\n * This is designed to be used with React's useEffect for cleanup.\n *\n * @param store - The auth store to update\n * @param checkAuthStatus - Function to check authentication status\n * @param config - Optional configuration\n * @returns Cleanup function to stop monitoring\n *\n * @example\n * ```typescript\n * useEffect(() => {\n * const cleanup = startSessionMonitor(authStore, checkAuthStatus, {\n * interval: 30_000,\n * onSessionExpired: () => {\n * toast.warn('Your session has expired');\n * }\n * });\n *\n * return cleanup;\n * }, []);\n * ```\n */\nexport function startSessionMonitor(\n store: ReturnType<typeof createAuthStore>,\n checkAuthStatus: () => Promise<AuthStatus>,\n config: SessionMonitorConfig = {}\n): () => void {\n const finalConfig = { ...DEFAULT_CONFIG, ...config };\n const logger = Logger.create({\n namespace: finalConfig.loggerNamespace,\n context: { component: 'SessionMonitor' },\n });\n\n logger.debug({ interval: finalConfig.interval }, 'Starting session monitor');\n\n let isActive = true;\n // Portable timer handle: `number` in the browser, `NodeJS.Timeout` under Node —\n // this package is framework-agnostic and runs in both.\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const poll = async (): Promise<void> => {\n if (!isActive) return;\n\n try {\n const result = await checkAuthStatus();\n logger.debug({ authenticated: result.authenticated }, 'Session monitor check');\n\n if (!result.authenticated) {\n // User is no longer authenticated - session ended\n logger.info('Session monitor detected unauthenticated state - session ended');\n store.send({ type: 'sessionExpired' });\n\n if (finalConfig.onSessionExpired) {\n finalConfig.onSessionExpired();\n }\n\n // Stop monitoring after session expires\n return;\n }\n\n if (result.user) {\n store.send({ type: 'authSuccess', user: result.user });\n }\n } catch (error) {\n // Check if this is an expected invalid_grant error (expired refresh token)\n const err = error as { code?: string; error?: string; error_description?: string; };\n const isInvalidGrant =\n err?.code === 'OAUTH_RESPONSE_BODY_ERROR' && err?.error === 'invalid_grant';\n\n if (isInvalidGrant) {\n // This is expected during logout or session expiry - log at info level\n logger.info('Session monitor detected expired refresh token - user session ended');\n store.send({ type: 'sessionExpired' });\n\n if (finalConfig.onSessionExpired) {\n finalConfig.onSessionExpired();\n }\n\n // Stop monitoring after session expires\n return;\n }\n\n // Unexpected error during auth check - log with details\n const errorDetails: Record<string, unknown> = {\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n\n // Extract OAuth error details if present\n if (error && typeof error === 'object') {\n const oauthError = error as any;\n if (oauthError.code) errorDetails.code = oauthError.code;\n if (oauthError.error) errorDetails.error = oauthError.error;\n if (oauthError.error_description)\n errorDetails.error_description = oauthError.error_description;\n if (oauthError.status) errorDetails.status = oauthError.status;\n }\n\n logger.error(errorDetails, 'Session monitor error');\n\n if (finalConfig.onError && error instanceof Error) {\n finalConfig.onError(error);\n }\n }\n\n // Schedule next poll if still active\n if (isActive) {\n timeoutId = setTimeout(poll, finalConfig.interval);\n }\n };\n\n // Start first poll\n timeoutId = setTimeout(poll, finalConfig.interval);\n\n // Return cleanup function\n return () => {\n logger.debug('Stopping session monitor');\n isActive = false;\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n}\n","/**\n * Configures fides-auth to use @eventuras/logger for all internal logging.\n *\n * Call this once at application startup, before creating the auth store.\n *\n * @example\n * ```typescript\n * import { configureAuthLogger, createAuthStore } from '@eventuras/fides-auth-store';\n *\n * configureAuthLogger();\n * const authStore = createAuthStore({ checkAuthStatus });\n * ```\n */\n\nimport { configureLogger } from '@eventuras/fides-auth/logger';\nimport { Logger } from '@eventuras/logger';\n\nexport function configureAuthLogger(): void {\n configureLogger({\n create(options) {\n return Logger.create(options);\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/store.ts","../src/session-monitor.ts","../src/configure-logger.ts"],"sourcesContent":["import { createStore } from '@xstate/store';\nimport { Logger } from '@eventuras/logger';\nimport type { SessionUser, AuthStatus } from './types';\n\n/**\n * Authentication store context\n */\nexport type AuthStoreContext = {\n user: SessionUser | null;\n isAdmin: boolean;\n isAuthenticated: boolean;\n error: string | null;\n lastChecked: Date | null;\n isInitializing: boolean;\n};\n\n/**\n * Configuration for the auth store\n */\nexport type AuthStoreConfig = {\n /**\n * Function to check current authentication status\n */\n checkAuthStatus: () => Promise<AuthStatus>;\n\n /**\n * Optional configuration\n */\n config?: {\n /**\n * Role name that indicates admin access\n * @default 'Admin'\n */\n adminRole?: string;\n\n /**\n * Namespace for logger\n * @default 'fides-auth-next:store'\n */\n loggerNamespace?: string;\n };\n};\n\n/**\n * Default configuration values\n */\nconst DEFAULT_CONFIG = {\n adminRole: 'Admin',\n loggerNamespace: 'fides:auth-store',\n};\n\n/**\n * Creates an authentication store with XState Store\n *\n * @param options - Configuration for the auth store\n * @returns Configured XState store\n *\n * @example\n * ```typescript\n * const authStore = createAuthStore({\n * checkAuthStatus: async () => getAuthStatus(),\n * config: {\n * adminRole: 'Admin',\n * loggerNamespace: 'myapp:auth',\n * }\n * });\n * ```\n */\nexport function createAuthStore(options: AuthStoreConfig) {\n const config = { ...DEFAULT_CONFIG, ...options.config };\n const logger = Logger.create({\n namespace: config.loggerNamespace,\n context: { component: 'AuthStore' },\n });\n\n /**\n * Initial context values\n */\n const initialContext: AuthStoreContext = {\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: null,\n lastChecked: null,\n isInitializing: true,\n };\n\n /**\n * Create the store with events\n */\n const store = createStore(\n {\n context: initialContext,\n on: {\n /**\n * Initialize authentication - check current status\n */\n initialize: () => ({\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: null,\n lastChecked: null,\n isInitializing: true,\n }),\n\n /**\n * Authentication check succeeded\n */\n authSuccess: (_context: AuthStoreContext, event: { user: SessionUser; }) => {\n logger.info({ user: event.user.roles }, 'User authenticated');\n return {\n user: event.user,\n isAdmin: event.user.roles?.includes(config.adminRole) ?? false,\n isAuthenticated: true,\n error: null,\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * Authentication check failed - not authenticated\n */\n authFailed: (_context: AuthStoreContext, event: { error?: string; } = {}) => {\n logger.info('User not authenticated');\n return {\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: event.error || null,\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * Session expired\n */\n sessionExpired: () => {\n logger.warn('Session expired');\n return {\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: 'Session expired',\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * User logged out\n */\n logout: () => {\n logger.info('User logged out');\n return {\n user: null,\n isAdmin: false,\n isAuthenticated: false,\n error: null,\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * Login success\n */\n loginSuccess: (_context: AuthStoreContext, event: { user: SessionUser; }) => {\n logger.info({ user: event.user.email }, 'Login successful');\n return {\n user: event.user,\n isAdmin: event.user.roles?.includes(config.adminRole) ?? false,\n isAuthenticated: true,\n error: null,\n lastChecked: new Date(),\n isInitializing: false,\n };\n },\n\n /**\n * Update last checked timestamp\n */\n updateLastChecked: (context: AuthStoreContext) => ({\n ...context,\n lastChecked: new Date(),\n }),\n\n /**\n * Set error\n */\n setError: (context: AuthStoreContext, event: { error: string; }) => ({\n ...context,\n error: event.error,\n }),\n\n /**\n * Clear error\n */\n clearError: (context: AuthStoreContext) => ({\n ...context,\n error: null,\n }),\n },\n }\n );\n\n return store;\n}\n\n/**\n * Helper function to initialize auth by checking status\n */\nexport async function initializeAuth(\n store: ReturnType<typeof createAuthStore>,\n checkAuthStatus: () => Promise<AuthStatus>\n) {\n const logger = Logger.create({\n namespace: 'fides:auth-store',\n context: { component: 'initializeAuth' },\n });\n\n logger.debug('Initializing authentication');\n store.send({ type: 'initialize' });\n\n try {\n const result = await checkAuthStatus();\n logger.debug({ authenticated: result.authenticated }, 'Auth status checked');\n\n if (result.authenticated && result.user) {\n store.send({ type: 'authSuccess', user: result.user });\n } else {\n store.send({ type: 'authFailed' });\n }\n } catch (error) {\n logger.debug({ error }, 'Auth check returned no session');\n store.send({ type: 'authFailed' });\n }\n}\n\n/**\n * Helper function to check auth status and update store\n */\nexport async function checkAuth(\n store: ReturnType<typeof createAuthStore>,\n checkAuthStatus: () => Promise<AuthStatus>\n) {\n const logger = Logger.create({\n namespace: 'fides:auth-store',\n context: { component: 'checkAuth' },\n });\n\n logger.debug('Checking authentication status');\n\n try {\n const result = await checkAuthStatus();\n logger.debug({ authenticated: result.authenticated }, 'Auth status checked');\n\n if (result.authenticated && result.user) {\n store.send({ type: 'authSuccess', user: result.user });\n } else {\n store.send({ type: 'authFailed' });\n }\n\n store.send({ type: 'updateLastChecked' });\n } catch (error) {\n // Check if this is an expected invalid_grant error (expired refresh token)\n const err = error as { code?: string; error?: string; error_description?: string; };\n const isInvalidGrant =\n err?.code === 'OAUTH_RESPONSE_BODY_ERROR' && err?.error === 'invalid_grant';\n\n if (isInvalidGrant) {\n // This is expected during logout or session expiry - log at info level\n logger.info('Session ended - refresh token expired or invalid');\n store.send({ type: 'sessionExpired' });\n } else {\n // Unexpected error during auth check - log with details\n const errorDetails: Record<string, unknown> = {\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n\n // Extract OAuth error details if present\n if (error && typeof error === 'object') {\n const oauthError = error as any;\n if (oauthError.code) errorDetails.code = oauthError.code;\n if (oauthError.error) errorDetails.error = oauthError.error;\n if (oauthError.error_description)\n errorDetails.error_description = oauthError.error_description;\n if (oauthError.status) errorDetails.status = oauthError.status;\n }\n\n logger.error(errorDetails, 'Auth check error');\n store.send({\n type: 'authFailed',\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n}\n","import { createLogger } from '@eventuras/fides-auth/logger';\nimport { SESSION_EVENT, type SessionClientEvent } from '@eventuras/fides-auth/session-events';\nimport type { createAuthStore } from './store';\nimport type { AuthStatus } from './types';\n\n/**\n * Configuration for session monitoring\n */\nexport type SessionMonitorConfig = {\n /**\n * Interval in milliseconds for session monitoring polling\n * @default 30000 (30 seconds)\n */\n interval?: number;\n\n /**\n * Namespace for logger\n * @default 'fides:session-monitor'\n */\n loggerNamespace?: string;\n\n /**\n * Callback when session expires\n */\n onSessionExpired?: () => void;\n\n /**\n * Callback when session check fails\n */\n onError?: (error: Error) => void;\n\n /**\n * Called for every session lifecycle event the monitor observes, using the\n * same vocabulary as the server-side events.\n *\n * The logger writes to the browser console, which production never sees.\n * Forward these to your own endpoint, Sentry or an OTLP collector to get the\n * client half of a session's story into the same place as the server half.\n * The library ships no transport of its own.\n */\n onEvent?: (event: SessionClientEvent) => void;\n};\n\nconst DEFAULT_CONFIG = {\n interval: 30_000, // 30 seconds\n loggerNamespace: 'fides:session-monitor',\n};\n\n/**\n * Creates a session monitor that polls auth status at regular intervals\n *\n * This is designed to be used with React's useEffect for cleanup.\n *\n * @param store - The auth store to update\n * @param checkAuthStatus - Function to check authentication status\n * @param config - Optional configuration\n * @returns Cleanup function to stop monitoring\n *\n * @example\n * ```typescript\n * useEffect(() => {\n * const cleanup = startSessionMonitor(authStore, checkAuthStatus, {\n * interval: 30_000,\n * onSessionExpired: () => {\n * toast.warn('Your session has expired');\n * }\n * });\n *\n * return cleanup;\n * }, []);\n * ```\n */\nexport function startSessionMonitor(\n store: ReturnType<typeof createAuthStore>,\n checkAuthStatus: () => Promise<AuthStatus>,\n config: SessionMonitorConfig = {}\n): () => void {\n const finalConfig = { ...DEFAULT_CONFIG, ...config };\n // The pluggable factory, not @eventuras/logger directly — otherwise\n // configureAuthLogger() has no effect here and this one module logs to a\n // different place than the rest of the package.\n const logger = createLogger({\n namespace: finalConfig.loggerNamespace,\n context: { component: 'SessionMonitor' },\n });\n\n // A consumer's beacon must never be able to stop the monitor.\n const emit = (event: SessionClientEvent): void => {\n try {\n finalConfig.onEvent?.(event);\n } catch (error) {\n logger.warn({ error: String(error) }, 'onEvent callback threw');\n }\n };\n\n logger.debug({ interval: finalConfig.interval }, 'Starting session monitor');\n\n let isActive = true;\n // Portable timer handle: `number` in the browser, `NodeJS.Timeout` under Node —\n // this package is framework-agnostic and runs in both.\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const poll = async (): Promise<void> => {\n if (!isActive) return;\n\n try {\n const result = await checkAuthStatus();\n logger.debug({ authenticated: result.authenticated }, 'Session monitor check');\n\n if (!result.authenticated) {\n // User is no longer authenticated - session ended\n logger.info('Session monitor detected unauthenticated state - session ended');\n emit({ event: SESSION_EVENT.REJECTED, source: 'session-monitor' });\n store.send({ type: 'sessionExpired' });\n\n if (finalConfig.onSessionExpired) {\n finalConfig.onSessionExpired();\n }\n\n // Stop monitoring after session expires\n return;\n }\n\n if (result.user) {\n store.send({ type: 'authSuccess', user: result.user });\n }\n } catch (error) {\n // Check if this is an expected invalid_grant error (expired refresh token)\n const err = error as { code?: string; error?: string; error_description?: string; };\n const isInvalidGrant =\n err?.code === 'OAUTH_RESPONSE_BODY_ERROR' && err?.error === 'invalid_grant';\n\n if (isInvalidGrant) {\n // This is expected during logout or session expiry - log at info level\n logger.info('Session monitor detected expired refresh token - user session ended');\n emit({\n event: SESSION_EVENT.REJECTED,\n source: 'session-monitor',\n reason: 'refresh_failed',\n });\n store.send({ type: 'sessionExpired' });\n\n if (finalConfig.onSessionExpired) {\n finalConfig.onSessionExpired();\n }\n\n // Stop monitoring after session expires\n return;\n }\n\n // Unexpected error during auth check - log with details\n const errorDetails: Record<string, unknown> = {\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n\n // Extract OAuth error details if present\n if (error && typeof error === 'object') {\n const oauthError = error as any;\n if (oauthError.code) errorDetails.code = oauthError.code;\n if (oauthError.error) errorDetails.error = oauthError.error;\n if (oauthError.error_description)\n errorDetails.error_description = oauthError.error_description;\n if (oauthError.status) errorDetails.status = oauthError.status;\n }\n\n logger.error(errorDetails, 'Session monitor error');\n\n if (finalConfig.onError && error instanceof Error) {\n finalConfig.onError(error);\n }\n }\n\n // Schedule next poll if still active\n if (isActive) {\n timeoutId = setTimeout(poll, finalConfig.interval);\n }\n };\n\n // Start first poll\n timeoutId = setTimeout(poll, finalConfig.interval);\n\n // Return cleanup function\n return () => {\n logger.debug('Stopping session monitor');\n isActive = false;\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n };\n}\n","/**\n * Configures fides-auth to use @eventuras/logger for all internal logging.\n *\n * Call this once at application startup, before creating the auth store.\n *\n * @example\n * ```typescript\n * import { configureAuthLogger, createAuthStore } from '@eventuras/fides-auth-store';\n *\n * configureAuthLogger();\n * const authStore = createAuthStore({ checkAuthStatus });\n * ```\n */\n\nimport { configureLogger } from '@eventuras/fides-auth/logger';\nimport { Logger } from '@eventuras/logger';\n\nexport function configureAuthLogger(): void {\n configureLogger({\n create(options) {\n return Logger.create(options);\n },\n });\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { SessionClientEvent } from '@eventuras/fides-auth/session-events';
1
2
  import { createAuthStore } from './store';
2
3
  import { AuthStatus } from './types';
3
4
  /**
@@ -22,6 +23,16 @@ export type SessionMonitorConfig = {
22
23
  * Callback when session check fails
23
24
  */
24
25
  onError?: (error: Error) => void;
26
+ /**
27
+ * Called for every session lifecycle event the monitor observes, using the
28
+ * same vocabulary as the server-side events.
29
+ *
30
+ * The logger writes to the browser console, which production never sees.
31
+ * Forward these to your own endpoint, Sentry or an OTLP collector to get the
32
+ * client half of a session's story into the same place as the server half.
33
+ * The library ships no transport of its own.
34
+ */
35
+ onEvent?: (event: SessionClientEvent) => void;
25
36
  };
26
37
  /**
27
38
  * Creates a session monitor that polls auth status at regular intervals
@@ -1 +1 @@
1
- {"version":3,"file":"session-monitor.d.ts","sourceRoot":"","sources":["../src/session-monitor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,CAAC;AAOF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,EACzC,eAAe,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,EAC1C,MAAM,GAAE,oBAAyB,GAChC,MAAM,IAAI,CAgGZ"}
1
+ {"version":3,"file":"session-monitor.d.ts","sourceRoot":"","sources":["../src/session-monitor.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC9F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC/C,CAAC;AAOF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,EACzC,eAAe,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,EAC1C,MAAM,GAAE,oBAAyB,GAChC,MAAM,IAAI,CAkHZ"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Types for the Authentication Store
3
+ *
4
+ * These types are generic and can be used across different applications.
5
+ */
6
+ /**
7
+ * Represents a user session with basic information
8
+ */
9
+ export type SessionUser = {
10
+ name: string;
11
+ email: string;
12
+ roles: string[];
13
+ };
14
+ /**
15
+ * Result of checking authentication status
16
+ */
17
+ export type AuthStatus = {
18
+ authenticated: boolean;
19
+ user?: SessionUser;
20
+ };
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventuras/fides-auth-store",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Framework-agnostic authentication state store (XState Store) for @eventuras/fides-auth",
5
5
  "keywords": [
6
6
  "authentication",
@@ -40,10 +40,11 @@
40
40
  "dependencies": {
41
41
  "@eventuras/logger": "^0.8.1",
42
42
  "@xstate/store": "^4.2.2",
43
- "@eventuras/fides-auth": "0.12.0"
43
+ "@eventuras/fides-auth": "0.13.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^22.20.1",
47
+ "typescript": "^6.0.2",
47
48
  "vite": "^8.2.0",
48
49
  "vitest": "^4.1.10",
49
50
  "@eventuras/typescript-config": "1.0.0",
@@ -54,6 +55,7 @@
54
55
  },
55
56
  "scripts": {
56
57
  "build": "vite build",
58
+ "typecheck": "tsc --noEmit",
57
59
  "dev": "vite build --watch",
58
60
  "test": "vitest run",
59
61
  "test:watch": "vitest"