@htlkg/core 0.0.2 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +51 -0
  2. package/dist/index.d.ts +219 -0
  3. package/dist/index.js +121 -0
  4. package/dist/index.js.map +1 -1
  5. package/package.json +60 -34
  6. package/src/amplify-astro-adapter/amplify-astro-adapter.md +167 -0
  7. package/src/amplify-astro-adapter/createCookieStorageAdapterFromAstroContext.test.ts +305 -0
  8. package/src/amplify-astro-adapter/createCookieStorageAdapterFromAstroContext.ts +97 -0
  9. package/src/amplify-astro-adapter/createRunWithAmplifyServerContext.ts +84 -0
  10. package/src/amplify-astro-adapter/errors.test.ts +115 -0
  11. package/src/amplify-astro-adapter/errors.ts +105 -0
  12. package/src/amplify-astro-adapter/globalSettings.test.ts +78 -0
  13. package/src/amplify-astro-adapter/globalSettings.ts +16 -0
  14. package/src/amplify-astro-adapter/index.ts +14 -0
  15. package/src/amplify-astro-adapter/types.ts +55 -0
  16. package/src/auth/auth.md +178 -0
  17. package/src/auth/index.test.ts +180 -0
  18. package/src/auth/index.ts +294 -0
  19. package/src/constants/constants.md +132 -0
  20. package/src/constants/index.test.ts +116 -0
  21. package/src/constants/index.ts +98 -0
  22. package/src/core-exports.property.test.ts +186 -0
  23. package/src/errors/errors.md +177 -0
  24. package/src/errors/index.test.ts +153 -0
  25. package/src/errors/index.ts +134 -0
  26. package/src/index.ts +65 -0
  27. package/src/routes/index.ts +225 -0
  28. package/src/routes/routes.md +189 -0
  29. package/src/types/index.ts +94 -0
  30. package/src/types/types.md +144 -0
  31. package/src/utils/index.test.ts +257 -0
  32. package/src/utils/index.ts +112 -0
  33. package/src/utils/logger.ts +88 -0
  34. package/src/utils/utils.md +199 -0
  35. package/src/workspace.property.test.ts +235 -0
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @htlkg/core
2
+
3
+ Core utilities, types, authentication, and constants for Hotelinking applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @htlkg/core
9
+ ```
10
+
11
+ ## Modules
12
+
13
+ ### [Amplify Astro Adapter](src/amplify-astro-adapter/amplify-astro-adapter.md)
14
+ Server-side authentication support for Astro with AWS Amplify. Cookie-based auth context for SSR.
15
+
16
+ ### [Auth](src/auth/auth.md)
17
+ User authentication functions for server-side and client-side. Cognito integration with role-based access.
18
+
19
+ ### [Constants](src/constants/constants.md)
20
+ Centralized constants for routes, products, permissions, and user roles.
21
+
22
+ ### [Errors](src/errors/errors.md)
23
+ Standardized error classes: `AppError`, `AuthError`, `ValidationError`, `NotFoundError`.
24
+
25
+ ### [Routes](src/routes/routes.md)
26
+ Type-safe route definitions with parameter interpolation. Eliminates string literals.
27
+
28
+ ### [Types](src/types/types.md)
29
+ Core TypeScript interfaces: `Brand`, `Account`, `User`, `Product`, `ProductInstance`.
30
+
31
+ ### [Utils](src/utils/utils.md)
32
+ Common utilities: `logger`, `formatDate`, `truncateText`, `groupBy`, `debounce`, `throttle`.
33
+
34
+ ## Quick Start
35
+
36
+ ```typescript
37
+ // Authentication
38
+ import { getUser, hasAccessToBrand } from '@htlkg/core/auth';
39
+
40
+ // Type-safe routes
41
+ import { adminRoutes, buildUrl } from '@htlkg/core/routes';
42
+
43
+ // Constants
44
+ import { PERMISSIONS, USER_ROLES } from '@htlkg/core/constants';
45
+
46
+ // Error handling
47
+ import { NotFoundError, ValidationError } from '@htlkg/core/errors';
48
+
49
+ // Utilities
50
+ import { formatDate, debounce } from '@htlkg/core/utils';
51
+ ```
package/dist/index.d.ts CHANGED
@@ -5,3 +5,222 @@ export { PERMISSIONS, PRODUCTS, ROUTES, USER_ROLES } from './constants/index.js'
5
5
  export { AppError, AuthError, NotFoundError, ValidationError } from './errors/index.js';
6
6
  export { APIContext } from 'astro';
7
7
  import './logger-BTW3fOeM.js';
8
+
9
+ /**
10
+ * Type-Safe Routes
11
+ *
12
+ * Centralized route definitions with type safety and parameter interpolation.
13
+ * Eliminates string literals scattered across the codebase.
14
+ */
15
+ /**
16
+ * Route parameters type
17
+ */
18
+ type RouteParams = Record<string, string | number>;
19
+ /**
20
+ * Route function interface - can be called with params or used as path
21
+ */
22
+ interface Route<TParams extends RouteParams = RouteParams> {
23
+ /** Base path of the route */
24
+ readonly path: string;
25
+ /** Generate URL with interpolated parameters */
26
+ (params?: TParams): string;
27
+ }
28
+ /**
29
+ * Create a route with optional parameters
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const userRoute = createRoute<{ id: string }>('/users/:id');
34
+ * userRoute({ id: '123' }); // "/users/123"
35
+ * userRoute.path; // "/users/:id"
36
+ * ```
37
+ */
38
+ declare function createRoute<TParams extends RouteParams = Record<string, never>>(path: string): Route<TParams>;
39
+ /**
40
+ * Admin routes
41
+ */
42
+ declare const adminRoutes: {
43
+ /** Dashboard */
44
+ readonly dashboard: Route<Record<string, never>>;
45
+ /** Accounts list */
46
+ readonly accounts: Route<Record<string, never>>;
47
+ /** Account detail */
48
+ readonly account: Route<{
49
+ id: string | number;
50
+ }>;
51
+ /** Account brands */
52
+ readonly accountBrands: Route<{
53
+ id: string | number;
54
+ }>;
55
+ /** Brands list */
56
+ readonly brands: Route<Record<string, never>>;
57
+ /** Brand detail */
58
+ readonly brand: Route<{
59
+ id: string | number;
60
+ }>;
61
+ /** Brand settings */
62
+ readonly brandSettings: Route<{
63
+ id: string | number;
64
+ }>;
65
+ /** Users list */
66
+ readonly users: Route<Record<string, never>>;
67
+ /** User detail */
68
+ readonly user: Route<{
69
+ id: string;
70
+ }>;
71
+ /** Current user profile */
72
+ readonly profile: Route<Record<string, never>>;
73
+ /** Analytics */
74
+ readonly analytics: Route<Record<string, never>>;
75
+ };
76
+ /**
77
+ * Portal routes (customer-facing)
78
+ */
79
+ declare const portalRoutes: {
80
+ /** Portal home */
81
+ readonly home: Route<Record<string, never>>;
82
+ /** Brand portal */
83
+ readonly brand: Route<{
84
+ brandId: string | number;
85
+ }>;
86
+ /** Brand settings */
87
+ readonly brandSettings: Route<{
88
+ brandId: string | number;
89
+ }>;
90
+ /** Brand dashboard */
91
+ readonly brandDashboard: Route<{
92
+ brandId: string | number;
93
+ }>;
94
+ /** Brand analytics */
95
+ readonly brandAnalytics: Route<{
96
+ brandId: string | number;
97
+ }>;
98
+ };
99
+ /**
100
+ * Auth routes
101
+ */
102
+ declare const authRoutes: {
103
+ /** Login page */
104
+ readonly login: Route<Record<string, never>>;
105
+ /** Logout endpoint */
106
+ readonly logout: Route<Record<string, never>>;
107
+ /** Confirm sign in */
108
+ readonly confirmSignIn: Route<Record<string, never>>;
109
+ };
110
+ /**
111
+ * API routes
112
+ */
113
+ declare const apiRoutes: {
114
+ /** Auth endpoints */
115
+ readonly auth: {
116
+ readonly logout: Route<Record<string, never>>;
117
+ readonly confirmSignIn: Route<Record<string, never>>;
118
+ };
119
+ };
120
+ /**
121
+ * All routes combined
122
+ */
123
+ declare const routes: {
124
+ readonly admin: {
125
+ /** Dashboard */
126
+ readonly dashboard: Route<Record<string, never>>;
127
+ /** Accounts list */
128
+ readonly accounts: Route<Record<string, never>>;
129
+ /** Account detail */
130
+ readonly account: Route<{
131
+ id: string | number;
132
+ }>;
133
+ /** Account brands */
134
+ readonly accountBrands: Route<{
135
+ id: string | number;
136
+ }>;
137
+ /** Brands list */
138
+ readonly brands: Route<Record<string, never>>;
139
+ /** Brand detail */
140
+ readonly brand: Route<{
141
+ id: string | number;
142
+ }>;
143
+ /** Brand settings */
144
+ readonly brandSettings: Route<{
145
+ id: string | number;
146
+ }>;
147
+ /** Users list */
148
+ readonly users: Route<Record<string, never>>;
149
+ /** User detail */
150
+ readonly user: Route<{
151
+ id: string;
152
+ }>;
153
+ /** Current user profile */
154
+ readonly profile: Route<Record<string, never>>;
155
+ /** Analytics */
156
+ readonly analytics: Route<Record<string, never>>;
157
+ };
158
+ readonly portal: {
159
+ /** Portal home */
160
+ readonly home: Route<Record<string, never>>;
161
+ /** Brand portal */
162
+ readonly brand: Route<{
163
+ brandId: string | number;
164
+ }>;
165
+ /** Brand settings */
166
+ readonly brandSettings: Route<{
167
+ brandId: string | number;
168
+ }>;
169
+ /** Brand dashboard */
170
+ readonly brandDashboard: Route<{
171
+ brandId: string | number;
172
+ }>;
173
+ /** Brand analytics */
174
+ readonly brandAnalytics: Route<{
175
+ brandId: string | number;
176
+ }>;
177
+ };
178
+ readonly auth: {
179
+ /** Login page */
180
+ readonly login: Route<Record<string, never>>;
181
+ /** Logout endpoint */
182
+ readonly logout: Route<Record<string, never>>;
183
+ /** Confirm sign in */
184
+ readonly confirmSignIn: Route<Record<string, never>>;
185
+ };
186
+ readonly api: {
187
+ /** Auth endpoints */
188
+ readonly auth: {
189
+ readonly logout: Route<Record<string, never>>;
190
+ readonly confirmSignIn: Route<Record<string, never>>;
191
+ };
192
+ };
193
+ };
194
+ /**
195
+ * Type for all routes
196
+ */
197
+ type Routes = typeof routes;
198
+ /**
199
+ * Helper to check if a path matches a route pattern
200
+ */
201
+ declare function matchesRoute(path: string, route: Route): boolean;
202
+ /**
203
+ * Extract parameters from a path given a route pattern
204
+ */
205
+ declare function extractRouteParams<TParams extends RouteParams>(path: string, route: Route<TParams>): TParams | null;
206
+ /**
207
+ * Navigate to a route (client-side helper)
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * navigateTo(routes.admin.account({ id: '123' }));
212
+ * ```
213
+ */
214
+ declare function navigateTo(url: string): void;
215
+ /**
216
+ * Build a URL with query parameters
217
+ *
218
+ * @example
219
+ * ```typescript
220
+ * const url = buildUrl(routes.admin.users(), { page: 2, status: 'active' });
221
+ * // "/admin/users?page=2&status=active"
222
+ * ```
223
+ */
224
+ declare function buildUrl(path: string, params?: Record<string, string | number | boolean | null | undefined>): string;
225
+
226
+ export { type Route, type RouteParams, type Routes, adminRoutes, apiRoutes, authRoutes, buildUrl, createRoute, extractRouteParams, matchesRoute, navigateTo, portalRoutes, routes };
package/dist/index.js CHANGED
@@ -586,6 +586,117 @@ var NotFoundError = class _NotFoundError extends AppError {
586
586
  };
