@htlkg/core 0.0.14 → 0.0.15

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.
@@ -68,5 +68,10 @@ declare function requireBrandAccess(context: APIContext, brandId: number, loginU
68
68
  user?: User;
69
69
  redirectTo?: string;
70
70
  }>;
71
+ /**
72
+ * Sign out the current user (client-side)
73
+ * With SSR mode enabled, Amplify automatically clears auth cookies
74
+ */
75
+ declare function signOut(): Promise<void>;
71
76
 
72
- export { type User, getClientUser, getUser, hasAccessToAccount, hasAccessToBrand, isAdminUser, isSuperAdminUser, requireAdminAccess, requireAuth, requireBrandAccess };
77
+ export { type User, getClientUser, getUser, hasAccessToAccount, hasAccessToBrand, isAdminUser, isSuperAdminUser, requireAdminAccess, requireAuth, requireBrandAccess, signOut };
@@ -377,6 +377,23 @@ async function requireBrandAccess(context, brandId, loginUrl) {
377
377
  "requireBrandAccess should be imported from @htlkg/astro/middleware"
378
378
  );
379
379
  }
380
+ async function signOut() {
381
+ try {
382
+ const { signOut: amplifySignOut } = await import("aws-amplify/auth");
383
+ await amplifySignOut({ global: true });
384
+ } catch (error) {
385
+ console.warn("[Auth] Amplify signOut failed, clearing cookies manually:", error);
386
+ if (typeof document !== "undefined") {
387
+ const cookies = document.cookie.split(";");
388
+ for (const cookie of cookies) {
389
+ const [name] = cookie.trim().split("=");
390
+ if (name.includes("CognitoIdentityServiceProvider") || name.includes("amplify") || name.includes("idToken") || name.includes("accessToken") || name.includes("refreshToken")) {
391
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
392
+ }
393
+ }
394
+ }
395
+ }
396
+ }
380
397
  export {
381
398
  getClientUser,
382
399
  getUser,
@@ -386,6 +403,7 @@ export {
386
403
  isSuperAdminUser,
387
404
  requireAdminAccess,
388
405
  requireAuth,
389
- requireBrandAccess
406
+ requireBrandAccess,
407
+ signOut
390
408
  };
391
409
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth/index.ts","../../src/amplify-astro-adapter/createRunWithAmplifyServerContext.ts","../../src/amplify-astro-adapter/globalSettings.ts","../../src/utils/logger.ts","../../src/amplify-astro-adapter/createCookieStorageAdapterFromAstroContext.ts"],"sourcesContent":["/**\n * @htlkg/core/auth\n * Core authentication functions and utilities\n */\n\nimport type { APIContext } from \"astro\";\nimport { Amplify } from \"aws-amplify\";\nimport { fetchAuthSession } from \"aws-amplify/auth\";\nimport {\n\tfetchAuthSession as fetchServerAuthSession,\n\tgetCurrentUser as getServerCurrentUser,\n} from \"aws-amplify/auth/server\";\nimport { createRunWithAmplifyServerContext, globalSettings } from \"../amplify-astro-adapter\";\n\n// Re-export types\nexport type { APIContext } from \"astro\";\n\n/**\n * User interface representing an authenticated user\n */\nexport interface User {\n\tusername: string;\n\temail: string;\n\tbrandIds: number[];\n\taccountIds: number[];\n\tisAdmin: boolean;\n\tisSuperAdmin: boolean;\n\troles: string[];\n}\n\n/**\n * Parse comma-separated IDs from Cognito custom attributes\n */\nfunction parseIds(ids: string | undefined): number[] {\n\tif (!ids) return [];\n\treturn ids\n\t\t.split(\",\")\n\t\t.map((id) => Number.parseInt(id.trim(), 10))\n\t\t.filter((id) => !Number.isNaN(id));\n}\n\n// Track if Amplify has been configured\nlet amplifyConfigured = false;\n\n/**\n * Configure Amplify on first use (server-side)\n * This must be called before any auth operations\n */\nfunction ensureAmplifyConfigured(): void {\n\tif (amplifyConfigured) return;\n\n\ttry {\n\t\t// Amplify should already be configured by the middleware\n\t\t// This is just a safety check\n\t\tconst config = Amplify.getConfig();\n\t\tif (!config.Auth) {\n\t\t\tthrow new Error(\"Amplify Auth not configured\");\n\t\t}\n\t\tamplifyConfigured = true;\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : \"Unknown error\";\n\t\tconsole.error(`[Auth] Amplify not configured: ${errorMsg}`);\n\t\tthrow error;\n\t}\n}\n\n/**\n * Get current authenticated user (server-side)\n * Reads Amplify auth cookies from the request and validates the session\n */\nexport async function getUser(context: APIContext): Promise<User | null> {\n\ttry {\n\t\tensureAmplifyConfigured();\n\t\t\n\t\t// Get the current Amplify configuration\n\t\tconst amplifyConfig = Amplify.getConfig();\n\n\t\t// Create the server context runner - pass globalSettings explicitly\n\t\t// to ensure the same instance is used across all modules\n\t\tconst runWithAmplifyServerContext = createRunWithAmplifyServerContext({\n\t\t\tconfig: amplifyConfig,\n\t\t\tglobalSettings,\n\t\t});\n\n\t\t// Create Astro server context\n\t\tconst astroServerContext = {\n\t\t\tcookies: context.cookies,\n\t\t\trequest: context.request,\n\t\t};\n\n\t\t// Run in Amplify server context\n\t\tconst user = await runWithAmplifyServerContext({\n\t\t\tastroServerContext,\n\t\t\toperation: async (contextSpec) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst currentUser = await getServerCurrentUser(contextSpec as any);\n\t\t\t\t\tconst session = await fetchServerAuthSession(contextSpec as any);\n\n\t\t\t\t\tif (!session.tokens?.accessToken) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst accessPayload = session.tokens.accessToken.payload;\n\t\t\t\t\tconst idPayload = session.tokens.idToken?.payload;\n\n\t\t\t\t\t// Parse user attributes - email is typically in ID token, not access token\n\t\t\t\t\tconst email =\n\t\t\t\t\t\t(idPayload?.email as string) ||\n\t\t\t\t\t\t(accessPayload.email as string) ||\n\t\t\t\t\t\t\"\";\n\t\t\t\t\tconst brandIds = parseIds(\n\t\t\t\t\t\taccessPayload[\"custom:brand_ids\"] as string,\n\t\t\t\t\t);\n\t\t\t\t\tconst accountIds = parseIds(\n\t\t\t\t\t\taccessPayload[\"custom:account_ids\"] as string,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Check admin status\n\t\t\t\t\tconst groups = (accessPayload[\"cognito:groups\"] as string[]) || [];\n\t\t\t\t\tconst isAdmin =\n\t\t\t\t\t\tgroups.includes(\"admin\") ||\n\t\t\t\t\t\tgroups.includes(\"ADMINS\") ||\n\t\t\t\t\t\tgroups.includes(\"SUPER_ADMINS\");\n\t\t\t\t\tconst isSuperAdmin = groups.includes(\"SUPER_ADMINS\");\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tusername: currentUser.username,\n\t\t\t\t\t\temail,\n\t\t\t\t\t\tbrandIds,\n\t\t\t\t\t\taccountIds,\n\t\t\t\t\t\tisAdmin,\n\t\t\t\t\t\tisSuperAdmin,\n\t\t\t\t\t\troles: groups,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// UserUnAuthenticatedException is expected when user is not logged in\n\t\t\t\t\t// Only log other errors without sensitive data\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\terror.name !== \"UserUnAuthenticatedException\"\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Log error name and message without stack trace or sensitive data\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\"[Auth] Error in server context:\",\n\t\t\t\t\t\t\terror.name,\n\t\t\t\t\t\t\t\"-\",\n\t\t\t\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\treturn user;\n\t} catch (error) {\n\t\t// Log error without exposing sensitive information\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(\n\t\t\t\t\"[Auth] Server-side auth error:\",\n\t\t\t\terror.name,\n\t\t\t\t\"-\",\n\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.error(\"[Auth] Server-side auth error: Unknown error\");\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * Get current authenticated user (client-side)\n */\nexport async function getClientUser(): Promise<User | null> {\n\ttry {\n\t\tconst session = await fetchAuthSession();\n\n\t\tif (!session.tokens?.accessToken) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst accessPayload = session.tokens.accessToken.payload;\n\t\tconst idPayload = session.tokens.idToken?.payload;\n\n\t\tconst email =\n\t\t\t(idPayload?.email as string) || (accessPayload.email as string) || \"\";\n\t\tconst brandIds = parseIds(accessPayload[\"custom:brand_ids\"] as string);\n\t\tconst accountIds = parseIds(accessPayload[\"custom:account_ids\"] as string);\n\n\t\tconst groups = (accessPayload[\"cognito:groups\"] as string[]) || [];\n\t\tconst isAdmin =\n\t\t\tgroups.includes(\"admin\") ||\n\t\t\tgroups.includes(\"ADMINS\") ||\n\t\t\tgroups.includes(\"SUPER_ADMINS\");\n\t\tconst isSuperAdmin = groups.includes(\"SUPER_ADMINS\");\n\n\t\treturn {\n\t\t\tusername: (accessPayload.username as string) || \"\",\n\t\t\temail,\n\t\t\tbrandIds,\n\t\t\taccountIds,\n\t\t\tisAdmin,\n\t\t\tisSuperAdmin,\n\t\t\troles: groups,\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(\n\t\t\t\t\"[Auth] Client auth error:\",\n\t\t\t\terror.name,\n\t\t\t\t\"-\",\n\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t);\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * Check if user has access to a specific brand\n */\nexport function hasAccessToBrand(\n\tuser: User | null,\n\tbrandId: number,\n): boolean {\n\tif (!user) return false;\n\tif (user.isAdmin) return true;\n\treturn user.brandIds.includes(brandId);\n}\n\n/**\n * Check if user has access to a specific account\n */\nexport function hasAccessToAccount(\n\tuser: User | null,\n\taccountId: number,\n): boolean {\n\tif (!user) return false;\n\tif (user.isAdmin) return true;\n\treturn user.accountIds.includes(accountId);\n}\n\n/**\n * Check if user is an admin\n */\nexport function isAdminUser(user: User | null): boolean {\n\treturn user?.isAdmin || false;\n}\n\n/**\n * Check if user is a super admin\n */\nexport function isSuperAdminUser(user: User | null): boolean {\n\treturn user?.isSuperAdmin || false;\n}\n\n/**\n * Placeholder for requireAuth - will be implemented in @htlkg/integrations\n * This is here for type exports and documentation\n */\nexport async function requireAuth(\n\tcontext: APIContext,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireAuth should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Placeholder for requireAdminAccess - will be implemented in @htlkg/integrations\n */\nexport async function requireAdminAccess(\n\tcontext: APIContext,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireAdminAccess should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Placeholder for requireBrandAccess - will be implemented in @htlkg/integrations\n */\nexport async function requireBrandAccess(\n\tcontext: APIContext,\n\tbrandId: number,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireBrandAccess should be imported from @htlkg/astro/middleware\",\n\t);\n}\n","import type { ResourcesConfig } from 'aws-amplify';\nimport { sharedInMemoryStorage } from 'aws-amplify/utils';\nimport {\n createAWSCredentialsAndIdentityIdProvider,\n createKeyValueStorageFromCookieStorageAdapter,\n createUserPoolsTokenProvider,\n runWithAmplifyServerContext as coreRunWithContext,\n} from 'aws-amplify/adapter-core';\n\nimport type { AstroServer } from './types';\nimport { globalSettings as defaultGlobalSettings } from './globalSettings';\nimport { createCookieStorageAdapterFromAstroContext } from './createCookieStorageAdapterFromAstroContext';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('amplify-server-context');\n\n/**\n * Creates a function that runs operations within the Amplify server context.\n *\n * IMPORTANT: Pass globalSettings explicitly to avoid module singleton issues\n * when using linked packages or different bundling contexts.\n */\nexport const createRunWithAmplifyServerContext = ({\n config: resourcesConfig,\n globalSettings = defaultGlobalSettings,\n}: {\n config: ResourcesConfig;\n globalSettings?: AstroServer.GlobalSettings;\n}): AstroServer.RunOperationWithContext => {\n const isServerSideAuthEnabled = globalSettings.isServerSideAuthEnabled();\n const isSSLOrigin = globalSettings.isSSLOrigin();\n const setCookieOptions = globalSettings.getRuntimeOptions().cookies ?? {};\n\n log.debug('Settings:', {\n isServerSideAuthEnabled,\n isSSLOrigin,\n hasCookieOptions: Object.keys(setCookieOptions).length > 0,\n });\n \n const mergedSetCookieOptions = {\n ...(isServerSideAuthEnabled && { httpOnly: true, sameSite: 'lax' as const }),\n ...setCookieOptions,\n ...(isServerSideAuthEnabled && { secure: isSSLOrigin }),\n path: '/',\n };\n\n const runWithContext: AstroServer.RunOperationWithContext = async ({\n astroServerContext,\n operation,\n }) => {\n if (resourcesConfig.Auth) {\n const cookieAdapter = await createCookieStorageAdapterFromAstroContext(astroServerContext);\n \n const keyValueStorage =\n astroServerContext === null\n ? sharedInMemoryStorage\n : createKeyValueStorageFromCookieStorageAdapter(\n cookieAdapter,\n undefined,\n mergedSetCookieOptions\n );\n\n const credentialsProvider = createAWSCredentialsAndIdentityIdProvider(\n resourcesConfig.Auth,\n keyValueStorage\n );\n \n const tokenProvider = createUserPoolsTokenProvider(\n resourcesConfig.Auth,\n keyValueStorage\n );\n\n return coreRunWithContext(\n resourcesConfig,\n { Auth: { credentialsProvider, tokenProvider } },\n operation\n );\n }\n\n return coreRunWithContext(resourcesConfig, {}, operation);\n };\n\n return runWithContext;\n};\n","import type { AstroServer } from './types';\n\nexport const globalSettings: AstroServer.GlobalSettings = (() => {\n let runtimeOptions: AstroServer.RuntimeOptions = {};\n let serverSideAuthEnabled = true;\n let sslOrigin = false;\n\n return {\n setRuntimeOptions(opts) { runtimeOptions = opts ?? {}; },\n getRuntimeOptions() { return runtimeOptions; },\n enableServerSideAuth() { serverSideAuthEnabled = true; },\n isServerSideAuthEnabled() { return serverSideAuthEnabled; },\n setIsSSLOrigin(v: boolean) { sslOrigin = v; },\n isSSLOrigin() { return sslOrigin; },\n };\n})();\n","/**\n * Simple debug logger utility\n * \n * Debug logs are only shown when DEBUG=true or HTLKG_DEBUG=true is set in environment.\n * Info logs are always shown.\n * \n * @example\n * ```typescript\n * import { logger } from '@htlkg/core/utils/logger';\n * \n * logger.debug('server-client', 'Detailed debug info', { data });\n * logger.info('server-client', 'Important info message');\n * logger.warn('server-client', 'Warning message');\n * logger.error('server-client', 'Error occurred', error);\n * ```\n */\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst isDebugEnabled = (): boolean => {\n // Check Node.js environment variables\n if (typeof process !== 'undefined' && process.env) {\n return process.env.DEBUG === 'true' || \n process.env.HTLKG_DEBUG === 'true' ||\n process.env.DEBUG === '*';\n }\n // Browser/Vite environment - check for DEV mode\n try {\n // @ts-ignore - import.meta.env is Vite-specific\n if (typeof import.meta !== 'undefined' && import.meta.env) {\n // @ts-ignore\n return import.meta.env.DEBUG === 'true' || \n // @ts-ignore\n import.meta.env.HTLKG_DEBUG === 'true' ||\n // @ts-ignore\n import.meta.env.DEV === true;\n }\n } catch {\n // Ignore errors accessing import.meta\n }\n return false;\n};\n\nconst formatMessage = (namespace: string, message: string): string => {\n return `[${namespace}] ${message}`;\n};\n\nexport const logger = {\n /**\n * Debug log - only shown when DEBUG=true\n */\n debug(namespace: string, message: string, ...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.log(formatMessage(namespace, message), ...args);\n }\n },\n\n /**\n * Info log - always shown\n */\n info(namespace: string, message: string, ...args: unknown[]): void {\n console.info(formatMessage(namespace, message), ...args);\n },\n\n /**\n * Warning log - always shown\n */\n warn(namespace: string, message: string, ...args: unknown[]): void {\n console.warn(formatMessage(namespace, message), ...args);\n },\n\n /**\n * Error log - always shown\n */\n error(namespace: string, message: string, ...args: unknown[]): void {\n console.error(formatMessage(namespace, message), ...args);\n },\n};\n\n/**\n * Create a namespaced logger for a specific module\n */\nexport const createLogger = (namespace: string) => ({\n debug: (message: string, ...args: unknown[]) => logger.debug(namespace, message, ...args),\n info: (message: string, ...args: unknown[]) => logger.info(namespace, message, ...args),\n warn: (message: string, ...args: unknown[]) => logger.warn(namespace, message, ...args),\n error: (message: string, ...args: unknown[]) => logger.error(namespace, message, ...args),\n});\n","import type { CookieStorage } from 'aws-amplify/adapter-core';\nimport type { AstroServer } from './types';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('cookie-storage-adapter');\n\n// Ensures the cookie names are encoded in order to look up the cookie store\n// that is manipulated by js-cookie on the client side.\n// Details of the js-cookie encoding behavior see:\n// https://github.com/js-cookie/js-cookie#encoding\n// The implementation is borrowed from js-cookie without escaping `[()]` as\n// we are not using those chars in the auth keys.\nfunction ensureEncodedForJSCookie(name: string): string {\n return encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent);\n}\n\nfunction parseCookieHeader(cookieHeader: string | null) {\n const out: Record<string, string> = {};\n if (!cookieHeader) return out;\n for (const part of cookieHeader.split(';')) {\n const [rawName, ...rest] = part.trim().split('=');\n const name = decodeURIComponent(rawName || '');\n const value = decodeURIComponent(rest.join('=') || '');\n if (name) out[name] = value;\n }\n return out;\n}\n\nfunction mapSameSite(\n s: CookieStorage.SetCookieOptions['sameSite']\n): 'lax' | 'strict' | 'none' | undefined {\n if (s === true) return 'strict';\n if (s === false) return 'lax';\n if (s === 'lax' || s === 'strict' || s === 'none') return s;\n return undefined;\n}\n\nexport async function createCookieStorageAdapterFromAstroContext(\n astroServerContext: AstroServer.ServerContext\n): Promise<CookieStorage.Adapter> {\n if (astroServerContext === null) {\n log.debug('Context is null, returning no-op adapter');\n return {\n get: () => undefined,\n getAll: () => [],\n set: () => {},\n delete: () => {},\n };\n }\n\n const { cookies, request } = astroServerContext;\n const cookieHeader = request?.headers?.get('cookie');\n const headerCookies = parseCookieHeader(cookieHeader ?? null);\n\n // Debug: Log available cookies (names only for security)\n const cookieNames = Object.keys(headerCookies);\n const cognitoCookies = cookieNames.filter(name => name.includes('CognitoIdentityServiceProvider'));\n log.debug('Available cookies:', cookieNames.length);\n log.debug('Cognito cookies found:', cognitoCookies.length);\n if (cognitoCookies.length > 0) {\n log.debug('Cognito cookie names:', cognitoCookies);\n }\n\n const adapter: CookieStorage.Adapter = {\n get(name) {\n const encodedName = ensureEncodedForJSCookie(name);\n const v = cookies?.get(encodedName)?.value ?? headerCookies[encodedName] ?? headerCookies[name];\n // Debug: Log token lookups (only for auth-related cookies)\n if (name.includes('accessToken') || name.includes('idToken') || name.includes('refreshToken') || name.includes('LastAuthUser')) {\n log.debug(`get('${name}'): ${v ? 'FOUND' : 'NOT FOUND'}`);\n }\n return v ? { name, value: v } : undefined;\n },\n getAll() {\n const fromAPI =\n (typeof (cookies as any)?.getAll === 'function'\n ? (cookies as any).getAll().map((c: any) => ({ name: c.name, value: c.value }))\n : Object.entries(headerCookies).map(([name, value]) => ({ name, value })));\n return fromAPI;\n },\n set(name, value, options) {\n try {\n (cookies as any).set(name, value, {\n ...(options ?? {}),\n sameSite: mapSameSite(options?.sameSite),\n });\n } catch {}\n },\n delete(name: string) {\n try {\n (cookies as any).delete(name);\n } catch {}\n },\n };\n\n return adapter;\n}\n"],"mappings":"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","names":["log","globalSettings"]}
1
+ {"version":3,"sources":["../../src/auth/index.ts","../../src/amplify-astro-adapter/createRunWithAmplifyServerContext.ts","../../src/amplify-astro-adapter/globalSettings.ts","../../src/utils/logger.ts","../../src/amplify-astro-adapter/createCookieStorageAdapterFromAstroContext.ts"],"sourcesContent":["/**\n * @htlkg/core/auth\n * Core authentication functions and utilities\n */\n\nimport type { APIContext } from \"astro\";\nimport { Amplify } from \"aws-amplify\";\nimport { fetchAuthSession } from \"aws-amplify/auth\";\nimport {\n\tfetchAuthSession as fetchServerAuthSession,\n\tgetCurrentUser as getServerCurrentUser,\n} from \"aws-amplify/auth/server\";\nimport { createRunWithAmplifyServerContext, globalSettings } from \"../amplify-astro-adapter\";\n\n// Re-export types\nexport type { APIContext } from \"astro\";\n\n/**\n * User interface representing an authenticated user\n */\nexport interface User {\n\tusername: string;\n\temail: string;\n\tbrandIds: number[];\n\taccountIds: number[];\n\tisAdmin: boolean;\n\tisSuperAdmin: boolean;\n\troles: string[];\n}\n\n/**\n * Parse comma-separated IDs from Cognito custom attributes\n */\nfunction parseIds(ids: string | undefined): number[] {\n\tif (!ids) return [];\n\treturn ids\n\t\t.split(\",\")\n\t\t.map((id) => Number.parseInt(id.trim(), 10))\n\t\t.filter((id) => !Number.isNaN(id));\n}\n\n// Track if Amplify has been configured\nlet amplifyConfigured = false;\n\n/**\n * Configure Amplify on first use (server-side)\n * This must be called before any auth operations\n */\nfunction ensureAmplifyConfigured(): void {\n\tif (amplifyConfigured) return;\n\n\ttry {\n\t\t// Amplify should already be configured by the middleware\n\t\t// This is just a safety check\n\t\tconst config = Amplify.getConfig();\n\t\tif (!config.Auth) {\n\t\t\tthrow new Error(\"Amplify Auth not configured\");\n\t\t}\n\t\tamplifyConfigured = true;\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : \"Unknown error\";\n\t\tconsole.error(`[Auth] Amplify not configured: ${errorMsg}`);\n\t\tthrow error;\n\t}\n}\n\n/**\n * Get current authenticated user (server-side)\n * Reads Amplify auth cookies from the request and validates the session\n */\nexport async function getUser(context: APIContext): Promise<User | null> {\n\ttry {\n\t\tensureAmplifyConfigured();\n\t\t\n\t\t// Get the current Amplify configuration\n\t\tconst amplifyConfig = Amplify.getConfig();\n\n\t\t// Create the server context runner - pass globalSettings explicitly\n\t\t// to ensure the same instance is used across all modules\n\t\tconst runWithAmplifyServerContext = createRunWithAmplifyServerContext({\n\t\t\tconfig: amplifyConfig,\n\t\t\tglobalSettings,\n\t\t});\n\n\t\t// Create Astro server context\n\t\tconst astroServerContext = {\n\t\t\tcookies: context.cookies,\n\t\t\trequest: context.request,\n\t\t};\n\n\t\t// Run in Amplify server context\n\t\tconst user = await runWithAmplifyServerContext({\n\t\t\tastroServerContext,\n\t\t\toperation: async (contextSpec) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst currentUser = await getServerCurrentUser(contextSpec as any);\n\t\t\t\t\tconst session = await fetchServerAuthSession(contextSpec as any);\n\n\t\t\t\t\tif (!session.tokens?.accessToken) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst accessPayload = session.tokens.accessToken.payload;\n\t\t\t\t\tconst idPayload = session.tokens.idToken?.payload;\n\n\t\t\t\t\t// Parse user attributes - email is typically in ID token, not access token\n\t\t\t\t\tconst email =\n\t\t\t\t\t\t(idPayload?.email as string) ||\n\t\t\t\t\t\t(accessPayload.email as string) ||\n\t\t\t\t\t\t\"\";\n\t\t\t\t\tconst brandIds = parseIds(\n\t\t\t\t\t\taccessPayload[\"custom:brand_ids\"] as string,\n\t\t\t\t\t);\n\t\t\t\t\tconst accountIds = parseIds(\n\t\t\t\t\t\taccessPayload[\"custom:account_ids\"] as string,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Check admin status\n\t\t\t\t\tconst groups = (accessPayload[\"cognito:groups\"] as string[]) || [];\n\t\t\t\t\tconst isAdmin =\n\t\t\t\t\t\tgroups.includes(\"admin\") ||\n\t\t\t\t\t\tgroups.includes(\"ADMINS\") ||\n\t\t\t\t\t\tgroups.includes(\"SUPER_ADMINS\");\n\t\t\t\t\tconst isSuperAdmin = groups.includes(\"SUPER_ADMINS\");\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tusername: currentUser.username,\n\t\t\t\t\t\temail,\n\t\t\t\t\t\tbrandIds,\n\t\t\t\t\t\taccountIds,\n\t\t\t\t\t\tisAdmin,\n\t\t\t\t\t\tisSuperAdmin,\n\t\t\t\t\t\troles: groups,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// UserUnAuthenticatedException is expected when user is not logged in\n\t\t\t\t\t// Only log other errors without sensitive data\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\terror.name !== \"UserUnAuthenticatedException\"\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Log error name and message without stack trace or sensitive data\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\"[Auth] Error in server context:\",\n\t\t\t\t\t\t\terror.name,\n\t\t\t\t\t\t\t\"-\",\n\t\t\t\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\treturn user;\n\t} catch (error) {\n\t\t// Log error without exposing sensitive information\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(\n\t\t\t\t\"[Auth] Server-side auth error:\",\n\t\t\t\terror.name,\n\t\t\t\t\"-\",\n\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.error(\"[Auth] Server-side auth error: Unknown error\");\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * Get current authenticated user (client-side)\n */\nexport async function getClientUser(): Promise<User | null> {\n\ttry {\n\t\tconst session = await fetchAuthSession();\n\n\t\tif (!session.tokens?.accessToken) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst accessPayload = session.tokens.accessToken.payload;\n\t\tconst idPayload = session.tokens.idToken?.payload;\n\n\t\tconst email =\n\t\t\t(idPayload?.email as string) || (accessPayload.email as string) || \"\";\n\t\tconst brandIds = parseIds(accessPayload[\"custom:brand_ids\"] as string);\n\t\tconst accountIds = parseIds(accessPayload[\"custom:account_ids\"] as string);\n\n\t\tconst groups = (accessPayload[\"cognito:groups\"] as string[]) || [];\n\t\tconst isAdmin =\n\t\t\tgroups.includes(\"admin\") ||\n\t\t\tgroups.includes(\"ADMINS\") ||\n\t\t\tgroups.includes(\"SUPER_ADMINS\");\n\t\tconst isSuperAdmin = groups.includes(\"SUPER_ADMINS\");\n\n\t\treturn {\n\t\t\tusername: (accessPayload.username as string) || \"\",\n\t\t\temail,\n\t\t\tbrandIds,\n\t\t\taccountIds,\n\t\t\tisAdmin,\n\t\t\tisSuperAdmin,\n\t\t\troles: groups,\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(\n\t\t\t\t\"[Auth] Client auth error:\",\n\t\t\t\terror.name,\n\t\t\t\t\"-\",\n\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t);\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * Check if user has access to a specific brand\n */\nexport function hasAccessToBrand(\n\tuser: User | null,\n\tbrandId: number,\n): boolean {\n\tif (!user) return false;\n\tif (user.isAdmin) return true;\n\treturn user.brandIds.includes(brandId);\n}\n\n/**\n * Check if user has access to a specific account\n */\nexport function hasAccessToAccount(\n\tuser: User | null,\n\taccountId: number,\n): boolean {\n\tif (!user) return false;\n\tif (user.isAdmin) return true;\n\treturn user.accountIds.includes(accountId);\n}\n\n/**\n * Check if user is an admin\n */\nexport function isAdminUser(user: User | null): boolean {\n\treturn user?.isAdmin || false;\n}\n\n/**\n * Check if user is a super admin\n */\nexport function isSuperAdminUser(user: User | null): boolean {\n\treturn user?.isSuperAdmin || false;\n}\n\n/**\n * Placeholder for requireAuth - will be implemented in @htlkg/integrations\n * This is here for type exports and documentation\n */\nexport async function requireAuth(\n\tcontext: APIContext,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireAuth should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Placeholder for requireAdminAccess - will be implemented in @htlkg/integrations\n */\nexport async function requireAdminAccess(\n\tcontext: APIContext,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireAdminAccess should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Placeholder for requireBrandAccess - will be implemented in @htlkg/integrations\n */\nexport async function requireBrandAccess(\n\tcontext: APIContext,\n\tbrandId: number,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireBrandAccess should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Sign out the current user (client-side)\n * With SSR mode enabled, Amplify automatically clears auth cookies\n */\nexport async function signOut(): Promise<void> {\n\ttry {\n\t\tconst { signOut: amplifySignOut } = await import(\"aws-amplify/auth\");\n\t\tawait amplifySignOut({ global: true });\n\t} catch (error) {\n\t\t// If Amplify signOut fails (e.g., not configured), clear cookies manually\n\t\tconsole.warn(\"[Auth] Amplify signOut failed, clearing cookies manually:\", error);\n\n\t\t// Clear all auth-related cookies by setting them to expire\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tconst cookies = document.cookie.split(\";\");\n\t\t\tfor (const cookie of cookies) {\n\t\t\t\tconst [name] = cookie.trim().split(\"=\");\n\t\t\t\tif (\n\t\t\t\t\tname.includes(\"CognitoIdentityServiceProvider\") ||\n\t\t\t\t\tname.includes(\"amplify\") ||\n\t\t\t\t\tname.includes(\"idToken\") ||\n\t\t\t\t\tname.includes(\"accessToken\") ||\n\t\t\t\t\tname.includes(\"refreshToken\")\n\t\t\t\t) {\n\t\t\t\t\tdocument.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { ResourcesConfig } from 'aws-amplify';\nimport { sharedInMemoryStorage } from 'aws-amplify/utils';\nimport {\n createAWSCredentialsAndIdentityIdProvider,\n createKeyValueStorageFromCookieStorageAdapter,\n createUserPoolsTokenProvider,\n runWithAmplifyServerContext as coreRunWithContext,\n} from 'aws-amplify/adapter-core';\n\nimport type { AstroServer } from './types';\nimport { globalSettings as defaultGlobalSettings } from './globalSettings';\nimport { createCookieStorageAdapterFromAstroContext } from './createCookieStorageAdapterFromAstroContext';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('amplify-server-context');\n\n/**\n * Creates a function that runs operations within the Amplify server context.\n *\n * IMPORTANT: Pass globalSettings explicitly to avoid module singleton issues\n * when using linked packages or different bundling contexts.\n */\nexport const createRunWithAmplifyServerContext = ({\n config: resourcesConfig,\n globalSettings = defaultGlobalSettings,\n}: {\n config: ResourcesConfig;\n globalSettings?: AstroServer.GlobalSettings;\n}): AstroServer.RunOperationWithContext => {\n const isServerSideAuthEnabled = globalSettings.isServerSideAuthEnabled();\n const isSSLOrigin = globalSettings.isSSLOrigin();\n const setCookieOptions = globalSettings.getRuntimeOptions().cookies ?? {};\n\n log.debug('Settings:', {\n isServerSideAuthEnabled,\n isSSLOrigin,\n hasCookieOptions: Object.keys(setCookieOptions).length > 0,\n });\n \n const mergedSetCookieOptions = {\n ...(isServerSideAuthEnabled && { httpOnly: true, sameSite: 'lax' as const }),\n ...setCookieOptions,\n ...(isServerSideAuthEnabled && { secure: isSSLOrigin }),\n path: '/',\n };\n\n const runWithContext: AstroServer.RunOperationWithContext = async ({\n astroServerContext,\n operation,\n }) => {\n if (resourcesConfig.Auth) {\n const cookieAdapter = await createCookieStorageAdapterFromAstroContext(astroServerContext);\n \n const keyValueStorage =\n astroServerContext === null\n ? sharedInMemoryStorage\n : createKeyValueStorageFromCookieStorageAdapter(\n cookieAdapter,\n undefined,\n mergedSetCookieOptions\n );\n\n const credentialsProvider = createAWSCredentialsAndIdentityIdProvider(\n resourcesConfig.Auth,\n keyValueStorage\n );\n \n const tokenProvider = createUserPoolsTokenProvider(\n resourcesConfig.Auth,\n keyValueStorage\n );\n\n return coreRunWithContext(\n resourcesConfig,\n { Auth: { credentialsProvider, tokenProvider } },\n operation\n );\n }\n\n return coreRunWithContext(resourcesConfig, {}, operation);\n };\n\n return runWithContext;\n};\n","import type { AstroServer } from './types';\n\nexport const globalSettings: AstroServer.GlobalSettings = (() => {\n let runtimeOptions: AstroServer.RuntimeOptions = {};\n let serverSideAuthEnabled = true;\n let sslOrigin = false;\n\n return {\n setRuntimeOptions(opts) { runtimeOptions = opts ?? {}; },\n getRuntimeOptions() { return runtimeOptions; },\n enableServerSideAuth() { serverSideAuthEnabled = true; },\n isServerSideAuthEnabled() { return serverSideAuthEnabled; },\n setIsSSLOrigin(v: boolean) { sslOrigin = v; },\n isSSLOrigin() { return sslOrigin; },\n };\n})();\n","/**\n * Simple debug logger utility\n * \n * Debug logs are only shown when DEBUG=true or HTLKG_DEBUG=true is set in environment.\n * Info logs are always shown.\n * \n * @example\n * ```typescript\n * import { logger } from '@htlkg/core/utils/logger';\n * \n * logger.debug('server-client', 'Detailed debug info', { data });\n * logger.info('server-client', 'Important info message');\n * logger.warn('server-client', 'Warning message');\n * logger.error('server-client', 'Error occurred', error);\n * ```\n */\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst isDebugEnabled = (): boolean => {\n // Check Node.js environment variables\n if (typeof process !== 'undefined' && process.env) {\n return process.env.DEBUG === 'true' || \n process.env.HTLKG_DEBUG === 'true' ||\n process.env.DEBUG === '*';\n }\n // Browser/Vite environment - check for DEV mode\n try {\n // @ts-ignore - import.meta.env is Vite-specific\n if (typeof import.meta !== 'undefined' && import.meta.env) {\n // @ts-ignore\n return import.meta.env.DEBUG === 'true' || \n // @ts-ignore\n import.meta.env.HTLKG_DEBUG === 'true' ||\n // @ts-ignore\n import.meta.env.DEV === true;\n }\n } catch {\n // Ignore errors accessing import.meta\n }\n return false;\n};\n\nconst formatMessage = (namespace: string, message: string): string => {\n return `[${namespace}] ${message}`;\n};\n\nexport const logger = {\n /**\n * Debug log - only shown when DEBUG=true\n */\n debug(namespace: string, message: string, ...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.log(formatMessage(namespace, message), ...args);\n }\n },\n\n /**\n * Info log - always shown\n */\n info(namespace: string, message: string, ...args: unknown[]): void {\n console.info(formatMessage(namespace, message), ...args);\n },\n\n /**\n * Warning log - always shown\n */\n warn(namespace: string, message: string, ...args: unknown[]): void {\n console.warn(formatMessage(namespace, message), ...args);\n },\n\n /**\n * Error log - always shown\n */\n error(namespace: string, message: string, ...args: unknown[]): void {\n console.error(formatMessage(namespace, message), ...args);\n },\n};\n\n/**\n * Create a namespaced logger for a specific module\n */\nexport const createLogger = (namespace: string) => ({\n debug: (message: string, ...args: unknown[]) => logger.debug(namespace, message, ...args),\n info: (message: string, ...args: unknown[]) => logger.info(namespace, message, ...args),\n warn: (message: string, ...args: unknown[]) => logger.warn(namespace, message, ...args),\n error: (message: string, ...args: unknown[]) => logger.error(namespace, message, ...args),\n});\n","import type { CookieStorage } from 'aws-amplify/adapter-core';\nimport type { AstroServer } from './types';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('cookie-storage-adapter');\n\n// Ensures the cookie names are encoded in order to look up the cookie store\n// that is manipulated by js-cookie on the client side.\n// Details of the js-cookie encoding behavior see:\n// https://github.com/js-cookie/js-cookie#encoding\n// The implementation is borrowed from js-cookie without escaping `[()]` as\n// we are not using those chars in the auth keys.\nfunction ensureEncodedForJSCookie(name: string): string {\n return encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent);\n}\n\nfunction parseCookieHeader(cookieHeader: string | null) {\n const out: Record<string, string> = {};\n if (!cookieHeader) return out;\n for (const part of cookieHeader.split(';')) {\n const [rawName, ...rest] = part.trim().split('=');\n const name = decodeURIComponent(rawName || '');\n const value = decodeURIComponent(rest.join('=') || '');\n if (name) out[name] = value;\n }\n return out;\n}\n\nfunction mapSameSite(\n s: CookieStorage.SetCookieOptions['sameSite']\n): 'lax' | 'strict' | 'none' | undefined {\n if (s === true) return 'strict';\n if (s === false) return 'lax';\n if (s === 'lax' || s === 'strict' || s === 'none') return s;\n return undefined;\n}\n\nexport async function createCookieStorageAdapterFromAstroContext(\n astroServerContext: AstroServer.ServerContext\n): Promise<CookieStorage.Adapter> {\n if (astroServerContext === null) {\n log.debug('Context is null, returning no-op adapter');\n return {\n get: () => undefined,\n getAll: () => [],\n set: () => {},\n delete: () => {},\n };\n }\n\n const { cookies, request } = astroServerContext;\n const cookieHeader = request?.headers?.get('cookie');\n const headerCookies = parseCookieHeader(cookieHeader ?? null);\n\n // Debug: Log available cookies (names only for security)\n const cookieNames = Object.keys(headerCookies);\n const cognitoCookies = cookieNames.filter(name => name.includes('CognitoIdentityServiceProvider'));\n log.debug('Available cookies:', cookieNames.length);\n log.debug('Cognito cookies found:', cognitoCookies.length);\n if (cognitoCookies.length > 0) {\n log.debug('Cognito cookie names:', cognitoCookies);\n }\n\n const adapter: CookieStorage.Adapter = {\n get(name) {\n const encodedName = ensureEncodedForJSCookie(name);\n const v = cookies?.get(encodedName)?.value ?? headerCookies[encodedName] ?? headerCookies[name];\n // Debug: Log token lookups (only for auth-related cookies)\n if (name.includes('accessToken') || name.includes('idToken') || name.includes('refreshToken') || name.includes('LastAuthUser')) {\n log.debug(`get('${name}'): ${v ? 'FOUND' : 'NOT FOUND'}`);\n }\n return v ? { name, value: v } : undefined;\n },\n getAll() {\n const fromAPI =\n (typeof (cookies as any)?.getAll === 'function'\n ? (cookies as any).getAll().map((c: any) => ({ name: c.name, value: c.value }))\n : Object.entries(headerCookies).map(([name, value]) => ({ name, value })));\n return fromAPI;\n },\n set(name, value, options) {\n try {\n (cookies as any).set(name, value, {\n ...(options ?? {}),\n sameSite: mapSameSite(options?.sameSite),\n });\n } catch {}\n },\n delete(name: string) {\n try {\n (cookies as any).delete(name);\n } catch {}\n },\n };\n\n return adapter;\n}\n"],"mappings":"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","names":["log","globalSettings"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/auth/index.ts","../src/amplify-astro-adapter/createRunWithAmplifyServerContext.ts","../src/amplify-astro-adapter/globalSettings.ts","../src/utils/logger.ts","../src/amplify-astro-adapter/createCookieStorageAdapterFromAstroContext.ts","../src/utils/index.ts","../src/constants/index.ts","../src/errors/index.ts","../src/routes/index.ts"],"sourcesContent":["/**\n * @htlkg/core/auth\n * Core authentication functions and utilities\n */\n\nimport type { APIContext } from \"astro\";\nimport { Amplify } from \"aws-amplify\";\nimport { fetchAuthSession } from \"aws-amplify/auth\";\nimport {\n\tfetchAuthSession as fetchServerAuthSession,\n\tgetCurrentUser as getServerCurrentUser,\n} from \"aws-amplify/auth/server\";\nimport { createRunWithAmplifyServerContext, globalSettings } from \"../amplify-astro-adapter\";\n\n// Re-export types\nexport type { APIContext } from \"astro\";\n\n/**\n * User interface representing an authenticated user\n */\nexport interface User {\n\tusername: string;\n\temail: string;\n\tbrandIds: number[];\n\taccountIds: number[];\n\tisAdmin: boolean;\n\tisSuperAdmin: boolean;\n\troles: string[];\n}\n\n/**\n * Parse comma-separated IDs from Cognito custom attributes\n */\nfunction parseIds(ids: string | undefined): number[] {\n\tif (!ids) return [];\n\treturn ids\n\t\t.split(\",\")\n\t\t.map((id) => Number.parseInt(id.trim(), 10))\n\t\t.filter((id) => !Number.isNaN(id));\n}\n\n// Track if Amplify has been configured\nlet amplifyConfigured = false;\n\n/**\n * Configure Amplify on first use (server-side)\n * This must be called before any auth operations\n */\nfunction ensureAmplifyConfigured(): void {\n\tif (amplifyConfigured) return;\n\n\ttry {\n\t\t// Amplify should already be configured by the middleware\n\t\t// This is just a safety check\n\t\tconst config = Amplify.getConfig();\n\t\tif (!config.Auth) {\n\t\t\tthrow new Error(\"Amplify Auth not configured\");\n\t\t}\n\t\tamplifyConfigured = true;\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : \"Unknown error\";\n\t\tconsole.error(`[Auth] Amplify not configured: ${errorMsg}`);\n\t\tthrow error;\n\t}\n}\n\n/**\n * Get current authenticated user (server-side)\n * Reads Amplify auth cookies from the request and validates the session\n */\nexport async function getUser(context: APIContext): Promise<User | null> {\n\ttry {\n\t\tensureAmplifyConfigured();\n\t\t\n\t\t// Get the current Amplify configuration\n\t\tconst amplifyConfig = Amplify.getConfig();\n\n\t\t// Create the server context runner - pass globalSettings explicitly\n\t\t// to ensure the same instance is used across all modules\n\t\tconst runWithAmplifyServerContext = createRunWithAmplifyServerContext({\n\t\t\tconfig: amplifyConfig,\n\t\t\tglobalSettings,\n\t\t});\n\n\t\t// Create Astro server context\n\t\tconst astroServerContext = {\n\t\t\tcookies: context.cookies,\n\t\t\trequest: context.request,\n\t\t};\n\n\t\t// Run in Amplify server context\n\t\tconst user = await runWithAmplifyServerContext({\n\t\t\tastroServerContext,\n\t\t\toperation: async (contextSpec) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst currentUser = await getServerCurrentUser(contextSpec as any);\n\t\t\t\t\tconst session = await fetchServerAuthSession(contextSpec as any);\n\n\t\t\t\t\tif (!session.tokens?.accessToken) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst accessPayload = session.tokens.accessToken.payload;\n\t\t\t\t\tconst idPayload = session.tokens.idToken?.payload;\n\n\t\t\t\t\t// Parse user attributes - email is typically in ID token, not access token\n\t\t\t\t\tconst email =\n\t\t\t\t\t\t(idPayload?.email as string) ||\n\t\t\t\t\t\t(accessPayload.email as string) ||\n\t\t\t\t\t\t\"\";\n\t\t\t\t\tconst brandIds = parseIds(\n\t\t\t\t\t\taccessPayload[\"custom:brand_ids\"] as string,\n\t\t\t\t\t);\n\t\t\t\t\tconst accountIds = parseIds(\n\t\t\t\t\t\taccessPayload[\"custom:account_ids\"] as string,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Check admin status\n\t\t\t\t\tconst groups = (accessPayload[\"cognito:groups\"] as string[]) || [];\n\t\t\t\t\tconst isAdmin =\n\t\t\t\t\t\tgroups.includes(\"admin\") ||\n\t\t\t\t\t\tgroups.includes(\"ADMINS\") ||\n\t\t\t\t\t\tgroups.includes(\"SUPER_ADMINS\");\n\t\t\t\t\tconst isSuperAdmin = groups.includes(\"SUPER_ADMINS\");\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tusername: currentUser.username,\n\t\t\t\t\t\temail,\n\t\t\t\t\t\tbrandIds,\n\t\t\t\t\t\taccountIds,\n\t\t\t\t\t\tisAdmin,\n\t\t\t\t\t\tisSuperAdmin,\n\t\t\t\t\t\troles: groups,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// UserUnAuthenticatedException is expected when user is not logged in\n\t\t\t\t\t// Only log other errors without sensitive data\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\terror.name !== \"UserUnAuthenticatedException\"\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Log error name and message without stack trace or sensitive data\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\"[Auth] Error in server context:\",\n\t\t\t\t\t\t\terror.name,\n\t\t\t\t\t\t\t\"-\",\n\t\t\t\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\treturn user;\n\t} catch (error) {\n\t\t// Log error without exposing sensitive information\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(\n\t\t\t\t\"[Auth] Server-side auth error:\",\n\t\t\t\terror.name,\n\t\t\t\t\"-\",\n\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.error(\"[Auth] Server-side auth error: Unknown error\");\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * Get current authenticated user (client-side)\n */\nexport async function getClientUser(): Promise<User | null> {\n\ttry {\n\t\tconst session = await fetchAuthSession();\n\n\t\tif (!session.tokens?.accessToken) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst accessPayload = session.tokens.accessToken.payload;\n\t\tconst idPayload = session.tokens.idToken?.payload;\n\n\t\tconst email =\n\t\t\t(idPayload?.email as string) || (accessPayload.email as string) || \"\";\n\t\tconst brandIds = parseIds(accessPayload[\"custom:brand_ids\"] as string);\n\t\tconst accountIds = parseIds(accessPayload[\"custom:account_ids\"] as string);\n\n\t\tconst groups = (accessPayload[\"cognito:groups\"] as string[]) || [];\n\t\tconst isAdmin =\n\t\t\tgroups.includes(\"admin\") ||\n\t\t\tgroups.includes(\"ADMINS\") ||\n\t\t\tgroups.includes(\"SUPER_ADMINS\");\n\t\tconst isSuperAdmin = groups.includes(\"SUPER_ADMINS\");\n\n\t\treturn {\n\t\t\tusername: (accessPayload.username as string) || \"\",\n\t\t\temail,\n\t\t\tbrandIds,\n\t\t\taccountIds,\n\t\t\tisAdmin,\n\t\t\tisSuperAdmin,\n\t\t\troles: groups,\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(\n\t\t\t\t\"[Auth] Client auth error:\",\n\t\t\t\terror.name,\n\t\t\t\t\"-\",\n\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t);\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * Check if user has access to a specific brand\n */\nexport function hasAccessToBrand(\n\tuser: User | null,\n\tbrandId: number,\n): boolean {\n\tif (!user) return false;\n\tif (user.isAdmin) return true;\n\treturn user.brandIds.includes(brandId);\n}\n\n/**\n * Check if user has access to a specific account\n */\nexport function hasAccessToAccount(\n\tuser: User | null,\n\taccountId: number,\n): boolean {\n\tif (!user) return false;\n\tif (user.isAdmin) return true;\n\treturn user.accountIds.includes(accountId);\n}\n\n/**\n * Check if user is an admin\n */\nexport function isAdminUser(user: User | null): boolean {\n\treturn user?.isAdmin || false;\n}\n\n/**\n * Check if user is a super admin\n */\nexport function isSuperAdminUser(user: User | null): boolean {\n\treturn user?.isSuperAdmin || false;\n}\n\n/**\n * Placeholder for requireAuth - will be implemented in @htlkg/integrations\n * This is here for type exports and documentation\n */\nexport async function requireAuth(\n\tcontext: APIContext,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireAuth should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Placeholder for requireAdminAccess - will be implemented in @htlkg/integrations\n */\nexport async function requireAdminAccess(\n\tcontext: APIContext,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireAdminAccess should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Placeholder for requireBrandAccess - will be implemented in @htlkg/integrations\n */\nexport async function requireBrandAccess(\n\tcontext: APIContext,\n\tbrandId: number,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireBrandAccess should be imported from @htlkg/astro/middleware\",\n\t);\n}\n","import type { ResourcesConfig } from 'aws-amplify';\nimport { sharedInMemoryStorage } from 'aws-amplify/utils';\nimport {\n createAWSCredentialsAndIdentityIdProvider,\n createKeyValueStorageFromCookieStorageAdapter,\n createUserPoolsTokenProvider,\n runWithAmplifyServerContext as coreRunWithContext,\n} from 'aws-amplify/adapter-core';\n\nimport type { AstroServer } from './types';\nimport { globalSettings as defaultGlobalSettings } from './globalSettings';\nimport { createCookieStorageAdapterFromAstroContext } from './createCookieStorageAdapterFromAstroContext';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('amplify-server-context');\n\n/**\n * Creates a function that runs operations within the Amplify server context.\n *\n * IMPORTANT: Pass globalSettings explicitly to avoid module singleton issues\n * when using linked packages or different bundling contexts.\n */\nexport const createRunWithAmplifyServerContext = ({\n config: resourcesConfig,\n globalSettings = defaultGlobalSettings,\n}: {\n config: ResourcesConfig;\n globalSettings?: AstroServer.GlobalSettings;\n}): AstroServer.RunOperationWithContext => {\n const isServerSideAuthEnabled = globalSettings.isServerSideAuthEnabled();\n const isSSLOrigin = globalSettings.isSSLOrigin();\n const setCookieOptions = globalSettings.getRuntimeOptions().cookies ?? {};\n\n log.debug('Settings:', {\n isServerSideAuthEnabled,\n isSSLOrigin,\n hasCookieOptions: Object.keys(setCookieOptions).length > 0,\n });\n \n const mergedSetCookieOptions = {\n ...(isServerSideAuthEnabled && { httpOnly: true, sameSite: 'lax' as const }),\n ...setCookieOptions,\n ...(isServerSideAuthEnabled && { secure: isSSLOrigin }),\n path: '/',\n };\n\n const runWithContext: AstroServer.RunOperationWithContext = async ({\n astroServerContext,\n operation,\n }) => {\n if (resourcesConfig.Auth) {\n const cookieAdapter = await createCookieStorageAdapterFromAstroContext(astroServerContext);\n \n const keyValueStorage =\n astroServerContext === null\n ? sharedInMemoryStorage\n : createKeyValueStorageFromCookieStorageAdapter(\n cookieAdapter,\n undefined,\n mergedSetCookieOptions\n );\n\n const credentialsProvider = createAWSCredentialsAndIdentityIdProvider(\n resourcesConfig.Auth,\n keyValueStorage\n );\n \n const tokenProvider = createUserPoolsTokenProvider(\n resourcesConfig.Auth,\n keyValueStorage\n );\n\n return coreRunWithContext(\n resourcesConfig,\n { Auth: { credentialsProvider, tokenProvider } },\n operation\n );\n }\n\n return coreRunWithContext(resourcesConfig, {}, operation);\n };\n\n return runWithContext;\n};\n","import type { AstroServer } from './types';\n\nexport const globalSettings: AstroServer.GlobalSettings = (() => {\n let runtimeOptions: AstroServer.RuntimeOptions = {};\n let serverSideAuthEnabled = true;\n let sslOrigin = false;\n\n return {\n setRuntimeOptions(opts) { runtimeOptions = opts ?? {}; },\n getRuntimeOptions() { return runtimeOptions; },\n enableServerSideAuth() { serverSideAuthEnabled = true; },\n isServerSideAuthEnabled() { return serverSideAuthEnabled; },\n setIsSSLOrigin(v: boolean) { sslOrigin = v; },\n isSSLOrigin() { return sslOrigin; },\n };\n})();\n","/**\n * Simple debug logger utility\n * \n * Debug logs are only shown when DEBUG=true or HTLKG_DEBUG=true is set in environment.\n * Info logs are always shown.\n * \n * @example\n * ```typescript\n * import { logger } from '@htlkg/core/utils/logger';\n * \n * logger.debug('server-client', 'Detailed debug info', { data });\n * logger.info('server-client', 'Important info message');\n * logger.warn('server-client', 'Warning message');\n * logger.error('server-client', 'Error occurred', error);\n * ```\n */\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst isDebugEnabled = (): boolean => {\n // Check Node.js environment variables\n if (typeof process !== 'undefined' && process.env) {\n return process.env.DEBUG === 'true' || \n process.env.HTLKG_DEBUG === 'true' ||\n process.env.DEBUG === '*';\n }\n // Browser/Vite environment - check for DEV mode\n try {\n // @ts-ignore - import.meta.env is Vite-specific\n if (typeof import.meta !== 'undefined' && import.meta.env) {\n // @ts-ignore\n return import.meta.env.DEBUG === 'true' || \n // @ts-ignore\n import.meta.env.HTLKG_DEBUG === 'true' ||\n // @ts-ignore\n import.meta.env.DEV === true;\n }\n } catch {\n // Ignore errors accessing import.meta\n }\n return false;\n};\n\nconst formatMessage = (namespace: string, message: string): string => {\n return `[${namespace}] ${message}`;\n};\n\nexport const logger = {\n /**\n * Debug log - only shown when DEBUG=true\n */\n debug(namespace: string, message: string, ...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.log(formatMessage(namespace, message), ...args);\n }\n },\n\n /**\n * Info log - always shown\n */\n info(namespace: string, message: string, ...args: unknown[]): void {\n console.info(formatMessage(namespace, message), ...args);\n },\n\n /**\n * Warning log - always shown\n */\n warn(namespace: string, message: string, ...args: unknown[]): void {\n console.warn(formatMessage(namespace, message), ...args);\n },\n\n /**\n * Error log - always shown\n */\n error(namespace: string, message: string, ...args: unknown[]): void {\n console.error(formatMessage(namespace, message), ...args);\n },\n};\n\n/**\n * Create a namespaced logger for a specific module\n */\nexport const createLogger = (namespace: string) => ({\n debug: (message: string, ...args: unknown[]) => logger.debug(namespace, message, ...args),\n info: (message: string, ...args: unknown[]) => logger.info(namespace, message, ...args),\n warn: (message: string, ...args: unknown[]) => logger.warn(namespace, message, ...args),\n error: (message: string, ...args: unknown[]) => logger.error(namespace, message, ...args),\n});\n","import type { CookieStorage } from 'aws-amplify/adapter-core';\nimport type { AstroServer } from './types';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('cookie-storage-adapter');\n\n// Ensures the cookie names are encoded in order to look up the cookie store\n// that is manipulated by js-cookie on the client side.\n// Details of the js-cookie encoding behavior see:\n// https://github.com/js-cookie/js-cookie#encoding\n// The implementation is borrowed from js-cookie without escaping `[()]` as\n// we are not using those chars in the auth keys.\nfunction ensureEncodedForJSCookie(name: string): string {\n return encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent);\n}\n\nfunction parseCookieHeader(cookieHeader: string | null) {\n const out: Record<string, string> = {};\n if (!cookieHeader) return out;\n for (const part of cookieHeader.split(';')) {\n const [rawName, ...rest] = part.trim().split('=');\n const name = decodeURIComponent(rawName || '');\n const value = decodeURIComponent(rest.join('=') || '');\n if (name) out[name] = value;\n }\n return out;\n}\n\nfunction mapSameSite(\n s: CookieStorage.SetCookieOptions['sameSite']\n): 'lax' | 'strict' | 'none' | undefined {\n if (s === true) return 'strict';\n if (s === false) return 'lax';\n if (s === 'lax' || s === 'strict' || s === 'none') return s;\n return undefined;\n}\n\nexport async function createCookieStorageAdapterFromAstroContext(\n astroServerContext: AstroServer.ServerContext\n): Promise<CookieStorage.Adapter> {\n if (astroServerContext === null) {\n log.debug('Context is null, returning no-op adapter');\n return {\n get: () => undefined,\n getAll: () => [],\n set: () => {},\n delete: () => {},\n };\n }\n\n const { cookies, request } = astroServerContext;\n const cookieHeader = request?.headers?.get('cookie');\n const headerCookies = parseCookieHeader(cookieHeader ?? null);\n\n // Debug: Log available cookies (names only for security)\n const cookieNames = Object.keys(headerCookies);\n const cognitoCookies = cookieNames.filter(name => name.includes('CognitoIdentityServiceProvider'));\n log.debug('Available cookies:', cookieNames.length);\n log.debug('Cognito cookies found:', cognitoCookies.length);\n if (cognitoCookies.length > 0) {\n log.debug('Cognito cookie names:', cognitoCookies);\n }\n\n const adapter: CookieStorage.Adapter = {\n get(name) {\n const encodedName = ensureEncodedForJSCookie(name);\n const v = cookies?.get(encodedName)?.value ?? headerCookies[encodedName] ?? headerCookies[name];\n // Debug: Log token lookups (only for auth-related cookies)\n if (name.includes('accessToken') || name.includes('idToken') || name.includes('refreshToken') || name.includes('LastAuthUser')) {\n log.debug(`get('${name}'): ${v ? 'FOUND' : 'NOT FOUND'}`);\n }\n return v ? { name, value: v } : undefined;\n },\n getAll() {\n const fromAPI =\n (typeof (cookies as any)?.getAll === 'function'\n ? (cookies as any).getAll().map((c: any) => ({ name: c.name, value: c.value }))\n : Object.entries(headerCookies).map(([name, value]) => ({ name, value })));\n return fromAPI;\n },\n set(name, value, options) {\n try {\n (cookies as any).set(name, value, {\n ...(options ?? {}),\n sameSite: mapSameSite(options?.sameSite),\n });\n } catch {}\n },\n delete(name: string) {\n try {\n (cookies as any).delete(name);\n } catch {}\n },\n };\n\n return adapter;\n}\n","/**\n * @htlkg/core/utils\n * Core utility functions for Hotelinking applications\n */\n\n// Logger utility\nexport { logger, createLogger } from './logger';\n\n/**\n * Format a date to a localized string\n * @param date - Date to format\n * @param locale - Locale string (default: 'en-US')\n * @param options - Intl.DateTimeFormatOptions\n * @returns Formatted date string\n */\nexport function formatDate(\n\tdate: Date | string | number,\n\tlocale = \"en-US\",\n\toptions: Intl.DateTimeFormatOptions = {\n\t\tyear: \"numeric\",\n\t\tmonth: \"short\",\n\t\tday: \"numeric\",\n\t},\n): string {\n\tconst dateObj = typeof date === \"string\" || typeof date === \"number\" ? new Date(date) : date;\n\treturn new Intl.DateTimeFormat(locale, options).format(dateObj);\n}\n\n/**\n * Truncate text to a maximum length with ellipsis\n * @param text - Text to truncate\n * @param maxLength - Maximum length before truncation\n * @param suffix - Suffix to append (default: '...')\n * @returns Truncated text\n */\nexport function truncateText(\n\ttext: string,\n\tmaxLength: number,\n\tsuffix = \"...\",\n): string {\n\tif (text.length <= maxLength) return text;\n\treturn text.slice(0, maxLength - suffix.length) + suffix;\n}\n\n/**\n * Group an array of items by a key\n * @param items - Array of items to group\n * @param keyFn - Function to extract the grouping key\n * @returns Object with keys as group names and values as arrays of items\n */\nexport function groupBy<T>(\n\titems: T[],\n\tkeyFn: (item: T) => string | number,\n): Record<string | number, T[]> {\n\treturn items.reduce(\n\t\t(groups, item) => {\n\t\t\tconst key = keyFn(item);\n\t\t\tif (!groups[key]) {\n\t\t\t\tgroups[key] = [];\n\t\t\t}\n\t\t\tgroups[key].push(item);\n\t\t\treturn groups;\n\t\t},\n\t\t{} as Record<string | number, T[]>,\n\t);\n}\n\n/**\n * Debounce a function call\n * @param fn - Function to debounce\n * @param delay - Delay in milliseconds\n * @returns Debounced function\n */\nexport function debounce<T extends (...args: any[]) => any>(\n\tfn: T,\n\tdelay: number,\n): (...args: Parameters<T>) => void {\n\tlet timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n\treturn function debounced(...args: Parameters<T>) {\n\t\tif (timeoutId !== null) {\n\t\t\tclearTimeout(timeoutId);\n\t\t}\n\t\ttimeoutId = setTimeout(() => {\n\t\t\tfn(...args);\n\t\t\ttimeoutId = null;\n\t\t}, delay);\n\t};\n}\n\n/**\n * Throttle a function call\n * @param fn - Function to throttle\n * @param limit - Minimum time between calls in milliseconds\n * @returns Throttled function\n */\nexport function throttle<T extends (...args: any[]) => any>(\n\tfn: T,\n\tlimit: number,\n): (...args: Parameters<T>) => void {\n\tlet inThrottle = false;\n\n\treturn function throttled(...args: Parameters<T>) {\n\t\tif (!inThrottle) {\n\t\t\tfn(...args);\n\t\t\tinThrottle = true;\n\t\t\tsetTimeout(() => {\n\t\t\t\tinThrottle = false;\n\t\t\t}, limit);\n\t\t}\n\t};\n}\n\n/**\n * Get current timestamp in ISO 8601 format\n * Useful for audit trails, logging, and database timestamps\n * @returns Current timestamp as ISO string (e.g., \"2024-01-15T10:30:00.000Z\")\n */\nexport function getCurrentTimestamp(): string {\n\treturn new Date().toISOString();\n}\n","/**\n * @htlkg/core/constants\n * Core constants for Hotelinking applications\n */\n\n/**\n * Application routes\n */\nexport const ROUTES = {\n\t// Admin routes\n\tADMIN: {\n\t\tHOME: \"/admin\",\n\t\tBRANDS: \"/admin/brands\",\n\t\tACCOUNTS: \"/admin/accounts\",\n\t\tUSERS: \"/admin/users\",\n\t\tPRODUCTS: \"/admin/products\",\n\t\tSETTINGS: \"/admin/settings\",\n\t},\n\t// Brand routes\n\tBRAND: {\n\t\tHOME: (brandId: string) => `/${brandId}`,\n\t\tADMIN: (brandId: string) => `/${brandId}/admin`,\n\t\tTEMPLATES: (brandId: string) => `/${brandId}/admin/templates`,\n\t\tSETTINGS: (brandId: string) => `/${brandId}/admin/settings`,\n\t},\n\t// Auth routes\n\tAUTH: {\n\t\tLOGIN: \"/login\",\n\t\tLOGOUT: \"/logout\",\n\t\tSIGNUP: \"/signup\",\n\t\tFORGOT_PASSWORD: \"/forgot-password\",\n\t},\n} as const;\n\n/**\n * Product definitions\n */\nexport const PRODUCTS = {\n\tWIFI_PORTAL: {\n\t\tid: \"wifi-portal\",\n\t\tname: \"WiFi Portal\",\n\t\tdescription: \"Captive portal for WiFi authentication\",\n\t},\n\tWHATSAPP_CRM: {\n\t\tid: \"whatsapp-crm\",\n\t\tname: \"WhatsApp CRM\",\n\t\tdescription: \"WhatsApp integration for customer relationship management\",\n\t},\n\tANALYTICS: {\n\t\tid: \"analytics\",\n\t\tname: \"Analytics\",\n\t\tdescription: \"Analytics and reporting dashboard\",\n\t},\n} as const;\n\n/**\n * Permission definitions\n */\nexport const PERMISSIONS = {\n\t// Brand permissions\n\tBRAND_VIEW: \"brand:view\",\n\tBRAND_EDIT: \"brand:edit\",\n\tBRAND_DELETE: \"brand:delete\",\n\tBRAND_CREATE: \"brand:create\",\n\n\t// Account permissions\n\tACCOUNT_VIEW: \"account:view\",\n\tACCOUNT_EDIT: \"account:edit\",\n\tACCOUNT_DELETE: \"account:delete\",\n\tACCOUNT_CREATE: \"account:create\",\n\n\t// User permissions\n\tUSER_VIEW: \"user:view\",\n\tUSER_EDIT: \"user:edit\",\n\tUSER_DELETE: \"user:delete\",\n\tUSER_CREATE: \"user:create\",\n\n\t// Product permissions\n\tPRODUCT_VIEW: \"product:view\",\n\tPRODUCT_EDIT: \"product:edit\",\n\tPRODUCT_ENABLE: \"product:enable\",\n\tPRODUCT_DISABLE: \"product:disable\",\n\n\t// Admin permissions\n\tADMIN_ACCESS: \"admin:access\",\n\tSUPER_ADMIN_ACCESS: \"super_admin:access\",\n} as const;\n\n/**\n * User role definitions\n */\nexport const USER_ROLES = {\n\tSUPER_ADMIN: \"SUPER_ADMINS\",\n\tADMIN: \"ADMINS\",\n\tBRAND_ADMIN: \"BRAND_ADMINS\",\n\tBRAND_USER: \"BRAND_USERS\",\n\tUSER: \"USERS\",\n} as const;\n","/**\n * @htlkg/core/errors\n * Core error classes for Hotelinking applications\n */\n\n/**\n * Base application error class\n */\nexport class AppError extends Error {\n\tpublic readonly code: string;\n\tpublic readonly statusCode: number;\n\tpublic readonly details?: Record<string, any>;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tcode = \"APP_ERROR\",\n\t\tstatusCode = 500,\n\t\tdetails?: Record<string, any>,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"AppError\";\n\t\tthis.code = code;\n\t\tthis.statusCode = statusCode;\n\t\tthis.details = details;\n\n\t\t// Maintains proper stack trace for where our error was thrown (only available on V8)\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, AppError);\n\t\t}\n\t}\n\n\t/**\n\t * Convert error to JSON representation\n\t */\n\ttoJSON(): Record<string, any> {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t\tcode: this.code,\n\t\t\tstatusCode: this.statusCode,\n\t\t\tdetails: this.details,\n\t\t};\n\t}\n}\n\n/**\n * Authentication error class\n */\nexport class AuthError extends AppError {\n\tconstructor(\n\t\tmessage: string,\n\t\tcode = \"AUTH_ERROR\",\n\t\tstatusCode = 401,\n\t\tdetails?: Record<string, any>,\n\t) {\n\t\tsuper(message, code, statusCode, details);\n\t\tthis.name = \"AuthError\";\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, AuthError);\n\t\t}\n\t}\n}\n\n/**\n * Validation error class\n */\nexport class ValidationError extends AppError {\n\tpublic readonly errors: Array<{ field: string; message: string }>;\n\n\tconstructor(\n\t\tmessage: string,\n\t\terrors: Array<{ field: string; message: string }> = [],\n\t\tcode = \"VALIDATION_ERROR\",\n\t\tstatusCode = 400,\n\t) {\n\t\tsuper(message, code, statusCode, { errors });\n\t\tthis.name = \"ValidationError\";\n\t\tthis.errors = errors;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, ValidationError);\n\t\t}\n\t}\n\n\t/**\n\t * Convert error to JSON representation\n\t */\n\ttoJSON(): Record<string, any> {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\terrors: this.errors,\n\t\t};\n\t}\n}\n\n/**\n * Not found error class\n */\nexport class NotFoundError extends AppError {\n\tpublic readonly resource: string;\n\tpublic readonly resourceId?: string;\n\n\tconstructor(\n\t\tresource: string,\n\t\tresourceId?: string,\n\t\tmessage?: string,\n\t\tcode = \"NOT_FOUND\",\n\t\tstatusCode = 404,\n\t) {\n\t\tconst defaultMessage = resourceId\n\t\t\t? `${resource} with id '${resourceId}' not found`\n\t\t\t: `${resource} not found`;\n\t\tsuper(message || defaultMessage, code, statusCode, { resource, resourceId });\n\t\tthis.name = \"NotFoundError\";\n\t\tthis.resource = resource;\n\t\tthis.resourceId = resourceId;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, NotFoundError);\n\t\t}\n\t}\n\n\t/**\n\t * Convert error to JSON representation\n\t */\n\ttoJSON(): Record<string, any> {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\tresource: this.resource,\n\t\t\tresourceId: this.resourceId,\n\t\t};\n\t}\n}\n","/**\n * Type-Safe Routes\n *\n * Centralized route definitions with type safety and parameter interpolation.\n * Eliminates string literals scattered across the codebase.\n */\n\n/**\n * Route parameters type\n */\nexport type RouteParams = Record<string, string | number>;\n\n/**\n * Route function interface - can be called with params or used as path\n */\nexport interface Route<TParams extends RouteParams = RouteParams> {\n\t/** Base path of the route */\n\treadonly path: string;\n\t/** Generate URL with interpolated parameters */\n\t(params?: TParams): string;\n}\n\n/**\n * Create a route with optional parameters\n *\n * @example\n * ```typescript\n * const userRoute = createRoute<{ id: string }>('/users/:id');\n * userRoute({ id: '123' }); // \"/users/123\"\n * userRoute.path; // \"/users/:id\"\n * ```\n */\nexport function createRoute<TParams extends RouteParams = Record<string, never>>(path: string): Route<TParams> {\n\tconst routeFn = (params?: TParams): string => {\n\t\tif (!params) return path;\n\n\t\tlet result = path;\n\t\tfor (const [key, value] of Object.entries(params)) {\n\t\t\tresult = result.replace(`:${key}`, String(value));\n\t\t}\n\t\treturn result;\n\t};\n\n\t// Add path as a property\n\tObject.defineProperty(routeFn, \"path\", {\n\t\tvalue: path,\n\t\twritable: false,\n\t\tenumerable: true,\n\t});\n\n\treturn routeFn as Route<TParams>;\n}\n\n/**\n * Admin routes\n */\nexport const adminRoutes = {\n\t/** Dashboard */\n\tdashboard: createRoute(\"/admin\"),\n\n\t/** Accounts list */\n\taccounts: createRoute(\"/admin/accounts\"),\n\n\t/** Account detail */\n\taccount: createRoute<{ id: string | number }>(\"/admin/accounts/:id\"),\n\n\t/** Account brands */\n\taccountBrands: createRoute<{ id: string | number }>(\"/admin/accounts/:id/brands\"),\n\n\t/** Brands list */\n\tbrands: createRoute(\"/admin/brands\"),\n\n\t/** Brand detail */\n\tbrand: createRoute<{ id: string | number }>(\"/admin/brands/:id\"),\n\n\t/** Brand settings */\n\tbrandSettings: createRoute<{ id: string | number }>(\"/admin/brands/:id/settings\"),\n\n\t/** Users list */\n\tusers: createRoute(\"/admin/users\"),\n\n\t/** User detail */\n\tuser: createRoute<{ id: string }>(\"/admin/users/:id\"),\n\n\t/** Current user profile */\n\tprofile: createRoute(\"/admin/user\"),\n\n\t/** Analytics */\n\tanalytics: createRoute(\"/admin/analytics\"),\n} as const;\n\n/**\n * Portal routes (customer-facing)\n */\nexport const portalRoutes = {\n\t/** Portal home */\n\thome: createRoute(\"/\"),\n\n\t/** Brand portal */\n\tbrand: createRoute<{ brandId: string | number }>(\"/brands/:brandId\"),\n\n\t/** Brand settings */\n\tbrandSettings: createRoute<{ brandId: string | number }>(\"/brands/:brandId/settings\"),\n\n\t/** Brand dashboard */\n\tbrandDashboard: createRoute<{ brandId: string | number }>(\"/brands/:brandId/dashboard\"),\n\n\t/** Brand analytics */\n\tbrandAnalytics: createRoute<{ brandId: string | number }>(\"/brands/:brandId/analytics\"),\n} as const;\n\n/**\n * Auth routes\n */\nexport const authRoutes = {\n\t/** Login page */\n\tlogin: createRoute(\"/login\"),\n\n\t/** Logout endpoint */\n\tlogout: createRoute(\"/api/auth/logout\"),\n\n\t/** Confirm sign in */\n\tconfirmSignIn: createRoute(\"/api/auth/confirm-signin\"),\n} as const;\n\n/**\n * API routes\n */\nexport const apiRoutes = {\n\t/** Auth endpoints */\n\tauth: {\n\t\tlogout: createRoute(\"/api/auth/logout\"),\n\t\tconfirmSignIn: createRoute(\"/api/auth/confirm-signin\"),\n\t},\n} as const;\n\n/**\n * All routes combined\n */\nexport const routes = {\n\tadmin: adminRoutes,\n\tportal: portalRoutes,\n\tauth: authRoutes,\n\tapi: apiRoutes,\n} as const;\n\n/**\n * Type for all routes\n */\nexport type Routes = typeof routes;\n\n/**\n * Helper to check if a path matches a route pattern\n */\nexport function matchesRoute(path: string, route: Route): boolean {\n\tconst pattern = route.path\n\t\t.replace(/:[^/]+/g, \"[^/]+\") // Replace :param with regex\n\t\t.replace(/\\//g, \"\\\\/\"); // Escape slashes\n\n\tconst regex = new RegExp(`^${pattern}$`);\n\treturn regex.test(path);\n}\n\n/**\n * Extract parameters from a path given a route pattern\n */\nexport function extractRouteParams<TParams extends RouteParams>(\n\tpath: string,\n\troute: Route<TParams>\n): TParams | null {\n\tconst paramNames: string[] = [];\n\tconst pattern = route.path.replace(/:([^/]+)/g, (_, name) => {\n\t\tparamNames.push(name);\n\t\treturn \"([^/]+)\";\n\t});\n\n\tconst regex = new RegExp(`^${pattern}$`);\n\tconst match = path.match(regex);\n\n\tif (!match) return null;\n\n\tconst params: RouteParams = {};\n\tparamNames.forEach((name, index) => {\n\t\tparams[name] = match[index + 1];\n\t});\n\n\treturn params as TParams;\n}\n\n/**\n * Navigate to a route (client-side helper)\n *\n * @example\n * ```typescript\n * navigateTo(routes.admin.account({ id: '123' }));\n * ```\n */\nexport function navigateTo(url: string): void {\n\tif (typeof window !== \"undefined\") {\n\t\twindow.location.href = url;\n\t}\n}\n\n/**\n * Build a URL with query parameters\n *\n * @example\n * ```typescript\n * const url = buildUrl(routes.admin.users(), { page: 2, status: 'active' });\n * // \"/admin/users?page=2&status=active\"\n * ```\n */\nexport function buildUrl(path: string, params?: Record<string, string | number | boolean | null | undefined>): string {\n\tif (!params) return path;\n\n\tconst searchParams = new URLSearchParams();\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (value !== null && value !== undefined && value !== \"\") {\n\t\t\tsearchParams.set(key, String(value));\n\t\t}\n\t}\n\n\tconst queryString = searchParams.toString();\n\treturn queryString ? `${path}?${queryString}` : path;\n}\n"],"mappings":"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","names":["log","globalSettings"]}
1
+ {"version":3,"sources":["../src/auth/index.ts","../src/amplify-astro-adapter/createRunWithAmplifyServerContext.ts","../src/amplify-astro-adapter/globalSettings.ts","../src/utils/logger.ts","../src/amplify-astro-adapter/createCookieStorageAdapterFromAstroContext.ts","../src/utils/index.ts","../src/constants/index.ts","../src/errors/index.ts","../src/routes/index.ts"],"sourcesContent":["/**\n * @htlkg/core/auth\n * Core authentication functions and utilities\n */\n\nimport type { APIContext } from \"astro\";\nimport { Amplify } from \"aws-amplify\";\nimport { fetchAuthSession } from \"aws-amplify/auth\";\nimport {\n\tfetchAuthSession as fetchServerAuthSession,\n\tgetCurrentUser as getServerCurrentUser,\n} from \"aws-amplify/auth/server\";\nimport { createRunWithAmplifyServerContext, globalSettings } from \"../amplify-astro-adapter\";\n\n// Re-export types\nexport type { APIContext } from \"astro\";\n\n/**\n * User interface representing an authenticated user\n */\nexport interface User {\n\tusername: string;\n\temail: string;\n\tbrandIds: number[];\n\taccountIds: number[];\n\tisAdmin: boolean;\n\tisSuperAdmin: boolean;\n\troles: string[];\n}\n\n/**\n * Parse comma-separated IDs from Cognito custom attributes\n */\nfunction parseIds(ids: string | undefined): number[] {\n\tif (!ids) return [];\n\treturn ids\n\t\t.split(\",\")\n\t\t.map((id) => Number.parseInt(id.trim(), 10))\n\t\t.filter((id) => !Number.isNaN(id));\n}\n\n// Track if Amplify has been configured\nlet amplifyConfigured = false;\n\n/**\n * Configure Amplify on first use (server-side)\n * This must be called before any auth operations\n */\nfunction ensureAmplifyConfigured(): void {\n\tif (amplifyConfigured) return;\n\n\ttry {\n\t\t// Amplify should already be configured by the middleware\n\t\t// This is just a safety check\n\t\tconst config = Amplify.getConfig();\n\t\tif (!config.Auth) {\n\t\t\tthrow new Error(\"Amplify Auth not configured\");\n\t\t}\n\t\tamplifyConfigured = true;\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : \"Unknown error\";\n\t\tconsole.error(`[Auth] Amplify not configured: ${errorMsg}`);\n\t\tthrow error;\n\t}\n}\n\n/**\n * Get current authenticated user (server-side)\n * Reads Amplify auth cookies from the request and validates the session\n */\nexport async function getUser(context: APIContext): Promise<User | null> {\n\ttry {\n\t\tensureAmplifyConfigured();\n\t\t\n\t\t// Get the current Amplify configuration\n\t\tconst amplifyConfig = Amplify.getConfig();\n\n\t\t// Create the server context runner - pass globalSettings explicitly\n\t\t// to ensure the same instance is used across all modules\n\t\tconst runWithAmplifyServerContext = createRunWithAmplifyServerContext({\n\t\t\tconfig: amplifyConfig,\n\t\t\tglobalSettings,\n\t\t});\n\n\t\t// Create Astro server context\n\t\tconst astroServerContext = {\n\t\t\tcookies: context.cookies,\n\t\t\trequest: context.request,\n\t\t};\n\n\t\t// Run in Amplify server context\n\t\tconst user = await runWithAmplifyServerContext({\n\t\t\tastroServerContext,\n\t\t\toperation: async (contextSpec) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst currentUser = await getServerCurrentUser(contextSpec as any);\n\t\t\t\t\tconst session = await fetchServerAuthSession(contextSpec as any);\n\n\t\t\t\t\tif (!session.tokens?.accessToken) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst accessPayload = session.tokens.accessToken.payload;\n\t\t\t\t\tconst idPayload = session.tokens.idToken?.payload;\n\n\t\t\t\t\t// Parse user attributes - email is typically in ID token, not access token\n\t\t\t\t\tconst email =\n\t\t\t\t\t\t(idPayload?.email as string) ||\n\t\t\t\t\t\t(accessPayload.email as string) ||\n\t\t\t\t\t\t\"\";\n\t\t\t\t\tconst brandIds = parseIds(\n\t\t\t\t\t\taccessPayload[\"custom:brand_ids\"] as string,\n\t\t\t\t\t);\n\t\t\t\t\tconst accountIds = parseIds(\n\t\t\t\t\t\taccessPayload[\"custom:account_ids\"] as string,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Check admin status\n\t\t\t\t\tconst groups = (accessPayload[\"cognito:groups\"] as string[]) || [];\n\t\t\t\t\tconst isAdmin =\n\t\t\t\t\t\tgroups.includes(\"admin\") ||\n\t\t\t\t\t\tgroups.includes(\"ADMINS\") ||\n\t\t\t\t\t\tgroups.includes(\"SUPER_ADMINS\");\n\t\t\t\t\tconst isSuperAdmin = groups.includes(\"SUPER_ADMINS\");\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tusername: currentUser.username,\n\t\t\t\t\t\temail,\n\t\t\t\t\t\tbrandIds,\n\t\t\t\t\t\taccountIds,\n\t\t\t\t\t\tisAdmin,\n\t\t\t\t\t\tisSuperAdmin,\n\t\t\t\t\t\troles: groups,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// UserUnAuthenticatedException is expected when user is not logged in\n\t\t\t\t\t// Only log other errors without sensitive data\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\terror.name !== \"UserUnAuthenticatedException\"\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Log error name and message without stack trace or sensitive data\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\"[Auth] Error in server context:\",\n\t\t\t\t\t\t\terror.name,\n\t\t\t\t\t\t\t\"-\",\n\t\t\t\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\treturn user;\n\t} catch (error) {\n\t\t// Log error without exposing sensitive information\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(\n\t\t\t\t\"[Auth] Server-side auth error:\",\n\t\t\t\terror.name,\n\t\t\t\t\"-\",\n\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.error(\"[Auth] Server-side auth error: Unknown error\");\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * Get current authenticated user (client-side)\n */\nexport async function getClientUser(): Promise<User | null> {\n\ttry {\n\t\tconst session = await fetchAuthSession();\n\n\t\tif (!session.tokens?.accessToken) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst accessPayload = session.tokens.accessToken.payload;\n\t\tconst idPayload = session.tokens.idToken?.payload;\n\n\t\tconst email =\n\t\t\t(idPayload?.email as string) || (accessPayload.email as string) || \"\";\n\t\tconst brandIds = parseIds(accessPayload[\"custom:brand_ids\"] as string);\n\t\tconst accountIds = parseIds(accessPayload[\"custom:account_ids\"] as string);\n\n\t\tconst groups = (accessPayload[\"cognito:groups\"] as string[]) || [];\n\t\tconst isAdmin =\n\t\t\tgroups.includes(\"admin\") ||\n\t\t\tgroups.includes(\"ADMINS\") ||\n\t\t\tgroups.includes(\"SUPER_ADMINS\");\n\t\tconst isSuperAdmin = groups.includes(\"SUPER_ADMINS\");\n\n\t\treturn {\n\t\t\tusername: (accessPayload.username as string) || \"\",\n\t\t\temail,\n\t\t\tbrandIds,\n\t\t\taccountIds,\n\t\t\tisAdmin,\n\t\t\tisSuperAdmin,\n\t\t\troles: groups,\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(\n\t\t\t\t\"[Auth] Client auth error:\",\n\t\t\t\terror.name,\n\t\t\t\t\"-\",\n\t\t\t\terror.message.replace(/token[=:]\\s*[^\\s,}]+/gi, \"token=***\"),\n\t\t\t);\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/**\n * Check if user has access to a specific brand\n */\nexport function hasAccessToBrand(\n\tuser: User | null,\n\tbrandId: number,\n): boolean {\n\tif (!user) return false;\n\tif (user.isAdmin) return true;\n\treturn user.brandIds.includes(brandId);\n}\n\n/**\n * Check if user has access to a specific account\n */\nexport function hasAccessToAccount(\n\tuser: User | null,\n\taccountId: number,\n): boolean {\n\tif (!user) return false;\n\tif (user.isAdmin) return true;\n\treturn user.accountIds.includes(accountId);\n}\n\n/**\n * Check if user is an admin\n */\nexport function isAdminUser(user: User | null): boolean {\n\treturn user?.isAdmin || false;\n}\n\n/**\n * Check if user is a super admin\n */\nexport function isSuperAdminUser(user: User | null): boolean {\n\treturn user?.isSuperAdmin || false;\n}\n\n/**\n * Placeholder for requireAuth - will be implemented in @htlkg/integrations\n * This is here for type exports and documentation\n */\nexport async function requireAuth(\n\tcontext: APIContext,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireAuth should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Placeholder for requireAdminAccess - will be implemented in @htlkg/integrations\n */\nexport async function requireAdminAccess(\n\tcontext: APIContext,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireAdminAccess should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Placeholder for requireBrandAccess - will be implemented in @htlkg/integrations\n */\nexport async function requireBrandAccess(\n\tcontext: APIContext,\n\tbrandId: number,\n\tloginUrl?: string,\n): Promise<{ success: boolean; user?: User; redirectTo?: string }> {\n\tthrow new Error(\n\t\t\"requireBrandAccess should be imported from @htlkg/astro/middleware\",\n\t);\n}\n\n/**\n * Sign out the current user (client-side)\n * With SSR mode enabled, Amplify automatically clears auth cookies\n */\nexport async function signOut(): Promise<void> {\n\ttry {\n\t\tconst { signOut: amplifySignOut } = await import(\"aws-amplify/auth\");\n\t\tawait amplifySignOut({ global: true });\n\t} catch (error) {\n\t\t// If Amplify signOut fails (e.g., not configured), clear cookies manually\n\t\tconsole.warn(\"[Auth] Amplify signOut failed, clearing cookies manually:\", error);\n\n\t\t// Clear all auth-related cookies by setting them to expire\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tconst cookies = document.cookie.split(\";\");\n\t\t\tfor (const cookie of cookies) {\n\t\t\t\tconst [name] = cookie.trim().split(\"=\");\n\t\t\t\tif (\n\t\t\t\t\tname.includes(\"CognitoIdentityServiceProvider\") ||\n\t\t\t\t\tname.includes(\"amplify\") ||\n\t\t\t\t\tname.includes(\"idToken\") ||\n\t\t\t\t\tname.includes(\"accessToken\") ||\n\t\t\t\t\tname.includes(\"refreshToken\")\n\t\t\t\t) {\n\t\t\t\t\tdocument.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { ResourcesConfig } from 'aws-amplify';\nimport { sharedInMemoryStorage } from 'aws-amplify/utils';\nimport {\n createAWSCredentialsAndIdentityIdProvider,\n createKeyValueStorageFromCookieStorageAdapter,\n createUserPoolsTokenProvider,\n runWithAmplifyServerContext as coreRunWithContext,\n} from 'aws-amplify/adapter-core';\n\nimport type { AstroServer } from './types';\nimport { globalSettings as defaultGlobalSettings } from './globalSettings';\nimport { createCookieStorageAdapterFromAstroContext } from './createCookieStorageAdapterFromAstroContext';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('amplify-server-context');\n\n/**\n * Creates a function that runs operations within the Amplify server context.\n *\n * IMPORTANT: Pass globalSettings explicitly to avoid module singleton issues\n * when using linked packages or different bundling contexts.\n */\nexport const createRunWithAmplifyServerContext = ({\n config: resourcesConfig,\n globalSettings = defaultGlobalSettings,\n}: {\n config: ResourcesConfig;\n globalSettings?: AstroServer.GlobalSettings;\n}): AstroServer.RunOperationWithContext => {\n const isServerSideAuthEnabled = globalSettings.isServerSideAuthEnabled();\n const isSSLOrigin = globalSettings.isSSLOrigin();\n const setCookieOptions = globalSettings.getRuntimeOptions().cookies ?? {};\n\n log.debug('Settings:', {\n isServerSideAuthEnabled,\n isSSLOrigin,\n hasCookieOptions: Object.keys(setCookieOptions).length > 0,\n });\n \n const mergedSetCookieOptions = {\n ...(isServerSideAuthEnabled && { httpOnly: true, sameSite: 'lax' as const }),\n ...setCookieOptions,\n ...(isServerSideAuthEnabled && { secure: isSSLOrigin }),\n path: '/',\n };\n\n const runWithContext: AstroServer.RunOperationWithContext = async ({\n astroServerContext,\n operation,\n }) => {\n if (resourcesConfig.Auth) {\n const cookieAdapter = await createCookieStorageAdapterFromAstroContext(astroServerContext);\n \n const keyValueStorage =\n astroServerContext === null\n ? sharedInMemoryStorage\n : createKeyValueStorageFromCookieStorageAdapter(\n cookieAdapter,\n undefined,\n mergedSetCookieOptions\n );\n\n const credentialsProvider = createAWSCredentialsAndIdentityIdProvider(\n resourcesConfig.Auth,\n keyValueStorage\n );\n \n const tokenProvider = createUserPoolsTokenProvider(\n resourcesConfig.Auth,\n keyValueStorage\n );\n\n return coreRunWithContext(\n resourcesConfig,\n { Auth: { credentialsProvider, tokenProvider } },\n operation\n );\n }\n\n return coreRunWithContext(resourcesConfig, {}, operation);\n };\n\n return runWithContext;\n};\n","import type { AstroServer } from './types';\n\nexport const globalSettings: AstroServer.GlobalSettings = (() => {\n let runtimeOptions: AstroServer.RuntimeOptions = {};\n let serverSideAuthEnabled = true;\n let sslOrigin = false;\n\n return {\n setRuntimeOptions(opts) { runtimeOptions = opts ?? {}; },\n getRuntimeOptions() { return runtimeOptions; },\n enableServerSideAuth() { serverSideAuthEnabled = true; },\n isServerSideAuthEnabled() { return serverSideAuthEnabled; },\n setIsSSLOrigin(v: boolean) { sslOrigin = v; },\n isSSLOrigin() { return sslOrigin; },\n };\n})();\n","/**\n * Simple debug logger utility\n * \n * Debug logs are only shown when DEBUG=true or HTLKG_DEBUG=true is set in environment.\n * Info logs are always shown.\n * \n * @example\n * ```typescript\n * import { logger } from '@htlkg/core/utils/logger';\n * \n * logger.debug('server-client', 'Detailed debug info', { data });\n * logger.info('server-client', 'Important info message');\n * logger.warn('server-client', 'Warning message');\n * logger.error('server-client', 'Error occurred', error);\n * ```\n */\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst isDebugEnabled = (): boolean => {\n // Check Node.js environment variables\n if (typeof process !== 'undefined' && process.env) {\n return process.env.DEBUG === 'true' || \n process.env.HTLKG_DEBUG === 'true' ||\n process.env.DEBUG === '*';\n }\n // Browser/Vite environment - check for DEV mode\n try {\n // @ts-ignore - import.meta.env is Vite-specific\n if (typeof import.meta !== 'undefined' && import.meta.env) {\n // @ts-ignore\n return import.meta.env.DEBUG === 'true' || \n // @ts-ignore\n import.meta.env.HTLKG_DEBUG === 'true' ||\n // @ts-ignore\n import.meta.env.DEV === true;\n }\n } catch {\n // Ignore errors accessing import.meta\n }\n return false;\n};\n\nconst formatMessage = (namespace: string, message: string): string => {\n return `[${namespace}] ${message}`;\n};\n\nexport const logger = {\n /**\n * Debug log - only shown when DEBUG=true\n */\n debug(namespace: string, message: string, ...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.log(formatMessage(namespace, message), ...args);\n }\n },\n\n /**\n * Info log - always shown\n */\n info(namespace: string, message: string, ...args: unknown[]): void {\n console.info(formatMessage(namespace, message), ...args);\n },\n\n /**\n * Warning log - always shown\n */\n warn(namespace: string, message: string, ...args: unknown[]): void {\n console.warn(formatMessage(namespace, message), ...args);\n },\n\n /**\n * Error log - always shown\n */\n error(namespace: string, message: string, ...args: unknown[]): void {\n console.error(formatMessage(namespace, message), ...args);\n },\n};\n\n/**\n * Create a namespaced logger for a specific module\n */\nexport const createLogger = (namespace: string) => ({\n debug: (message: string, ...args: unknown[]) => logger.debug(namespace, message, ...args),\n info: (message: string, ...args: unknown[]) => logger.info(namespace, message, ...args),\n warn: (message: string, ...args: unknown[]) => logger.warn(namespace, message, ...args),\n error: (message: string, ...args: unknown[]) => logger.error(namespace, message, ...args),\n});\n","import type { CookieStorage } from 'aws-amplify/adapter-core';\nimport type { AstroServer } from './types';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('cookie-storage-adapter');\n\n// Ensures the cookie names are encoded in order to look up the cookie store\n// that is manipulated by js-cookie on the client side.\n// Details of the js-cookie encoding behavior see:\n// https://github.com/js-cookie/js-cookie#encoding\n// The implementation is borrowed from js-cookie without escaping `[()]` as\n// we are not using those chars in the auth keys.\nfunction ensureEncodedForJSCookie(name: string): string {\n return encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent);\n}\n\nfunction parseCookieHeader(cookieHeader: string | null) {\n const out: Record<string, string> = {};\n if (!cookieHeader) return out;\n for (const part of cookieHeader.split(';')) {\n const [rawName, ...rest] = part.trim().split('=');\n const name = decodeURIComponent(rawName || '');\n const value = decodeURIComponent(rest.join('=') || '');\n if (name) out[name] = value;\n }\n return out;\n}\n\nfunction mapSameSite(\n s: CookieStorage.SetCookieOptions['sameSite']\n): 'lax' | 'strict' | 'none' | undefined {\n if (s === true) return 'strict';\n if (s === false) return 'lax';\n if (s === 'lax' || s === 'strict' || s === 'none') return s;\n return undefined;\n}\n\nexport async function createCookieStorageAdapterFromAstroContext(\n astroServerContext: AstroServer.ServerContext\n): Promise<CookieStorage.Adapter> {\n if (astroServerContext === null) {\n log.debug('Context is null, returning no-op adapter');\n return {\n get: () => undefined,\n getAll: () => [],\n set: () => {},\n delete: () => {},\n };\n }\n\n const { cookies, request } = astroServerContext;\n const cookieHeader = request?.headers?.get('cookie');\n const headerCookies = parseCookieHeader(cookieHeader ?? null);\n\n // Debug: Log available cookies (names only for security)\n const cookieNames = Object.keys(headerCookies);\n const cognitoCookies = cookieNames.filter(name => name.includes('CognitoIdentityServiceProvider'));\n log.debug('Available cookies:', cookieNames.length);\n log.debug('Cognito cookies found:', cognitoCookies.length);\n if (cognitoCookies.length > 0) {\n log.debug('Cognito cookie names:', cognitoCookies);\n }\n\n const adapter: CookieStorage.Adapter = {\n get(name) {\n const encodedName = ensureEncodedForJSCookie(name);\n const v = cookies?.get(encodedName)?.value ?? headerCookies[encodedName] ?? headerCookies[name];\n // Debug: Log token lookups (only for auth-related cookies)\n if (name.includes('accessToken') || name.includes('idToken') || name.includes('refreshToken') || name.includes('LastAuthUser')) {\n log.debug(`get('${name}'): ${v ? 'FOUND' : 'NOT FOUND'}`);\n }\n return v ? { name, value: v } : undefined;\n },\n getAll() {\n const fromAPI =\n (typeof (cookies as any)?.getAll === 'function'\n ? (cookies as any).getAll().map((c: any) => ({ name: c.name, value: c.value }))\n : Object.entries(headerCookies).map(([name, value]) => ({ name, value })));\n return fromAPI;\n },\n set(name, value, options) {\n try {\n (cookies as any).set(name, value, {\n ...(options ?? {}),\n sameSite: mapSameSite(options?.sameSite),\n });\n } catch {}\n },\n delete(name: string) {\n try {\n (cookies as any).delete(name);\n } catch {}\n },\n };\n\n return adapter;\n}\n","/**\n * @htlkg/core/utils\n * Core utility functions for Hotelinking applications\n */\n\n// Logger utility\nexport { logger, createLogger } from './logger';\n\n/**\n * Format a date to a localized string\n * @param date - Date to format\n * @param locale - Locale string (default: 'en-US')\n * @param options - Intl.DateTimeFormatOptions\n * @returns Formatted date string\n */\nexport function formatDate(\n\tdate: Date | string | number,\n\tlocale = \"en-US\",\n\toptions: Intl.DateTimeFormatOptions = {\n\t\tyear: \"numeric\",\n\t\tmonth: \"short\",\n\t\tday: \"numeric\",\n\t},\n): string {\n\tconst dateObj = typeof date === \"string\" || typeof date === \"number\" ? new Date(date) : date;\n\treturn new Intl.DateTimeFormat(locale, options).format(dateObj);\n}\n\n/**\n * Truncate text to a maximum length with ellipsis\n * @param text - Text to truncate\n * @param maxLength - Maximum length before truncation\n * @param suffix - Suffix to append (default: '...')\n * @returns Truncated text\n */\nexport function truncateText(\n\ttext: string,\n\tmaxLength: number,\n\tsuffix = \"...\",\n): string {\n\tif (text.length <= maxLength) return text;\n\treturn text.slice(0, maxLength - suffix.length) + suffix;\n}\n\n/**\n * Group an array of items by a key\n * @param items - Array of items to group\n * @param keyFn - Function to extract the grouping key\n * @returns Object with keys as group names and values as arrays of items\n */\nexport function groupBy<T>(\n\titems: T[],\n\tkeyFn: (item: T) => string | number,\n): Record<string | number, T[]> {\n\treturn items.reduce(\n\t\t(groups, item) => {\n\t\t\tconst key = keyFn(item);\n\t\t\tif (!groups[key]) {\n\t\t\t\tgroups[key] = [];\n\t\t\t}\n\t\t\tgroups[key].push(item);\n\t\t\treturn groups;\n\t\t},\n\t\t{} as Record<string | number, T[]>,\n\t);\n}\n\n/**\n * Debounce a function call\n * @param fn - Function to debounce\n * @param delay - Delay in milliseconds\n * @returns Debounced function\n */\nexport function debounce<T extends (...args: any[]) => any>(\n\tfn: T,\n\tdelay: number,\n): (...args: Parameters<T>) => void {\n\tlet timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n\treturn function debounced(...args: Parameters<T>) {\n\t\tif (timeoutId !== null) {\n\t\t\tclearTimeout(timeoutId);\n\t\t}\n\t\ttimeoutId = setTimeout(() => {\n\t\t\tfn(...args);\n\t\t\ttimeoutId = null;\n\t\t}, delay);\n\t};\n}\n\n/**\n * Throttle a function call\n * @param fn - Function to throttle\n * @param limit - Minimum time between calls in milliseconds\n * @returns Throttled function\n */\nexport function throttle<T extends (...args: any[]) => any>(\n\tfn: T,\n\tlimit: number,\n): (...args: Parameters<T>) => void {\n\tlet inThrottle = false;\n\n\treturn function throttled(...args: Parameters<T>) {\n\t\tif (!inThrottle) {\n\t\t\tfn(...args);\n\t\t\tinThrottle = true;\n\t\t\tsetTimeout(() => {\n\t\t\t\tinThrottle = false;\n\t\t\t}, limit);\n\t\t}\n\t};\n}\n\n/**\n * Get current timestamp in ISO 8601 format\n * Useful for audit trails, logging, and database timestamps\n * @returns Current timestamp as ISO string (e.g., \"2024-01-15T10:30:00.000Z\")\n */\nexport function getCurrentTimestamp(): string {\n\treturn new Date().toISOString();\n}\n","/**\n * @htlkg/core/constants\n * Core constants for Hotelinking applications\n */\n\n/**\n * Application routes\n */\nexport const ROUTES = {\n\t// Admin routes\n\tADMIN: {\n\t\tHOME: \"/admin\",\n\t\tBRANDS: \"/admin/brands\",\n\t\tACCOUNTS: \"/admin/accounts\",\n\t\tUSERS: \"/admin/users\",\n\t\tPRODUCTS: \"/admin/products\",\n\t\tSETTINGS: \"/admin/settings\",\n\t},\n\t// Brand routes\n\tBRAND: {\n\t\tHOME: (brandId: string) => `/${brandId}`,\n\t\tADMIN: (brandId: string) => `/${brandId}/admin`,\n\t\tTEMPLATES: (brandId: string) => `/${brandId}/admin/templates`,\n\t\tSETTINGS: (brandId: string) => `/${brandId}/admin/settings`,\n\t},\n\t// Auth routes\n\tAUTH: {\n\t\tLOGIN: \"/login\",\n\t\tLOGOUT: \"/logout\",\n\t\tSIGNUP: \"/signup\",\n\t\tFORGOT_PASSWORD: \"/forgot-password\",\n\t},\n} as const;\n\n/**\n * Product definitions\n */\nexport const PRODUCTS = {\n\tWIFI_PORTAL: {\n\t\tid: \"wifi-portal\",\n\t\tname: \"WiFi Portal\",\n\t\tdescription: \"Captive portal for WiFi authentication\",\n\t},\n\tWHATSAPP_CRM: {\n\t\tid: \"whatsapp-crm\",\n\t\tname: \"WhatsApp CRM\",\n\t\tdescription: \"WhatsApp integration for customer relationship management\",\n\t},\n\tANALYTICS: {\n\t\tid: \"analytics\",\n\t\tname: \"Analytics\",\n\t\tdescription: \"Analytics and reporting dashboard\",\n\t},\n} as const;\n\n/**\n * Permission definitions\n */\nexport const PERMISSIONS = {\n\t// Brand permissions\n\tBRAND_VIEW: \"brand:view\",\n\tBRAND_EDIT: \"brand:edit\",\n\tBRAND_DELETE: \"brand:delete\",\n\tBRAND_CREATE: \"brand:create\",\n\n\t// Account permissions\n\tACCOUNT_VIEW: \"account:view\",\n\tACCOUNT_EDIT: \"account:edit\",\n\tACCOUNT_DELETE: \"account:delete\",\n\tACCOUNT_CREATE: \"account:create\",\n\n\t// User permissions\n\tUSER_VIEW: \"user:view\",\n\tUSER_EDIT: \"user:edit\",\n\tUSER_DELETE: \"user:delete\",\n\tUSER_CREATE: \"user:create\",\n\n\t// Product permissions\n\tPRODUCT_VIEW: \"product:view\",\n\tPRODUCT_EDIT: \"product:edit\",\n\tPRODUCT_ENABLE: \"product:enable\",\n\tPRODUCT_DISABLE: \"product:disable\",\n\n\t// Admin permissions\n\tADMIN_ACCESS: \"admin:access\",\n\tSUPER_ADMIN_ACCESS: \"super_admin:access\",\n} as const;\n\n/**\n * User role definitions\n */\nexport const USER_ROLES = {\n\tSUPER_ADMIN: \"SUPER_ADMINS\",\n\tADMIN: \"ADMINS\",\n\tBRAND_ADMIN: \"BRAND_ADMINS\",\n\tBRAND_USER: \"BRAND_USERS\",\n\tUSER: \"USERS\",\n} as const;\n","/**\n * @htlkg/core/errors\n * Core error classes for Hotelinking applications\n */\n\n/**\n * Base application error class\n */\nexport class AppError extends Error {\n\tpublic readonly code: string;\n\tpublic readonly statusCode: number;\n\tpublic readonly details?: Record<string, any>;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tcode = \"APP_ERROR\",\n\t\tstatusCode = 500,\n\t\tdetails?: Record<string, any>,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"AppError\";\n\t\tthis.code = code;\n\t\tthis.statusCode = statusCode;\n\t\tthis.details = details;\n\n\t\t// Maintains proper stack trace for where our error was thrown (only available on V8)\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, AppError);\n\t\t}\n\t}\n\n\t/**\n\t * Convert error to JSON representation\n\t */\n\ttoJSON(): Record<string, any> {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t\tcode: this.code,\n\t\t\tstatusCode: this.statusCode,\n\t\t\tdetails: this.details,\n\t\t};\n\t}\n}\n\n/**\n * Authentication error class\n */\nexport class AuthError extends AppError {\n\tconstructor(\n\t\tmessage: string,\n\t\tcode = \"AUTH_ERROR\",\n\t\tstatusCode = 401,\n\t\tdetails?: Record<string, any>,\n\t) {\n\t\tsuper(message, code, statusCode, details);\n\t\tthis.name = \"AuthError\";\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, AuthError);\n\t\t}\n\t}\n}\n\n/**\n * Validation error class\n */\nexport class ValidationError extends AppError {\n\tpublic readonly errors: Array<{ field: string; message: string }>;\n\n\tconstructor(\n\t\tmessage: string,\n\t\terrors: Array<{ field: string; message: string }> = [],\n\t\tcode = \"VALIDATION_ERROR\",\n\t\tstatusCode = 400,\n\t) {\n\t\tsuper(message, code, statusCode, { errors });\n\t\tthis.name = \"ValidationError\";\n\t\tthis.errors = errors;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, ValidationError);\n\t\t}\n\t}\n\n\t/**\n\t * Convert error to JSON representation\n\t */\n\ttoJSON(): Record<string, any> {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\terrors: this.errors,\n\t\t};\n\t}\n}\n\n/**\n * Not found error class\n */\nexport class NotFoundError extends AppError {\n\tpublic readonly resource: string;\n\tpublic readonly resourceId?: string;\n\n\tconstructor(\n\t\tresource: string,\n\t\tresourceId?: string,\n\t\tmessage?: string,\n\t\tcode = \"NOT_FOUND\",\n\t\tstatusCode = 404,\n\t) {\n\t\tconst defaultMessage = resourceId\n\t\t\t? `${resource} with id '${resourceId}' not found`\n\t\t\t: `${resource} not found`;\n\t\tsuper(message || defaultMessage, code, statusCode, { resource, resourceId });\n\t\tthis.name = \"NotFoundError\";\n\t\tthis.resource = resource;\n\t\tthis.resourceId = resourceId;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, NotFoundError);\n\t\t}\n\t}\n\n\t/**\n\t * Convert error to JSON representation\n\t */\n\ttoJSON(): Record<string, any> {\n\t\treturn {\n\t\t\t...super.toJSON(),\n\t\t\tresource: this.resource,\n\t\t\tresourceId: this.resourceId,\n\t\t};\n\t}\n}\n","/**\n * Type-Safe Routes\n *\n * Centralized route definitions with type safety and parameter interpolation.\n * Eliminates string literals scattered across the codebase.\n */\n\n/**\n * Route parameters type\n */\nexport type RouteParams = Record<string, string | number>;\n\n/**\n * Route function interface - can be called with params or used as path\n */\nexport interface Route<TParams extends RouteParams = RouteParams> {\n\t/** Base path of the route */\n\treadonly path: string;\n\t/** Generate URL with interpolated parameters */\n\t(params?: TParams): string;\n}\n\n/**\n * Create a route with optional parameters\n *\n * @example\n * ```typescript\n * const userRoute = createRoute<{ id: string }>('/users/:id');\n * userRoute({ id: '123' }); // \"/users/123\"\n * userRoute.path; // \"/users/:id\"\n * ```\n */\nexport function createRoute<TParams extends RouteParams = Record<string, never>>(path: string): Route<TParams> {\n\tconst routeFn = (params?: TParams): string => {\n\t\tif (!params) return path;\n\n\t\tlet result = path;\n\t\tfor (const [key, value] of Object.entries(params)) {\n\t\t\tresult = result.replace(`:${key}`, String(value));\n\t\t}\n\t\treturn result;\n\t};\n\n\t// Add path as a property\n\tObject.defineProperty(routeFn, \"path\", {\n\t\tvalue: path,\n\t\twritable: false,\n\t\tenumerable: true,\n\t});\n\n\treturn routeFn as Route<TParams>;\n}\n\n/**\n * Admin routes\n */\nexport const adminRoutes = {\n\t/** Dashboard */\n\tdashboard: createRoute(\"/admin\"),\n\n\t/** Accounts list */\n\taccounts: createRoute(\"/admin/accounts\"),\n\n\t/** Account detail */\n\taccount: createRoute<{ id: string | number }>(\"/admin/accounts/:id\"),\n\n\t/** Account brands */\n\taccountBrands: createRoute<{ id: string | number }>(\"/admin/accounts/:id/brands\"),\n\n\t/** Brands list */\n\tbrands: createRoute(\"/admin/brands\"),\n\n\t/** Brand detail */\n\tbrand: createRoute<{ id: string | number }>(\"/admin/brands/:id\"),\n\n\t/** Brand settings */\n\tbrandSettings: createRoute<{ id: string | number }>(\"/admin/brands/:id/settings\"),\n\n\t/** Users list */\n\tusers: createRoute(\"/admin/users\"),\n\n\t/** User detail */\n\tuser: createRoute<{ id: string }>(\"/admin/users/:id\"),\n\n\t/** Current user profile */\n\tprofile: createRoute(\"/admin/user\"),\n\n\t/** Analytics */\n\tanalytics: createRoute(\"/admin/analytics\"),\n} as const;\n\n/**\n * Portal routes (customer-facing)\n */\nexport const portalRoutes = {\n\t/** Portal home */\n\thome: createRoute(\"/\"),\n\n\t/** Brand portal */\n\tbrand: createRoute<{ brandId: string | number }>(\"/brands/:brandId\"),\n\n\t/** Brand settings */\n\tbrandSettings: createRoute<{ brandId: string | number }>(\"/brands/:brandId/settings\"),\n\n\t/** Brand dashboard */\n\tbrandDashboard: createRoute<{ brandId: string | number }>(\"/brands/:brandId/dashboard\"),\n\n\t/** Brand analytics */\n\tbrandAnalytics: createRoute<{ brandId: string | number }>(\"/brands/:brandId/analytics\"),\n} as const;\n\n/**\n * Auth routes\n */\nexport const authRoutes = {\n\t/** Login page */\n\tlogin: createRoute(\"/login\"),\n\n\t/** Logout endpoint */\n\tlogout: createRoute(\"/api/auth/logout\"),\n\n\t/** Confirm sign in */\n\tconfirmSignIn: createRoute(\"/api/auth/confirm-signin\"),\n} as const;\n\n/**\n * API routes\n */\nexport const apiRoutes = {\n\t/** Auth endpoints */\n\tauth: {\n\t\tlogout: createRoute(\"/api/auth/logout\"),\n\t\tconfirmSignIn: createRoute(\"/api/auth/confirm-signin\"),\n\t},\n} as const;\n\n/**\n * All routes combined\n */\nexport const routes = {\n\tadmin: adminRoutes,\n\tportal: portalRoutes,\n\tauth: authRoutes,\n\tapi: apiRoutes,\n} as const;\n\n/**\n * Type for all routes\n */\nexport type Routes = typeof routes;\n\n/**\n * Helper to check if a path matches a route pattern\n */\nexport function matchesRoute(path: string, route: Route): boolean {\n\tconst pattern = route.path\n\t\t.replace(/:[^/]+/g, \"[^/]+\") // Replace :param with regex\n\t\t.replace(/\\//g, \"\\\\/\"); // Escape slashes\n\n\tconst regex = new RegExp(`^${pattern}$`);\n\treturn regex.test(path);\n}\n\n/**\n * Extract parameters from a path given a route pattern\n */\nexport function extractRouteParams<TParams extends RouteParams>(\n\tpath: string,\n\troute: Route<TParams>\n): TParams | null {\n\tconst paramNames: string[] = [];\n\tconst pattern = route.path.replace(/:([^/]+)/g, (_, name) => {\n\t\tparamNames.push(name);\n\t\treturn \"([^/]+)\";\n\t});\n\n\tconst regex = new RegExp(`^${pattern}$`);\n\tconst match = path.match(regex);\n\n\tif (!match) return null;\n\n\tconst params: RouteParams = {};\n\tparamNames.forEach((name, index) => {\n\t\tparams[name] = match[index + 1];\n\t});\n\n\treturn params as TParams;\n}\n\n/**\n * Navigate to a route (client-side helper)\n *\n * @example\n * ```typescript\n * navigateTo(routes.admin.account({ id: '123' }));\n * ```\n */\nexport function navigateTo(url: string): void {\n\tif (typeof window !== \"undefined\") {\n\t\twindow.location.href = url;\n\t}\n}\n\n/**\n * Build a URL with query parameters\n *\n * @example\n * ```typescript\n * const url = buildUrl(routes.admin.users(), { page: 2, status: 'active' });\n * // \"/admin/users?page=2&status=active\"\n * ```\n */\nexport function buildUrl(path: string, params?: Record<string, string | number | boolean | null | undefined>): string {\n\tif (!params) return path;\n\n\tconst searchParams = new URLSearchParams();\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (value !== null && value !== undefined && value !== \"\") {\n\t\t\tsearchParams.set(key, String(value));\n\t\t}\n\t}\n\n\tconst queryString = searchParams.toString();\n\treturn queryString ? `${path}?${queryString}` : path;\n}\n"],"mappings":"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","names":["log","globalSettings"]}
@@ -24,8 +24,10 @@ interface Brand {
24
24
  accountId: string;
25
25
  logo?: string;
26
26
  timezone: string;
27
- status: "active" | "inactive" | "maintenance" | "suspended";
27
+ status: "active" | "inactive" | "maintenance" | "suspended" | "deleted";
28
28
  settings: Record<string, any>;
29
+ deletedAt?: string;
30
+ deletedBy?: string;
29
31
  }
