@htlkg/astro 0.0.1

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 (70) hide show
  1. package/README.md +265 -0
  2. package/dist/chunk-33R4URZV.js +59 -0
  3. package/dist/chunk-33R4URZV.js.map +1 -0
  4. package/dist/chunk-64USRLVP.js +85 -0
  5. package/dist/chunk-64USRLVP.js.map +1 -0
  6. package/dist/chunk-WLOFOVCL.js +210 -0
  7. package/dist/chunk-WLOFOVCL.js.map +1 -0
  8. package/dist/chunk-WNMPTDCR.js +73 -0
  9. package/dist/chunk-WNMPTDCR.js.map +1 -0
  10. package/dist/chunk-Z2ZAL7KX.js +9 -0
  11. package/dist/chunk-Z2ZAL7KX.js.map +1 -0
  12. package/dist/chunk-ZQ4XMJH7.js +1 -0
  13. package/dist/chunk-ZQ4XMJH7.js.map +1 -0
  14. package/dist/htlkg/config.js +7 -0
  15. package/dist/htlkg/config.js.map +1 -0
  16. package/dist/htlkg/index.js +7 -0
  17. package/dist/htlkg/index.js.map +1 -0
  18. package/dist/index.js +64 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/middleware/index.js +168 -0
  21. package/dist/middleware/index.js.map +1 -0
  22. package/dist/utils/hydration.js +21 -0
  23. package/dist/utils/hydration.js.map +1 -0
  24. package/dist/utils/index.js +56 -0
  25. package/dist/utils/index.js.map +1 -0
  26. package/dist/utils/ssr.js +21 -0
  27. package/dist/utils/ssr.js.map +1 -0
  28. package/dist/utils/static.js +19 -0
  29. package/dist/utils/static.js.map +1 -0
  30. package/package.json +53 -0
  31. package/src/__mocks__/astro-middleware.ts +19 -0
  32. package/src/__mocks__/virtual-htlkg-config.ts +14 -0
  33. package/src/auth/LoginForm.vue +482 -0
  34. package/src/auth/LoginPage.astro +70 -0
  35. package/src/components/PageHeader.astro +145 -0
  36. package/src/components/Sidebar.astro +157 -0
  37. package/src/components/Topbar.astro +167 -0
  38. package/src/components/index.ts +9 -0
  39. package/src/htlkg/config.test.ts +165 -0
  40. package/src/htlkg/config.ts +242 -0
  41. package/src/htlkg/index.ts +245 -0
  42. package/src/htlkg/virtual-modules.test.ts +158 -0
  43. package/src/htlkg/virtual-modules.ts +81 -0
  44. package/src/index.ts +37 -0
  45. package/src/layouts/AdminLayout.astro +184 -0
  46. package/src/layouts/AuthLayout.astro +164 -0
  47. package/src/layouts/BrandLayout.astro +309 -0
  48. package/src/layouts/DefaultLayout.astro +25 -0
  49. package/src/layouts/PublicLayout.astro +153 -0
  50. package/src/layouts/index.ts +10 -0
  51. package/src/middleware/auth.ts +53 -0
  52. package/src/middleware/index.ts +31 -0
  53. package/src/middleware/route-guards.test.ts +182 -0
  54. package/src/middleware/route-guards.ts +218 -0
  55. package/src/patterns/admin/DetailPage.astro +195 -0
  56. package/src/patterns/admin/FormPage.astro +203 -0
  57. package/src/patterns/admin/ListPage.astro +178 -0
  58. package/src/patterns/admin/index.ts +9 -0
  59. package/src/patterns/brand/ConfigPage.astro +128 -0
  60. package/src/patterns/brand/PortalPage.astro +161 -0
  61. package/src/patterns/brand/index.ts +8 -0
  62. package/src/patterns/index.ts +8 -0
  63. package/src/utils/hydration.test.ts +154 -0
  64. package/src/utils/hydration.ts +151 -0
  65. package/src/utils/index.ts +9 -0
  66. package/src/utils/ssr.test.ts +235 -0
  67. package/src/utils/ssr.ts +139 -0
  68. package/src/utils/static.test.ts +144 -0
  69. package/src/utils/static.ts +144 -0
  70. package/src/vue-app-setup.ts +88 -0