587
587
  }
588
588
  };
589
+
590
+ // src/routes/index.ts
591
+ function createRoute(path) {
592
+ const routeFn = (params) => {
593
+ if (!params) return path;
594
+ let result = path;
595
+ for (const [key, value] of Object.entries(params)) {
596
+ result = result.replace(`:${key}`, String(value));
597
+ }
598
+ return result;
599
+ };
600
+ Object.defineProperty(routeFn, "path", {
601
+ value: path,
602
+ writable: false,
603
+ enumerable: true
604
+ });
605
+ return routeFn;
606
+ }
607
+ var adminRoutes = {
608
+ /** Dashboard */
609
+ dashboard: createRoute("/admin"),
610
+ /** Accounts list */
611
+ accounts: createRoute("/admin/accounts"),
612
+ /** Account detail */
613
+ account: createRoute("/admin/accounts/:id"),
614
+ /** Account brands */
615
+ accountBrands: createRoute("/admin/accounts/:id/brands"),
616
+ /** Brands list */
617
+ brands: createRoute("/admin/brands"),
618
+ /** Brand detail */
619
+ brand: createRoute("/admin/brands/:id"),
620
+ /** Brand settings */
621
+ brandSettings: createRoute("/admin/brands/:id/settings"),
622
+ /** Users list */
623
+ users: createRoute("/admin/users"),
624
+ /** User detail */
625
+ user: createRoute("/admin/users/:id"),
626
+ /** Current user profile */
627
+ profile: createRoute("/admin/user"),
628
+ /** Analytics */
629
+ analytics: createRoute("/admin/analytics")
630
+ };
631
+ var portalRoutes = {
632
+ /** Portal home */
633
+ home: createRoute("/"),
634
+ /** Brand portal */
635
+ brand: createRoute("/brands/:brandId"),
636
+ /** Brand settings */
637
+ brandSettings: createRoute("/brands/:brandId/settings"),
638
+ /** Brand dashboard */
639
+ brandDashboard: createRoute("/brands/:brandId/dashboard"),
640
+ /** Brand analytics */
641
+ brandAnalytics: createRoute("/brands/:brandId/analytics")
642
+ };
643
+ var authRoutes = {
644
+ /** Login page */
645
+ login: createRoute("/login"),
646
+ /** Logout endpoint */
647
+ logout: createRoute("/api/auth/logout"),
648
+ /** Confirm sign in */
649
+ confirmSignIn: createRoute("/api/auth/confirm-signin")
650
+ };
651
+ var apiRoutes = {
652
+ /** Auth endpoints */
653
+ auth: {
654
+ logout: createRoute("/api/auth/logout"),
655
+ confirmSignIn: createRoute("/api/auth/confirm-signin")
656
+ }
657
+ };
658
+ var routes = {
659
+ admin: adminRoutes,
660
+ portal: portalRoutes,
661
+ auth: authRoutes,
662
+ api: apiRoutes
663
+ };
664
+ function matchesRoute(path, route) {
665
+ const pattern = route.path.replace(/:[^/]+/g, "[^/]+").replace(/\//g, "\\/");
666
+ const regex = new RegExp(`^${pattern}$`);
667
+ return regex.test(path);
668
+ }
669
+ function extractRouteParams(path, route) {
670
+ const paramNames = [];
671
+ const pattern = route.path.replace(/:([^/]+)/g, (_, name) => {
672
+ paramNames.push(name);
673
+ return "([^/]+)";
674
+ });
675
+ const regex = new RegExp(`^${pattern}$`);
676
+ const match = path.match(regex);
677
+ if (!match) return null;
678
+ const params = {};
679
+ paramNames.forEach((name, index) => {
680
+ params[name] = match[index + 1];
681
+ });
682
+ return params;
683
+ }
684
+ function navigateTo(url) {
685
+ if (typeof window !== "undefined") {
686
+ window.location.href = url;
687
+ }
688
+ }
689
+ function buildUrl(path, params) {
690
+ if (!params) return path;
691
+ const searchParams = new URLSearchParams();
692
+ for (const [key, value] of Object.entries(params)) {
693
+ if (value !== null && value !== void 0 && value !== "") {
694
+ searchParams.set(key, String(value));
695
+ }
696
+ }
697
+ const queryString = searchParams.toString();
698
+ return queryString ? `${path}?${queryString}` : path;
699
+ }
589
700
  export {
590
701
  AppError,
591
702
  AuthError,
@@ -595,7 +706,13 @@ export {
595
706
  ROUTES,
596
707
  USER_ROLES,
597
708
  ValidationError,
709
+ adminRoutes,
710
+ apiRoutes,
711
+ authRoutes,
712
+ buildUrl,
713
+ createRoute,
598
714
  debounce,
715
+ extractRouteParams,
599
716
  formatDate,
600
717
  getClientUser,
601
718
  getUser,
@@ -604,9 +721,13 @@ export {
604
721
  hasAccessToBrand,
605
722
  isAdminUser,
606
723
  isSuperAdminUser,
724
+ matchesRoute,
725
+ navigateTo,
726
+ portalRoutes,
607
727
  requireAdminAccess,
608
728
  requireAuth,
609
729
  requireBrandAccess,
730
+ routes,
610
731
  throttle,
611
732
  truncateText
612
733
  };
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"],"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 * @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"],"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","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 * @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"]}