30
32
  /**
31
33
  * Account interface representing a customer account
@@ -36,6 +38,9 @@ interface Account {
36
38
  logo?: string;
37
39
  subscription: Record<string, any>;
38
40
  settings: Record<string, any>;
41
+ status?: "active" | "inactive" | "deleted";
42
+ deletedAt?: string;
43
+ deletedBy?: string;
39
44
  }
40
45
  /**
41
46
  * Product interface representing a product definition
@@ -61,6 +66,10 @@ interface ProductInstance {
61
66
  enabled: boolean;
62
67
  config: Record<string, any>;
63
68
  version: string;
69
+ createdAt?: string;
70
+ createdBy?: string;
71
+ updatedAt?: string;
72
+ updatedBy?: string;
64
73
  }
65
74
  /**
66
75
  * User interface representing a system user
@@ -74,7 +83,9 @@ interface User {
74
83
  roles?: string[];
75
84
  permissions?: Record<string, any>;
76
85
  lastLogin?: string;
77
- status: "active" | "inactive" | "pending" | "suspended";
86
+ status: "active" | "inactive" | "pending" | "suspended" | "deleted";
87
+ deletedAt?: string;
88
+ deletedBy?: string;
78
89
  }
79
90
  /**
80
91
  * BrandUser interface representing a user associated with a brand
@@ -85,5 +96,37 @@ interface BrandUser {
85
96
  role: string;
86
97
  permissions: string[];
87
98
  }
99
+ /**
100
+ * SystemSettings interface representing system-wide configuration
101
+ */
102
+ interface SystemSettings {
103
+ key: string;
104
+ softDeleteRetentionDays: number;
105
+ updatedAt?: string;
106
+ updatedBy?: string;
107
+ }
108
+ /**
109
+ * Contact interface representing a guest/contact record
110
+ */
111
+ interface Contact {
112
+ id: string;
113
+ brandId: string;
114
+ email: string;
115
+ phone?: string;
116
+ firstName: string;
117
+ lastName: string;
118
+ locale?: string;
119
+ gdprConsent: boolean;
120
+ gdprConsentDate?: string;
121
+ marketingOptIn?: boolean;
122
+ preferences?: Record<string, any>;
123
+ tags?: string[];
124
+ totalVisits?: number;
125
+ lastVisitDate?: string;
126
+ firstVisitDate?: string;
127
+ legacyId?: string;
128
+ createdAt?: string;
129
+ updatedAt?: string;
130
+ }
88
131
 