package/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # @htlkg/astro
2
+
3
+ Astro integration, layouts, page patterns, middleware, and utilities for Hotelinking applications.
4
+
5
+ ## Overview
6
+
7
+ `@htlkg/astro` consolidates all Astro-specific functionality into a single package, including:
8
+
9
+ - **Astro Integration** - Zero-config setup with `htlkg()` integration
10
+ - **Layouts** - AdminLayout, BrandLayout, AuthLayout, PublicLayout
11
+ - **Page Patterns** - Reusable page templates for common scenarios
12
+ - **Middleware** - Authentication and route guards
13
+ - **Components** - Astro components (Sidebar, Topbar, PageHeader)
14
+ - **Utilities** - SSR, hydration, and static rendering helpers
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pnpm add @htlkg/astro
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### 1. Configure Astro Integration
25
+
26
+ ```javascript
27
+ // astro.config.mjs
28
+ import { defineConfig } from 'astro/config';
29
+ import { htlkg } from '@htlkg/astro';
30
+
31
+ export default defineConfig({
32
+ integrations: [
33
+ htlkg({
34
+ auth: {
35
+ enabled: true,
36
+ loginPage: '/login',
37
+ publicRoutes: ['/login', '/public'],
38
+ },
39
+ brandRoutes: {
40
+ enabled: true,
41
+ pattern: '/[brandId]',
42
+ },
43
+ }),
44
+ ],
45
+ });
46
+ ```
47
+
48
+ ### 2. Use Layouts
49
+
50
+ ```astro
51
+ ---
52
+ // src/pages/admin/brands.astro
53
+ import { AdminLayout } from '@htlkg/astro/layouts';
54
+ import { BrandsPage } from '@/components';
55
+
56
+ const user = Astro.locals.user;
57
+ ---
58
+
59
+ <AdminLayout user={user} title="Brands">
60
+ <BrandsPage />
61
+ </AdminLayout>
62
+ ```
63
+
64
+ ### 3. Apply Middleware
65
+
66
+ ```astro
67
+ ---
68
+ // src/pages/admin/users.astro
69
+ import { requireAdminAccess } from '@htlkg/astro/middleware';
70
+
71
+ export const prerender = false;
72
+
73
+ // Require admin access
74
+ await requireAdminAccess(Astro);
75
+ ---
76
+ ```
77
+
78
+ ## Package Structure
79
+
80
+ ```
81
+ @htlkg/astro/
82
+ ├── auth/ # Authentication pages
83
+ │ └── LoginPage.astro
84
+ ├── components/ # Astro components
85
+ │ ├── PageHeader.astro
86
+ │ ├── Sidebar.astro
87
+ │ └── Topbar.astro
88
+ ├── htlkg/ # Astro integration
89
+ │ ├── index.ts # Main integration
90
+ │ ├── config.ts # Configuration types
91
+ │ └── virtual-modules.ts
92
+ ├── layouts/ # Page layouts
93
+ │ ├── AdminLayout.astro
94
+ │ ├── BrandLayout.astro
95
+ │ ├── AuthLayout.astro
96
+ │ └── PublicLayout.astro
97
+ ├── middleware/ # Middleware & route guards
98
+ │ ├── auth.ts
99
+ │ ├── route-guards.ts
100
+ │ └── index.ts
101
+ ├── patterns/ # Page patterns
102
+ │ ├── admin/
103
+ │ │ ├── ListPage.astro
104
+ │ │ ├── DetailPage.astro
105
+ │ │ └── FormPage.astro
106
+ │ └── brand/
107
+ │ ├── ConfigPage.astro
108
+ │ └── PortalPage.astro
109
+ └── utils/ # Utilities
110
+ ├── hydration.ts # Client hydration helpers
111
+ ├── ssr.ts # Server-side rendering helpers
112
+ └── static.ts # Static generation helpers
113
+ ```
114
+
115
+ ## Exports
116
+
117
+ ### Main Package (`@htlkg/astro`)
118
+
119
+ ```typescript
120
+ import { htlkg } from '@htlkg/astro';
121
+ import type { HtlkgIntegrationOptions, AuthUser } from '@htlkg/astro';
122
+ ```
123
+
124
+ ### Layouts
125
+
126
+ ```typescript
127
+ import { AdminLayout } from '@htlkg/astro/layouts';
128
+ import { BrandLayout } from '@htlkg/astro/layouts';
129
+ import { AuthLayout } from '@htlkg/astro/layouts';
130
+ import { PublicLayout } from '@htlkg/astro/layouts';
131
+ ```
132
+
133
+ ### Middleware
134
+
135
+ ```typescript
136
+ import {
137
+ requireAdminAccess,
138
+ requireBrandAccess,
139
+ requireAuth,
140
+ } from '@htlkg/astro/middleware';
141
+ ```
142
+
143
+ ### Page Patterns
144
+
145
+ ```typescript
146
+ import { ListPage } from '@htlkg/astro/patterns/admin';
147
+ import { DetailPage } from '@htlkg/astro/patterns/admin';
148
+ import { FormPage } from '@htlkg/astro/patterns/admin';
149
+ import { ConfigPage } from '@htlkg/astro/patterns/brand';
150
+ ```
151
+
152
+ ### Components
153
+
154
+ ```typescript
155
+ import { Sidebar } from '@htlkg/astro/components';
156
+ import { Topbar } from '@htlkg/astro/components';
157
+ import { PageHeader } from '@htlkg/astro/components';
158
+ ```
159
+
160
+ ### Utilities
161
+
162
+ ```typescript
163
+ import { getHydrationStrategy } from '@htlkg/astro/utils/hydration';
164
+ import { getSSRConfig } from '@htlkg/astro/utils/ssr';
165
+ import { getStaticPaths } from '@htlkg/astro/utils/static';
166
+ ```
167
+
168
+ ## Features
169
+
170
+ ### Astro Integration
171
+
172
+ The `htlkg()` integration provides:
173
+
174
+ - Automatic middleware setup
175
+ - Route guard configuration
176
+ - Login page injection
177
+ - Brand route handling
178
+ - Virtual module configuration
179
+
180
+ ### Layouts
181
+
182
+ Pre-built layouts for common page types:
183
+
184
+ - **AdminLayout** - Admin portal pages with sidebar navigation
185
+ - **BrandLayout** - Brand-specific pages with brand context
186
+ - **AuthLayout** - Authentication pages (login, signup)
187
+ - **PublicLayout** - Public-facing pages
188
+
189
+ ### Middleware
190
+
191
+ Authentication and authorization middleware:
192
+
193
+ - **requireAuth** - Require authenticated user
194
+ - **requireAdminAccess** - Require admin role
195
+ - **requireBrandAccess** - Require brand access
196
+
197
+ ### Page Patterns
198
+
199
+ Reusable page templates:
200
+
201
+ - **ListPage** - List/table view with filters
202
+ - **DetailPage** - Detail view with tabs
203
+ - **FormPage** - Form view with validation
204
+ - **ConfigPage** - Configuration page
205
+
206
+ ## Configuration
207
+
208
+ ### Integration Options
209
+
210
+ ```typescript
211
+ interface HtlkgIntegrationOptions {
212
+ auth?: {
213
+ enabled: boolean;
214
+ loginPage?: string;
215
+ publicRoutes?: RoutePattern[];
216
+ protectedRoutes?: RoutePattern[];
217
+ };
218
+ brandRoutes?: {
219
+ enabled: boolean;
220
+ pattern?: string;
221
+ };
222
+ }
223
+ ```
224
+
225
+ ### Route Guards
226
+
227
+ ```typescript
228
+ interface RouteGuardConfig {
229
+ publicRoutes: RoutePattern[];
230
+ protectedRoutes: RoutePattern[];
231
+ loginPage: string;
232
+ brandRoutePattern?: RegExp;
233
+ }
234
+ ```
235
+
236
+ ## Dependencies
237
+
238
+ - `astro` - Astro framework
239
+ - `@astrojs/vue` - Vue integration
240
+ - `@astrojs/tailwind` - Tailwind CSS integration
241
+ - `@htlkg/core` - Core utilities and types
242
+ - `@htlkg/components` - Vue components
243
+ - `vue` - Vue framework
244
+ - `tailwindcss` - Tailwind CSS
245
+
246
+ ## Development
247
+
248
+ ```bash
249
+ # Build package
250
+ pnpm build
251
+
252
+ # Watch mode
253
+ pnpm dev
254
+
255
+ # Run tests
256
+ pnpm test
257
+ ```
258
+
259
+ ## Migration
260
+
261
+ If migrating from `@htlkg/pages` and `@htlkg/integrations`, see [MIGRATION_ASTRO_PACKAGE.md](../../MIGRATION_ASTRO_PACKAGE.md).
262
+
263
+ ## License
264
+
265
+ Private - Hotelinking internal use only
@@ -0,0 +1,59 @@
1
+ // src/utils/static.ts
2
+ function generateStaticPaths(items, mapper) {
3
+ return items.map(mapper);
4
+ }
5
+ function generatePaginatedPaths(items, pageSize, mapper) {
6
+ const totalPages = Math.ceil(items.length / pageSize);
7
+ const paths = [];
8
+ for (let page = 1; page <= totalPages; page++) {
9
+ const start = (page - 1) * pageSize;
10
+ const end = start + pageSize;
11
+ const pageItems = items.slice(start, end);
12
+ paths.push(mapper(page, pageItems, totalPages));
13
+ }
14
+ return paths;
15
+ }
16
+ async function generateNestedPaths(items, mapper) {
17
+ const nestedPaths = await Promise.all(items.map(mapper));
18
+ return nestedPaths.flat();
19
+ }
20
+ function chunkArray(array, size) {
21
+ const chunks = [];
22
+ for (let i = 0; i < array.length; i += size) {
23
+ chunks.push(array.slice(i, i + size));
24
+ }
25
+ return chunks;
26
+ }
27
+ function sortItems(items, key, order = "asc") {
28
+ return [...items].sort((a, b) => {
29
+ const aVal = a[key];
30
+ const bVal = b[key];
31
+ if (aVal < bVal) return order === "asc" ? -1 : 1;
32
+ if (aVal > bVal) return order === "asc" ? 1 : -1;
33
+ return 0;
34
+ });
35
+ }
36
+ function filterItems(items, predicate) {
37
+ return items.filter(predicate);
38
+ }
39
+ function groupItems(items, key) {
40
+ return items.reduce((groups, item) => {
41
+ const groupKey = String(item[key]);
42
+ if (!groups[groupKey]) {
43
+ groups[groupKey] = [];
44
+ }
45
+ groups[groupKey].push(item);
46
+ return groups;
47
+ }, {});
48
+ }
49
+
50
+ export {
51
+ generateStaticPaths,
52
+ generatePaginatedPaths,
53
+ generateNestedPaths,
54
+ chunkArray,
55
+ sortItems,
56
+ filterItems,
57
+ groupItems
58
+ };
59
+ //# sourceMappingURL=chunk-33R4URZV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/static.ts"],"sourcesContent":["/**\n * Static Generation Utilities\n * \n * Helper functions for static site generation in Astro.\n */\n\n/**\n * Generate static paths from array of items\n * \n * @example\n * ```ts\n * export async function getStaticPaths() {\n * const brands = await getBrands();\n * return generateStaticPaths(brands, (brand) => ({\n * params: { brandId: brand.id },\n * props: { brand }\n * }));\n * }\n * ```\n */\nexport function generateStaticPaths<T, P = any>(\n items: T[],\n mapper: (item: T) => { params: Record<string, string | number>; props?: P }\n): Array<{ params: Record<string, string | number>; props?: P }> {\n return items.map(mapper);\n}\n\n/**\n * Generate paginated static paths\n * \n * @example\n * ```ts\n * export async function getStaticPaths() {\n * const items = await getItems();\n * return generatePaginatedPaths(items, 10, (page, items) => ({\n * params: { page: page.toString() },\n * props: { items, page }\n * }));\n * }\n * ```\n */\nexport function generatePaginatedPaths<T, P = any>(\n items: T[],\n pageSize: number,\n mapper: (\n page: number,\n pageItems: T[],\n totalPages: number\n ) => { params: Record<string, string | number>; props?: P }\n): Array<{ params: Record<string, string | number>; props?: P }> {\n const totalPages = Math.ceil(items.length / pageSize);\n const paths: Array<{ params: Record<string, string | number>; props?: P }> = [];\n \n for (let page = 1; page <= totalPages; page++) {\n const start = (page - 1) * pageSize;\n const end = start + pageSize;\n const pageItems = items.slice(start, end);\n \n paths.push(mapper(page, pageItems, totalPages));\n }\n \n return paths;\n}\n\n/**\n * Generate nested static paths\n * \n * @example\n * ```ts\n * export async function getStaticPaths() {\n * const brands = await getBrands();\n * return generateNestedPaths(brands, async (brand) => {\n * const products = await getProducts(brand.id);\n * return products.map(product => ({\n * params: { brandId: brand.id, productId: product.id },\n * props: { brand, product }\n * }));\n * });\n * }\n * ```\n */\nexport async function generateNestedPaths<T, P = any>(\n items: T[],\n mapper: (item: T) => Promise<Array<{ params: Record<string, string | number>; props?: P }>>\n): Promise<Array<{ params: Record<string, string | number>; props?: P }>> {\n const nestedPaths = await Promise.all(items.map(mapper));\n return nestedPaths.flat();\n}\n\n/**\n * Chunk array into smaller arrays\n */\nexport function chunkArray<T>(array: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < array.length; i += size) {\n chunks.push(array.slice(i, i + size));\n }\n return chunks;\n}\n\n/**\n * Sort items for static generation\n */\nexport function sortItems<T>(\n items: T[],\n key: keyof T,\n order: 'asc' | 'desc' = 'asc'\n): T[] {\n return [...items].sort((a, b) => {\n const aVal = a[key];\n const bVal = b[key];\n \n if (aVal < bVal) return order === 'asc' ? -1 : 1;\n if (aVal > bVal) return order === 'asc' ? 1 : -1;\n return 0;\n });\n}\n\n/**\n * Filter items for static generation\n */\nexport function filterItems<T>(\n items: T[],\n predicate: (item: T) => boolean\n): T[] {\n return items.filter(predicate);\n}\n\n/**\n * Group items by key\n */\nexport function groupItems<T>(\n items: T[],\n key: keyof T\n): Record<string, T[]> {\n return items.reduce((groups, item) => {\n const groupKey = String(item[key]);\n if (!groups[groupKey]) {\n groups[groupKey] = [];\n }\n groups[groupKey].push(item);\n return groups;\n }, {} as Record<string, T[]>);\n}\n"],"mappings":";AAoBO,SAAS,oBACd,OACA,QAC+D;AAC/D,SAAO,MAAM,IAAI,MAAM;AACzB;AAgBO,SAAS,uBACd,OACA,UACA,QAK+D;AAC/D,QAAM,aAAa,KAAK,KAAK,MAAM,SAAS,QAAQ;AACpD,QAAM,QAAuE,CAAC;AAE9E,WAAS,OAAO,GAAG,QAAQ,YAAY,QAAQ;AAC7C,UAAM,SAAS,OAAO,KAAK;AAC3B,UAAM,MAAM,QAAQ;AACpB,UAAM,YAAY,MAAM,MAAM,OAAO,GAAG;AAExC,UAAM,KAAK,OAAO,MAAM,WAAW,UAAU,CAAC;AAAA,EAChD;AAEA,SAAO;AACT;AAmBA,eAAsB,oBACpB,OACA,QACwE;AACxE,QAAM,cAAc,MAAM,QAAQ,IAAI,MAAM,IAAI,MAAM,CAAC;AACvD,SAAO,YAAY,KAAK;AAC1B;AAKO,SAAS,WAAc,OAAY,MAAqB;AAC7D,QAAM,SAAgB,CAAC;AACvB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,MAAM;AAC3C,WAAO,KAAK,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC;AAAA,EACtC;AACA,SAAO;AACT;AAKO,SAAS,UACd,OACA,KACA,QAAwB,OACnB;AACL,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC/B,UAAM,OAAO,EAAE,GAAG;AAClB,UAAM,OAAO,EAAE,GAAG;AAElB,QAAI,OAAO,KAAM,QAAO,UAAU,QAAQ,KAAK;AAC/C,QAAI,OAAO,KAAM,QAAO,UAAU,QAAQ,IAAI;AAC9C,WAAO;AAAA,EACT,CAAC;AACH;AAKO,SAAS,YACd,OACA,WACK;AACL,SAAO,MAAM,OAAO,SAAS;AAC/B;AAKO,SAAS,WACd,OACA,KACqB;AACrB,SAAO,MAAM,OAAO,CAAC,QAAQ,SAAS;AACpC,UAAM,WAAW,OAAO,KAAK,GAAG,CAAC;AACjC,QAAI,CAAC,OAAO,QAAQ,GAAG;AACrB,aAAO,QAAQ,IAAI,CAAC;AAAA,IACtB;AACA,WAAO,QAAQ,EAAE,KAAK,IAAI;AAC1B,WAAO;AAAA,EACT,GAAG,CAAC,CAAwB;AAC9B;","names":[]}
@@ -0,0 +1,85 @@
1
+ // src/utils/hydration.ts
2
+ function serializeForHydration(data) {
3
+ return JSON.stringify(data, (key, value) => {
4
+ if (typeof value === "function") {
5
+ return void 0;
6
+ }
7
+ if (value === void 0) {
8
+ return { __type: "undefined" };
9
+ }
10
+ return value;
11
+ });
12
+ }
13
+ function deserializeFromHydration(json) {
14
+ return JSON.parse(json, (key, value) => {
15
+ if (value && value.__type === "undefined") {
16
+ return void 0;
17
+ }
18
+ return value;
19
+ });
20
+ }
21
+ function createHydrationScript(variableName, data) {
22
+ const serialized = serializeForHydration(data);
23
+ return `window.${variableName} = ${serialized};`;
24
+ }
25
+ function createHydrationScripts(data) {
26
+ return Object.entries(data).map(([key, value]) => createHydrationScript(key, value)).join("\n");
27
+ }
28
+ function getHydratedData(variableName) {
29
+ if (typeof window === "undefined") {
30
+ return null;
31
+ }
32
+ const data = window[variableName];
33
+ return data ? deserializeFromHydration(JSON.stringify(data)) : null;
34
+ }
35
+ function shouldHydrate(strategy, options) {
36
+ if (typeof window === "undefined") {
37
+ return false;
38
+ }
39
+ switch (strategy) {
40
+ case "load":
41
+ return true;
42
+ case "idle":
43
+ return "requestIdleCallback" in window;
44
+ case "visible":
45
+ return "IntersectionObserver" in window;
46
+ case "media":
47
+ if (!options?.mediaQuery) return false;
48
+ return window.matchMedia(options.mediaQuery).matches;
49
+ case "only":
50
+ return false;
51
+ default:
52
+ return true;
53
+ }
54
+ }
55
+ function createIslandProps(props) {
56
+ const cleanProps = {};
57
+ for (const [key, value] of Object.entries(props)) {
58
+ if (typeof value === "function") {
59
+ continue;
60
+ }
61
+ if (value === void 0) {
62
+ continue;
63
+ }
64
+ cleanProps[key] = value;
65
+ }
66
+ return cleanProps;
67
+ }
68
+ function mergeProps(serverProps, clientProps) {
69
+ return {
70
+ ...serverProps,
71
+ ...clientProps
72
+ };
73
+ }
74
+
75
+ export {
76
+ serializeForHydration,
77
+ deserializeFromHydration,
78
+ createHydrationScript,
79
+ createHydrationScripts,
80
+ getHydratedData,
81
+ shouldHydrate,
82
+ createIslandProps,
83
+ mergeProps
84
+ };
85
+ //# sourceMappingURL=chunk-64USRLVP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/hydration.ts"],"sourcesContent":["/**\n * Hydration Utilities\n * \n * Helper functions for Vue component hydration in Astro.\n */\n\n/**\n * Serialize data for client-side hydration\n * Safely handles dates, functions, and circular references\n */\nexport function serializeForHydration<T>(data: T): string {\n return JSON.stringify(data, (key, value) => {\n // Skip functions\n if (typeof value === 'function') {\n return undefined;\n }\n \n // Handle undefined\n if (value === undefined) {\n return { __type: 'undefined' };\n }\n \n return value;\n });\n}\n\n/**\n * Deserialize data on client-side\n */\nexport function deserializeFromHydration<T>(json: string): T {\n return JSON.parse(json, (key, value) => {\n // Handle undefined\n if (value && value.__type === 'undefined') {\n return undefined;\n }\n \n return value;\n });\n}\n\n/**\n * Create hydration script for Vue components\n * \n * @example\n * ```astro\n * <script set:html={createHydrationScript('userData', user)} />\n * ```\n */\nexport function createHydrationScript(\n variableName: string,\n data: any\n): string {\n const serialized = serializeForHydration(data);\n return `window.${variableName} = ${serialized};`;\n}\n\n/**\n * Create multiple hydration scripts\n */\nexport function createHydrationScripts(\n data: Record<string, any>\n): string {\n return Object.entries(data)\n .map(([key, value]) => createHydrationScript(key, value))\n .join('\\n');\n}\n\n/**\n * Get hydrated data on client-side\n */\nexport function getHydratedData<T>(variableName: string): T | null {\n if (typeof window === 'undefined') {\n return null;\n }\n \n const data = (window as any)[variableName];\n return data ? deserializeFromHydration(JSON.stringify(data)) : null;\n}\n\n/**\n * Check if component should hydrate\n */\nexport function shouldHydrate(\n strategy: 'load' | 'idle' | 'visible' | 'media' | 'only',\n options?: {\n mediaQuery?: string;\n }\n): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n \n switch (strategy) {\n case 'load':\n return true;\n \n case 'idle':\n return 'requestIdleCallback' in window;\n \n case 'visible':\n return 'IntersectionObserver' in window;\n \n case 'media':\n if (!options?.mediaQuery) return false;\n return window.matchMedia(options.mediaQuery).matches;\n \n case 'only':\n return false;\n \n default:\n return true;\n }\n}\n\n/**\n * Create Vue island props\n * Prepares props for Vue component islands\n */\nexport function createIslandProps<T extends Record<string, any>>(\n props: T\n): T {\n // Remove functions and non-serializable values\n const cleanProps: any = {};\n \n for (const [key, value] of Object.entries(props)) {\n if (typeof value === 'function') {\n continue;\n }\n \n if (value === undefined) {\n continue;\n }\n \n cleanProps[key] = value;\n }\n \n return cleanProps;\n}\n\n/**\n * Merge server and client props\n */\nexport function mergeProps<T extends Record<string, any>>(\n serverProps: T,\n clientProps: Partial<T>\n): T {\n return {\n ...serverProps,\n ...clientProps,\n };\n}\n"],"mappings":";AAUO,SAAS,sBAAyB,MAAiB;AACxD,SAAO,KAAK,UAAU,MAAM,CAAC,KAAK,UAAU;AAE1C,QAAI,OAAO,UAAU,YAAY;AAC/B,aAAO;AAAA,IACT;AAGA,QAAI,UAAU,QAAW;AACvB,aAAO,EAAE,QAAQ,YAAY;AAAA,IAC/B;AAEA,WAAO;AAAA,EACT,CAAC;AACH;AAKO,SAAS,yBAA4B,MAAiB;AAC3D,SAAO,KAAK,MAAM,MAAM,CAAC,KAAK,UAAU;AAEtC,QAAI,SAAS,MAAM,WAAW,aAAa;AACzC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,CAAC;AACH;AAUO,SAAS,sBACd,cACA,MACQ;AACR,QAAM,aAAa,sBAAsB,IAAI;AAC7C,SAAO,UAAU,YAAY,MAAM,UAAU;AAC/C;AAKO,SAAS,uBACd,MACQ;AACR,SAAO,OAAO,QAAQ,IAAI,EACvB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,sBAAsB,KAAK,KAAK,CAAC,EACvD,KAAK,IAAI;AACd;AAKO,SAAS,gBAAmB,cAAgC;AACjE,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AAEA,QAAM,OAAQ,OAAe,YAAY;AACzC,SAAO,OAAO,yBAAyB,KAAK,UAAU,IAAI,CAAC,IAAI;AACjE;AAKO,SAAS,cACd,UACA,SAGS;AACT,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AAEA,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AACH,aAAO,yBAAyB;AAAA,IAElC,KAAK;AACH,aAAO,0BAA0B;AAAA,IAEnC,KAAK;AACH,UAAI,CAAC,SAAS,WAAY,QAAO;AACjC,aAAO,OAAO,WAAW,QAAQ,UAAU,EAAE;AAAA,IAE/C,KAAK;AACH,aAAO;AAAA,IAET;AACE,aAAO;AAAA,EACX;AACF;AAMO,SAAS,kBACd,OACG;AAEH,QAAM,aAAkB,CAAC;AAEzB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,OAAO,UAAU,YAAY;AAC/B;AAAA,IACF;AAEA,QAAI,UAAU,QAAW;AACvB;AAAA,IACF;AAEA,eAAW,GAAG,IAAI;AAAA,EACpB;AAEA,SAAO;AACT;AAKO,SAAS,WACd,aACA,aACG;AACH,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AACF;","names":[]}
@@ -0,0 +1,210 @@
1
+ // src/htlkg/index.ts
2
+ import tailwind from "@astrojs/tailwind";
3
+ import vue from "@astrojs/vue";
4
+
5
+ // src/htlkg/virtual-modules.ts
6
+ function serializePattern(pattern) {
7
+ if (pattern instanceof RegExp) {
8
+ return `new RegExp(${JSON.stringify(pattern.source)}, ${JSON.stringify(pattern.flags)})`;
9
+ }
10
+ return JSON.stringify(pattern);
11
+ }
12
+ function serializePatterns(patterns) {
13
+ if (!patterns || patterns.length === 0) return "[]";
14
+ return `[${patterns.map(serializePattern).join(", ")}]`;
15
+ }
16
+ function createVirtualModulePlugin(authConfig, loginPageConfig, amplifyConfig) {
17
+ return {
18
+ name: "htlkg-config",
19
+ resolveId(id) {
20
+ if (id === "virtual:htlkg-config") {
21
+ return "\0virtual:htlkg-config";
22
+ }
23
+ },
24
+ load(id) {
25
+ if (id === "\0virtual:htlkg-config") {
26
+ const serializedAuthConfig = `{
27
+ publicRoutes: ${serializePatterns(authConfig.publicRoutes || [])},
28
+ authenticatedRoutes: ${serializePatterns(authConfig.authenticatedRoutes || [])},
29
+ adminRoutes: ${serializePatterns(authConfig.adminRoutes || [])},
30
+ brandRoutes: ${JSON.stringify(authConfig.brandRoutes || [])},
31
+ loginUrl: ${JSON.stringify(authConfig.loginUrl || "/login")}
32
+ }`;
33
+ const serializedAmplifyConfig = amplifyConfig ? JSON.stringify(amplifyConfig) : "null";
34
+ const serializedLoginPageConfig = loginPageConfig !== false && loginPageConfig !== null ? JSON.stringify(loginPageConfig) : "null";
35
+ return `export const routeGuardConfig = ${serializedAuthConfig};
36
+ export const loginPageConfig = ${serializedLoginPageConfig};
37
+ export const amplifyConfig = ${serializedAmplifyConfig};`;
38
+ }
39
+ }
40
+ };
41
+ }
42
+ var virtualModuleTypes = `
43
+ declare module 'virtual:htlkg-config' {
44
+ import type { RouteGuardConfig, LoginPageConfig } from '@htlkg/astro/htlkg/config';
45
+
46
+ export const routeGuardConfig: RouteGuardConfig;
47
+ export const loginPageConfig: LoginPageConfig | null;
48
+ export const amplifyConfig: Record<string, unknown> | null;
49
+ }
50
+ `;
51
+
52
+ // src/htlkg/index.ts
53
+ var DEFAULT_ENV_VARS = [
54
+ "PUBLIC_COGNITO_USER_POOL_ID",
55
+ "PUBLIC_COGNITO_USER_POOL_CLIENT_ID"
56
+ ];
57
+ function htlkg(options = {}) {
58
+ const {
59
+ auth = {},
60
+ loginPage = { path: "/login", title: "Sign In", redirectUrl: "/admin" },
61
+ validateEnv = true,
62
+ requiredEnvVars = DEFAULT_ENV_VARS,
63
+ tailwind: tailwindOptions,
64
+ amplify
65
+ } = options;
66
+ const integrations = [];
67
+ if (tailwindOptions !== false) {
68
+ const tailwindConfig = typeof tailwindOptions === "object" ? tailwindOptions : void 0;
69
+ integrations.push(
70
+ tailwind(tailwindConfig)
71
+ );
72
+ }
73
+ integrations.push(
74
+ vue({
75
+ appEntrypoint: "@htlkg/astro/vue-app-setup"
76
+ })
77
+ );
78
+ integrations.push({
79
+ name: "@htlkg/astro",
80
+ hooks: {
81
+ "astro:config:setup": ({
82
+ config,
83
+ updateConfig,
84
+ addMiddleware,
85
+ injectRoute,
86
+ logger
87
+ }) => {
88
+ try {
89
+ const hasVue = config.integrations.some(
90
+ (i) => i.name === "@astrojs/vue"
91
+ );
92
+ if (hasVue) {
93
+ logger.info("Vue integration configured with Amplify app setup");
94
+ }
95
+ if (amplify) {
96
+ logger.info("Amplify configuration provided - will be configured on first request");
97
+ } else {
98
+ logger.info("No Amplify configuration provided - will use environment variables");
99
+ }
100
+ if (validateEnv && !amplify) {
101
+ const missing = requiredEnvVars.filter(
102
+ (varName) => !process.env[varName]
103
+ );
104
+ if (missing.length > 0) {
105
+ logger.warn(
106
+ `Missing required environment variables: ${missing.join(", ")}
107
+ Authentication may not work correctly. Please set these in your .env file:
108
+ ${missing.map((v) => ` - ${v}`).join("\n")}`
109
+ );
110
+ } else {
111
+ logger.info("All required environment variables are present");
112
+ }
113
+ }
114
+ try {
115
+ const virtualModulePlugin = createVirtualModulePlugin(
116
+ auth,
117
+ loginPage,
118
+ amplify || null
119
+ );
120
+ updateConfig({
121
+ vite: {
122
+ plugins: [virtualModulePlugin]
123
+ }
124
+ });
125
+ } catch (error) {
126
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
127
+ logger.error(
128
+ `Failed to create virtual module for route configuration: ${errorMsg}`
129
+ );
130
+ throw error;
131
+ }
132
+ try {
133
+ addMiddleware({
134
+ entrypoint: "@htlkg/astro/middleware",
135
+ order: "pre"
136
+ });
137
+ logger.info("Authentication middleware injected successfully");
138
+ } catch (error) {
139
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
140
+ logger.error(`Failed to inject middleware: ${errorMsg}`);
141
+ throw error;
142
+ }
143
+ const vueIntegrationIndex = config.integrations.findIndex(
144
+ (i) => i.name === "@astrojs/vue"
145
+ );
146
+ if (vueIntegrationIndex === -1) {
147
+ logger.warn(
148
+ "@astrojs/vue integration not found.\nThe htlkg integration should have added it automatically.\nIf you see this warning, there may be an integration ordering issue."
149
+ );
150
+ } else {
151
+ logger.info("Vue app setup with Amplify configuration enabled");
152
+ }
153
+ const hasTailwind = config.integrations.some(
154
+ (i) => i.name === "@astrojs/tailwind" || i.name === "astro:tailwind"
155
+ );
156
+ if (hasTailwind) {
157
+ logger.info("Tailwind CSS integration configured");
158
+ }
159
+ if (loginPage !== false) {
160
+ try {
161
+ const loginPath = loginPage.path || "/login";
162
+ injectRoute({
163
+ pattern: loginPath,
164
+ entrypoint: "@htlkg/astro/auth/LoginPage.astro",
165
+ prerender: false
166
+ });
167
+ logger.info(`Injected default login page at ${loginPath}`);
168
+ } catch (error) {
169
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
170
+ logger.warn(`Failed to inject login page: ${errorMsg}`);
171
+ }
172
+ }
173
+ logger.info("htlkg integration configured successfully");
174
+ } catch (error) {
175
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
176
+ logger.error(
177
+ `Failed to configure htlkg integration: ${errorMsg}`
178
+ );
179
+ throw error;
180
+ }
181
+ },
182
+ "astro:config:done": ({ injectTypes }) => {
183
+ injectTypes({
184
+ filename: "htlkg.d.ts",
185
+ content: `
186
+ import type { AuthUser } from '@htlkg/core/types';
187
+
188
+ declare global {
189
+ namespace App {
190
+ interface Locals {
191
+ user: AuthUser | null;
192
+ }
193
+ }
194
+ }
195
+
196
+ ${virtualModuleTypes}
197
+
198
+ export {};
199
+ `
200
+ });
201
+ }
202
+ }
203
+ });
204
+ return integrations.length === 1 ? integrations[0] : integrations;
205
+ }
206
+
207
+ export {
208
+ htlkg
209
+ };
210
+ //# sourceMappingURL=chunk-WLOFOVCL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/htlkg/index.ts","../src/htlkg/virtual-modules.ts"],"sourcesContent":["/**\n * htlkg Astro Integration\n * \n * Provides zero-config setup for Hotelinking applications with:\n * - Tailwind CSS integration\n * - Vue 3 integration with Amplify setup\n * - Authentication middleware\n * - Route guards\n * - Login page generation\n */\n\nimport tailwind from '@astrojs/tailwind';\nimport vue from '@astrojs/vue';\nimport type { AstroIntegration } from 'astro';\nimport type { HtlkgIntegrationOptions } from './config.js';\nimport { createVirtualModulePlugin, virtualModuleTypes } from './virtual-modules.js';\n\n/**\n * Default environment variables required for AWS Amplify authentication\n */\nconst DEFAULT_ENV_VARS = [\n\t'PUBLIC_COGNITO_USER_POOL_ID',\n\t'PUBLIC_COGNITO_USER_POOL_CLIENT_ID'\n];\n\n/**\n * htlkg Astro integration that provides zero-config authentication setup.\n *\n * This integration automatically:\n * - Includes Tailwind CSS integration (can be disabled)\n * - Includes Vue 3 integration with Amplify and Nanostores setup\n * - Injects authentication middleware for AWS Amplify\n * - Configures route guards based on declarative configuration\n * - Validates required environment variables (optional)\n * - Injects TypeScript types for Astro.locals.user\n * - Provides a default login page (optional)\n *\n * @param options - Configuration options for the integration\n * @returns Astro integration object or array of integrations\n *\n * @example\n * // astro.config.mjs\n * import { htlkg } from '@htlkg/astro';\n *\n * export default defineConfig({\n * integrations: [\n * htlkg({\n * tailwind: { configFile: './tailwind.config.mjs' },\n * auth: {\n * publicRoutes: ['/login', '/'],\n * adminRoutes: [/^\\/admin/],\n * loginUrl: '/login'\n * }\n * })\n * ]\n * });\n */\nexport function htlkg(\n\toptions: HtlkgIntegrationOptions = {},\n): AstroIntegration | AstroIntegration[] {\n\tconst {\n\t\tauth = {},\n\t\tloginPage = { path: '/login', title: 'Sign In', redirectUrl: '/admin' },\n\t\tvalidateEnv = true,\n\t\trequiredEnvVars = DEFAULT_ENV_VARS,\n\t\ttailwind: tailwindOptions,\n\t\tamplify,\n\t} = options;\n\n\tconst integrations: AstroIntegration[] = [];\n\n\t// Add Tailwind integration (enabled by default)\n\tif (tailwindOptions !== false) {\n\t\tconst tailwindConfig =\n\t\t\ttypeof tailwindOptions === 'object' ? tailwindOptions : undefined;\n\t\tintegrations.push(\n\t\t\ttailwind(tailwindConfig as Parameters<typeof tailwind>[0]),\n\t\t);\n\t}\n\n\t// Add Vue integration with Amplify setup entrypoint\n\t// Use package import specifier that Vite can resolve\n\tintegrations.push(\n\t\tvue({\n\t\t\tappEntrypoint: '@htlkg/astro/vue-app-setup',\n\t\t}),\n\t);\n\n\t// Add the main htlkg integration\n\tintegrations.push({\n\t\tname: '@htlkg/astro',\n\t\thooks: {\n\t\t\t'astro:config:setup': ({\n\t\t\t\tconfig,\n\t\t\t\tupdateConfig,\n\t\t\t\taddMiddleware,\n\t\t\t\tinjectRoute,\n\t\t\t\tlogger,\n\t\t\t}) => {\n\t\t\t\ttry {\n\t\t\t\t\t// 1. Verify Vue integration is present\n\t\t\t\t\tconst hasVue = config.integrations.some(\n\t\t\t\t\t\t(i) => i.name === '@astrojs/vue',\n\t\t\t\t\t);\n\t\t\t\t\tif (hasVue) {\n\t\t\t\t\t\tlogger.info('Vue integration configured with Amplify app setup');\n\t\t\t\t\t}\n\n\t\t\t\t\t// 2. Amplify will be configured by the middleware on first request\n\t\t\t\t\tif (amplify) {\n\t\t\t\t\t\tlogger.info('Amplify configuration provided - will be configured on first request');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.info('No Amplify configuration provided - will use environment variables');\n\t\t\t\t\t}\n\n\t\t\t\t\t// 3. Validate environment variables (only if not using amplify_outputs.json)\n\t\t\t\t\tif (validateEnv && !amplify) {\n\t\t\t\t\t\tconst missing = requiredEnvVars.filter(\n\t\t\t\t\t\t\t(varName) => !process.env[varName],\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (missing.length > 0) {\n\t\t\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\t\t`Missing required environment variables: ${missing.join(', ')}\\nAuthentication may not work correctly. Please set these in your .env file:\\n${missing.map((v) => ` - ${v}`).join('\\n')}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlogger.info('All required environment variables are present');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// 4. Create Vite virtual module plugin to pass configuration to middleware and pages\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst virtualModulePlugin = createVirtualModulePlugin(\n\t\t\t\t\t\t\tauth,\n\t\t\t\t\t\t\tloginPage,\n\t\t\t\t\t\t\tamplify || null\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tupdateConfig({\n\t\t\t\t\t\t\tvite: {\n\t\t\t\t\t\t\t\tplugins: [virtualModulePlugin],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst errorMsg =\n\t\t\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error';\n\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t`Failed to create virtual module for route configuration: ${errorMsg}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// 5. Inject middleware\n\t\t\t\t\ttry {\n\t\t\t\t\t\taddMiddleware({\n\t\t\t\t\t\t\tentrypoint: '@htlkg/astro/middleware',\n\t\t\t\t\t\t\torder: 'pre',\n\t\t\t\t\t\t});\n\t\t\t\t\t\tlogger.info('Authentication middleware injected successfully');\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst errorMsg =\n\t\t\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error';\n\t\t\t\t\t\tlogger.error(`Failed to inject middleware: ${errorMsg}`);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// 6. Verify Vue app entrypoint is configured\n\t\t\t\t\tconst vueIntegrationIndex = config.integrations.findIndex(\n\t\t\t\t\t\t(i) => i.name === '@astrojs/vue',\n\t\t\t\t\t);\n\n\t\t\t\t\tif (vueIntegrationIndex === -1) {\n\t\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\t'@astrojs/vue integration not found.\\n' +\n\t\t\t\t\t\t\t\t'The htlkg integration should have added it automatically.\\n' +\n\t\t\t\t\t\t\t\t'If you see this warning, there may be an integration ordering issue.',\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.info('Vue app setup with Amplify configuration enabled');\n\t\t\t\t\t}\n\n\t\t\t\t\t// 7. Verify Tailwind integration\n\t\t\t\t\tconst hasTailwind = config.integrations.some(\n\t\t\t\t\t\t(i) =>\n\t\t\t\t\t\t\ti.name === '@astrojs/tailwind' || i.name === 'astro:tailwind',\n\t\t\t\t\t);\n\n\t\t\t\t\tif (hasTailwind) {\n\t\t\t\t\t\tlogger.info('Tailwind CSS integration configured');\n\t\t\t\t\t}\n\n\t\t\t\t\t// 8. Inject login page route if enabled\n\t\t\t\t\tif (loginPage !== false) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst loginPath = loginPage.path || '/login';\n\t\t\t\t\t\t\tinjectRoute({\n\t\t\t\t\t\t\t\tpattern: loginPath,\n\t\t\t\t\t\t\t\tentrypoint: '@htlkg/astro/auth/LoginPage.astro',\n\t\t\t\t\t\t\t\tprerender: false,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tlogger.info(`Injected default login page at ${loginPath}`);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconst errorMsg =\n\t\t\t\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error';\n\t\t\t\t\t\t\tlogger.warn(`Failed to inject login page: ${errorMsg}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlogger.info('htlkg integration configured successfully');\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst errorMsg =\n\t\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error';\n\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t`Failed to configure htlkg integration: ${errorMsg}`,\n\t\t\t\t\t);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t\t'astro:config:done': ({ injectTypes }) => {\n\t\t\t\t// Inject TypeScript types for Astro.locals and virtual module\n\t\t\t\tinjectTypes({\n\t\t\t\t\tfilename: 'htlkg.d.ts',\n\t\t\t\t\tcontent: `\nimport type { AuthUser } from '@htlkg/core/types';\n\ndeclare global {\n namespace App {\n interface Locals {\n user: AuthUser | null;\n }\n }\n}\n\n${virtualModuleTypes}\n\nexport {};\n`,\n\t\t\t\t});\n\t\t\t},\n\t\t},\n\t});\n\n\t// Return single integration or array based on what was added\n\treturn integrations.length === 1 ? integrations[0] : integrations;\n}\n","/**\n * Virtual module setup for htlkg integration\n * Creates Vite virtual modules to pass configuration to middleware and pages\n */\n\nimport type { RouteGuardConfig, LoginPageConfig, RoutePattern } from './config.js';\n\n/**\n * Serialize a route pattern (RegExp or string) to JavaScript code\n */\nfunction serializePattern(pattern: RegExp | string): string {\n\tif (pattern instanceof RegExp) {\n\t\treturn `new RegExp(${JSON.stringify(pattern.source)}, ${JSON.stringify(pattern.flags)})`;\n\t}\n\treturn JSON.stringify(pattern);\n}\n\n/**\n * Serialize an array of route patterns to JavaScript code\n */\nfunction serializePatterns(patterns: RoutePattern[]): string {\n\tif (!patterns || patterns.length === 0) return '[]';\n\treturn `[${patterns.map(serializePattern).join(', ')}]`;\n}\n\n/**\n * Create the virtual module plugin for Vite\n * This plugin provides configuration to middleware and pages at runtime\n */\nexport function createVirtualModulePlugin(\n\tauthConfig: RouteGuardConfig,\n\tloginPageConfig: LoginPageConfig | false | null,\n\tamplifyConfig: Record<string, unknown> | null\n) {\n\treturn {\n\t\tname: 'htlkg-config',\n\t\tresolveId(id: string) {\n\t\t\tif (id === 'virtual:htlkg-config') {\n\t\t\t\treturn '\\0virtual:htlkg-config';\n\t\t\t}\n\t\t},\n\t\tload(id: string) {\n\t\t\tif (id === '\\0virtual:htlkg-config') {\n\t\t\t\t// Serialize auth configuration with RegExp support\n\t\t\t\tconst serializedAuthConfig = `{\n\t\t\t\t\tpublicRoutes: ${serializePatterns(authConfig.publicRoutes || [])},\n\t\t\t\t\tauthenticatedRoutes: ${serializePatterns(authConfig.authenticatedRoutes || [])},\n\t\t\t\t\tadminRoutes: ${serializePatterns(authConfig.adminRoutes || [])},\n\t\t\t\t\tbrandRoutes: ${JSON.stringify(authConfig.brandRoutes || [])},\n\t\t\t\t\tloginUrl: ${JSON.stringify(authConfig.loginUrl || '/login')}\n\t\t\t\t}`;\n\n\t\t\t\tconst serializedAmplifyConfig = amplifyConfig\n\t\t\t\t\t? JSON.stringify(amplifyConfig)\n\t\t\t\t\t: 'null';\n\n\t\t\t\tconst serializedLoginPageConfig = loginPageConfig !== false && loginPageConfig !== null\n\t\t\t\t\t? JSON.stringify(loginPageConfig)\n\t\t\t\t\t: 'null';\n\n\t\t\t\treturn `export const routeGuardConfig = ${serializedAuthConfig};\nexport const loginPageConfig = ${serializedLoginPageConfig};\nexport const amplifyConfig = ${serializedAmplifyConfig};`;\n\t\t\t}\n\t\t},\n\t};\n}\n\n/**\n * Type definitions for the virtual module\n * This should be injected into the project's type definitions\n */\nexport const virtualModuleTypes = `\ndeclare module 'virtual:htlkg-config' {\n import type { RouteGuardConfig, LoginPageConfig } from '@htlkg/astro/htlkg/config';\n \n export const routeGuardConfig: RouteGuardConfig;\n export const loginPageConfig: LoginPageConfig | null;\n export const amplifyConfig: Record<string, unknown> | null;\n}\n`;\n"],"mappings":"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","names":[]}