89
- export type { Account, AuthUser, Brand, BrandUser, Product, ProductInstance, User };
132
+ export type { Account, AuthUser, Brand, BrandUser, Contact, Product, ProductInstance, SystemSettings, User };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htlkg/core",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/auth/index.ts CHANGED
@@ -292,3 +292,34 @@ export async function requireBrandAccess(
292
292
  "requireBrandAccess should be imported from @htlkg/astro/middleware",
293
293
  );
294
294
  }
295
+
296
+ /**
297
+ * Sign out the current user (client-side)
298
+ * With SSR mode enabled, Amplify automatically clears auth cookies
299
+ */
300
+ export async function signOut(): Promise<void> {
301
+ try {
302
+ const { signOut: amplifySignOut } = await import("aws-amplify/auth");
303
+ await amplifySignOut({ global: true });
304
+ } catch (error) {
305
+ // If Amplify signOut fails (e.g., not configured), clear cookies manually
306
+ console.warn("[Auth] Amplify signOut failed, clearing cookies manually:", error);
307
+
308
+ // Clear all auth-related cookies by setting them to expire
309
+ if (typeof document !== "undefined") {
310
+ const cookies = document.cookie.split(";");
311
+ for (const cookie of cookies) {
312
+ const [name] = cookie.trim().split("=");
313
+ if (
314
+ name.includes("CognitoIdentityServiceProvider") ||
315
+ name.includes("amplify") ||
316
+ name.includes("idToken") ||
317
+ name.includes("accessToken") ||
318
+ name.includes("refreshToken")
319
+ ) {
320
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
@@ -26,8 +26,10 @@ export interface Brand {
26
26
  accountId: string;
27
27
  logo?: string;
28
28
  timezone: string;
29
- status: "active" | "inactive" | "maintenance" | "suspended";
29
+ status: "active" | "inactive" | "maintenance" | "suspended" | "deleted";
30
30
  settings: Record<string, any>;
31
+ deletedAt?: string;
32
+ deletedBy?: string;
31
33
  }
32
34
 
33
35
  /**
@@ -39,6 +41,9 @@ export interface Account {
39
41
  logo?: string;
40
42
  subscription: Record<string, any>;
41
43
  settings: Record<string, any>;
44
+ status?: "active" | "inactive" | "deleted";
45
+ deletedAt?: string;
46
+ deletedBy?: string;
42
47
  }
43
48
 
44
49
  /**
@@ -66,6 +71,11 @@ export interface ProductInstance {
66
71
  enabled: boolean;
67
72
  config: Record<string, any>;
68
73
  version: string;
74
+ // Audit fields
75
+ createdAt?: string;
76
+ createdBy?: string;
77
+ updatedAt?: string;
78
+ updatedBy?: string;
69
79
  }
70
80
 
71
81
  /**
@@ -80,7 +90,9 @@ export interface User {
80
90
  roles?: string[];
81
91
  permissions?: Record<string, any>;
82
92
  lastLogin?: string;
83
- status: "active" | "inactive" | "pending" | "suspended";
93
+ status: "active" | "inactive" | "pending" | "suspended" | "deleted";
94
+ deletedAt?: string;
95
+ deletedBy?: string;
84
96
  }
85
97
 
86
98
  /**
@@ -92,3 +104,37 @@ export interface BrandUser {
92
104
  role: string;
93
105
  permissions: string[];
94
106
  }
107
+
108
+ /**
109
+ * SystemSettings interface representing system-wide configuration
110
+ */
111
+ export interface SystemSettings {
112
+ key: string;
113
+ softDeleteRetentionDays: number;
114
+ updatedAt?: string;
115
+ updatedBy?: string;
116
+ }
117
+
118
+ /**
119
+ * Contact interface representing a guest/contact record
120
+ */
121
+ export interface Contact {
122
+ id: string;
123
+ brandId: string;
124
+ email: string;
125
+ phone?: string;
126
+ firstName: string;
127
+ lastName: string;
128
+ locale?: string;
129
+ gdprConsent: boolean;
130
+ gdprConsentDate?: string;
131
+ marketingOptIn?: boolean;
132
+ preferences?: Record<string, any>;
133
+ tags?: string[];
134
+ totalVisits?: number;
135
+ lastVisitDate?: string;
136
+ firstVisitDate?: string;
137
+ legacyId?: string;
138
+ createdAt?: string;
139
+ updatedAt?: string;
140
+ }