@htlkg/astro 0.0.2 → 0.0.3

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.
@@ -0,0 +1,260 @@
1
+ /**
2
+ * URL Parameter Parsing Utilities
3
+ *
4
+ * Utilities for parsing and building URL query parameters for list pages,
5
+ * supporting pagination, sorting, filtering, and search.
6
+ */
7
+
8
+ /**
9
+ * Filter configuration for a field
10
+ */
11
+ export interface FilterFieldConfig {
12
+ /** Field key */
13
+ key: string;
14
+ /** Field type for parsing */
15
+ type: "text" | "number" | "boolean" | "date" | "select";
16
+ /** Whether this filter should be applied via GraphQL (vs client-side) */
17
+ graphql?: boolean;
18
+ /** GraphQL operator to use (defaults to 'contains' for text, 'eq' for others) */
19
+ graphqlOperator?: "eq" | "ne" | "le" | "lt" | "ge" | "gt" | "contains" | "notContains" | "beginsWith";
20
+ /** Valid options for select type */
21
+ options?: string[];
22
+ }
23
+
24
+ /**
25
+ * Configuration for parsing list parameters
26
+ */
27
+ export interface ListParamConfig {
28
+ /** Default page size */
29
+ defaultPageSize?: number;
30
+ /** Default sort configuration */
31
+ defaultSort?: { key: string; order: "asc" | "desc" };
32
+ /** Searchable field keys */
33
+ searchableFields?: string[];
34
+ /** Filterable field configurations */
35
+ filterableFields?: FilterFieldConfig[];
36
+ /** Maximum page size allowed */
37
+ maxPageSize?: number;
38
+ }
39
+
40
+ /**
41
+ * Parsed list parameters
42
+ */
43
+ export interface ListParams {
44
+ /** Current page (1-indexed) */
45
+ page: number;
46
+ /** Items per page */
47
+ pageSize: number;
48
+ /** Sort field key */
49
+ sortKey: string;
50
+ /** Sort direction */
51
+ sortOrder: "asc" | "desc";
52
+ /** Search query */
53
+ search?: string;
54
+ /** Active filters */
55
+ filters: Record<string, any>;
56
+ }
57
+
58
+ /**
59
+ * Parse URL query parameters for a list page
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const params = parseListParams(Astro.url, {
64
+ * defaultPageSize: 25,
65
+ * defaultSort: { key: 'name', order: 'asc' },
66
+ * filterableFields: [
67
+ * { key: 'status', type: 'select', options: ['active', 'inactive'] },
68
+ * { key: 'name', type: 'text' },
69
+ * ],
70
+ * });
71
+ *
72
+ * // URL: ?page=2&pageSize=50&sortKey=email&status=active
73
+ * // Returns: { page: 2, pageSize: 50, sortKey: 'email', sortOrder: 'asc', filters: { status: 'active' } }
74
+ * ```
75
+ */
76
+ export function parseListParams(url: URL, config: ListParamConfig = {}): ListParams {
77
+ const searchParams = url.searchParams;
78
+ const {
79
+ defaultPageSize = 25,
80
+ defaultSort = { key: "id", order: "asc" },
81
+ filterableFields = [],
82
+ maxPageSize = 100,
83
+ } = config;
84
+
85
+ // Parse pagination
86
+ let page = parseInt(searchParams.get("page") ?? "1", 10);
87
+ if (Number.isNaN(page) || page < 1) page = 1;
88
+
89
+ let pageSize = parseInt(searchParams.get("pageSize") ?? String(defaultPageSize), 10);
90
+ if (Number.isNaN(pageSize) || pageSize < 1) pageSize = defaultPageSize;
91
+ if (pageSize > maxPageSize) pageSize = maxPageSize;
92
+
93
+ // Parse sorting
94
+ const sortKey = searchParams.get("sortKey") ?? defaultSort.key;
95
+ const sortOrderParam = searchParams.get("sortOrder");
96
+ const sortOrder: "asc" | "desc" =
97
+ sortOrderParam === "asc" || sortOrderParam === "desc" ? sortOrderParam : defaultSort.order;
98
+
99
+ // Parse search
100
+ const search = searchParams.get("search") ?? undefined;
101
+
102
+ // Parse filters
103
+ const filters: Record<string, any> = {};
104
+
105
+ for (const field of filterableFields) {
106
+ const value = searchParams.get(field.key);
107
+ if (value === null || value === "") continue;
108
+
109
+ // Parse based on field type
110
+ switch (field.type) {
111
+ case "number":
112
+ const numValue = parseFloat(value);
113
+ if (!Number.isNaN(numValue)) {
114
+ filters[field.key] = numValue;
115
+ }
116
+ break;
117
+
118
+ case "boolean":
119
+ filters[field.key] = value === "true" || value === "1";
120
+ break;
121
+
122
+ case "date":
123
+ const dateValue = new Date(value);
124
+ if (!Number.isNaN(dateValue.getTime())) {
125
+ filters[field.key] = dateValue;
126
+ }
127
+ break;
128
+
129
+ case "select":
130
+ // Validate against allowed options
131
+ if (!field.options || field.options.includes(value)) {
132
+ filters[field.key] = value;
133
+ }
134
+ break;
135
+
136
+ case "text":
137
+ default:
138
+ filters[field.key] = value;
139
+ break;
140
+ }
141
+ }
142
+
143
+ return {
144
+ page,
145
+ pageSize,
146
+ sortKey,
147
+ sortOrder,
148
+ search,
149
+ filters,
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Build URL query string from list parameters
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * const queryString = buildListQueryString({
159
+ * page: 2,
160
+ * pageSize: 50,
161
+ * sortKey: 'name',
162
+ * sortOrder: 'asc',
163
+ * filters: { status: 'active' },
164
+ * });
165
+ * // Returns: "page=2&pageSize=50&sortKey=name&sortOrder=asc&status=active"
166
+ * ```
167
+ */
168
+ export function buildListQueryString(params: Partial<ListParams>, defaults?: Partial<ListParams>): string {
169
+ const searchParams = new URLSearchParams();
170
+
171
+ // Add pagination (only if different from defaults)
172
+ if (params.page !== undefined && params.page !== 1) {
173
+ searchParams.set("page", String(params.page));
174
+ }
175
+
176
+ if (params.pageSize !== undefined && params.pageSize !== (defaults?.pageSize ?? 25)) {
177
+ searchParams.set("pageSize", String(params.pageSize));
178
+ }
179
+
180
+ // Add sorting (only if different from defaults)
181
+ if (params.sortKey !== undefined && params.sortKey !== (defaults?.sortKey ?? "id")) {
182
+ searchParams.set("sortKey", params.sortKey);
183
+ }
184
+
185
+ if (params.sortOrder !== undefined && params.sortOrder !== (defaults?.sortOrder ?? "asc")) {
186
+ searchParams.set("sortOrder", params.sortOrder);
187
+ }
188
+
189
+ // Add search
190
+ if (params.search) {
191
+ searchParams.set("search", params.search);
192
+ }
193
+
194
+ // Add filters
195
+ if (params.filters) {
196
+ for (const [key, value] of Object.entries(params.filters)) {
197
+ if (value === undefined || value === null || value === "") continue;
198
+
199
+ if (value instanceof Date) {
200
+ searchParams.set(key, value.toISOString());
201
+ } else if (typeof value === "boolean") {
202
+ searchParams.set(key, value ? "true" : "false");
203
+ } else {
204
+ searchParams.set(key, String(value));
205
+ }
206
+ }
207
+ }
208
+
209
+ return searchParams.toString();
210
+ }
211
+
212
+ /**
213
+ * Build URL with list parameters
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * const url = buildListUrl('/admin/users', { page: 2, filters: { status: 'active' } });
218
+ * // Returns: "/admin/users?page=2&status=active"
219
+ * ```
220
+ */
221
+ export function buildListUrl(basePath: string, params: Partial<ListParams>, defaults?: Partial<ListParams>): string {
222
+ const queryString = buildListQueryString(params, defaults);
223
+ return queryString ? `${basePath}?${queryString}` : basePath;
224
+ }
225
+
226
+ /**
227
+ * Merge current params with new params (for updating single values)
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * const newParams = mergeListParams(currentParams, { page: 2 });
232
+ * ```
233
+ */
234
+ export function mergeListParams(current: ListParams, updates: Partial<ListParams>): ListParams {
235
+ return {
236
+ ...current,
237
+ ...updates,
238
+ filters: {
239
+ ...current.filters,
240
+ ...updates.filters,
241
+ },
242
+ };
243
+ }
244
+
245
+ /**
246
+ * Check if any filters are active
247
+ */
248
+ export function hasActiveFilters(params: ListParams): boolean {
249
+ if (params.search) return true;
250
+ return Object.keys(params.filters).length > 0;
251
+ }
252
+
253
+ /**
254
+ * Get filter count
255
+ */
256
+ export function getFilterCount(params: ListParams): number {
257
+ let count = params.search ? 1 : 0;
258
+ count += Object.keys(params.filters).length;
259
+ return count;
260
+ }
@@ -0,0 +1,86 @@
1
+ # Utils Module
2
+
3
+ SSR, hydration, and static rendering helpers.
4
+
5
+ ## Installation
6
+
7
+ ```typescript
8
+ import { getHydrationStrategy } from '@htlkg/astro/utils/hydration';
9
+ import { getSSRConfig } from '@htlkg/astro/utils/ssr';
10
+ import { getStaticPaths } from '@htlkg/astro/utils/static';
11
+ import { parseFilters, buildFilterParams } from '@htlkg/astro/utils/filters';
12
+ import { parseParams, validateParams } from '@htlkg/astro/utils/params';
13
+ ```
14
+
15
+ ## Hydration Helpers
16
+
17
+ Control client-side hydration strategy.
18
+
19
+ ```typescript
20
+ import { getHydrationStrategy } from '@htlkg/astro/utils/hydration';
21
+
22
+ // Determine best hydration strategy based on component
23
+ const strategy = getHydrationStrategy(component, {
24
+ interactive: true,
25
+ priority: 'high',
26
+ });
27
+ // Returns: 'client:load' | 'client:idle' | 'client:visible'
28
+ ```
29
+
30
+ ## SSR Helpers
31
+
32
+ Server-side rendering configuration.
33
+
34
+ ```typescript
35
+ import { getSSRConfig } from '@htlkg/astro/utils/ssr';
36
+
37
+ const config = getSSRConfig({
38
+ auth: true,
39
+ cache: 'private',
40
+ maxAge: 60,
41
+ });
42
+ ```
43
+
44
+ ## Static Helpers
45
+
46
+ Static path generation for dynamic routes.
47
+
48
+ ```typescript
49
+ import { getStaticPaths } from '@htlkg/astro/utils/static';
50
+
51
+ export async function getStaticPaths() {
52
+ const brands = await fetchAllBrands();
53
+ return getStaticPaths(brands, 'id');
54
+ // Returns: [{ params: { id: '1' } }, { params: { id: '2' } }, ...]
55
+ }
56
+ ```
57
+
58
+ ## Filter Helpers
59
+
60
+ Parse and build URL filter parameters.
61
+
62
+ ```typescript
63
+ import { parseFilters, buildFilterParams } from '@htlkg/astro/utils/filters';
64
+
65
+ // Parse from URL
66
+ const filters = parseFilters(Astro.url.searchParams);
67
+ // { status: 'active', search: 'hotel' }
68
+
69
+ // Build URL params
70
+ const params = buildFilterParams({ status: 'active', page: 2 });
71
+ // '?status=active&page=2'
72
+ ```
73
+
74
+ ## Param Helpers
75
+
76
+ Parse and validate route parameters.
77
+
78
+ ```typescript
79
+ import { parseParams, validateParams } from '@htlkg/astro/utils/params';
80
+
81
+ const { brandId } = parseParams(Astro.params, ['brandId']);
82
+
83
+ const valid = validateParams(Astro.params, {
84
+ brandId: (v) => /^\d+$/.test(v),
85
+ });
86
+ ```
@@ -1,216 +0,0 @@
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
- import vueDevTools from "vite-plugin-vue-devtools";
54
- var DEFAULT_ENV_VARS = [
55
- "PUBLIC_COGNITO_USER_POOL_ID",
56
- "PUBLIC_COGNITO_USER_POOL_CLIENT_ID"
57
- ];
58
- function htlkg(options = {}) {
59
- const {
60
- auth = {},
61
- loginPage = { path: "/login", title: "Sign In", redirectUrl: "/admin" },
62
- validateEnv = true,
63
- requiredEnvVars = DEFAULT_ENV_VARS,
64
- tailwind: tailwindOptions,
65
- amplify
66
- } = options;
67
- const integrations = [];
68
- if (tailwindOptions !== false) {
69
- const tailwindConfig = typeof tailwindOptions === "object" ? tailwindOptions : void 0;
70
- integrations.push(
71
- tailwind(tailwindConfig)
72
- );
73
- }
74
- integrations.push(
75
- vue({
76
- appEntrypoint: "@htlkg/astro/vue-app-setup"
77
- })
78
- );
79
- integrations.push({
80
- name: "@htlkg/astro",
81
- hooks: {
82
- "astro:config:setup": ({
83
- config,
84
- updateConfig,
85
- addMiddleware,
86
- injectRoute,
87
- logger
88
- }) => {
89
- try {
90
- const hasVue = config.integrations.some(
91
- (i) => i.name === "@astrojs/vue"
92
- );
93
- if (hasVue) {
94
- logger.info("Vue integration configured with Amplify app setup");
95
- }
96
- if (amplify) {
97
- logger.info("Amplify configuration provided - will be configured on first request");
98
- } else {
99
- logger.info("No Amplify configuration provided - will use environment variables");
100
- }
101
- if (validateEnv && !amplify) {
102
- const missing = requiredEnvVars.filter(
103
- (varName) => !process.env[varName]
104
- );
105
- if (missing.length > 0) {
106
- logger.warn(
107
- `Missing required environment variables: ${missing.join(", ")}
108
- Authentication may not work correctly. Please set these in your .env file:
109
- ${missing.map((v) => ` - ${v}`).join("\n")}`
110
- );
111
- } else {
112
- logger.info("All required environment variables are present");
113
- }
114
- }
115
- try {
116
- const virtualModulePlugin = createVirtualModulePlugin(
117
- auth,
118
- loginPage,
119
- amplify || null
120
- );
121
- const vitePlugins = [virtualModulePlugin];
122
- if (import.meta.env?.DEV !== false) {
123
- vitePlugins.push(vueDevTools());
124
- logger.info("Vue DevTools plugin enabled for development");
125
- }
126
- updateConfig({
127
- vite: {
128
- plugins: vitePlugins
129
- }
130
- });
131
- } catch (error) {
132
- const errorMsg = error instanceof Error ? error.message : "Unknown error";
133
- logger.error(
134
- `Failed to create virtual module for route configuration: ${errorMsg}`
135
- );
136
- throw error;
137
- }
138
- try {
139
- addMiddleware({
140
- entrypoint: "@htlkg/astro/middleware",
141
- order: "pre"
142
- });
143
- logger.info("Authentication middleware injected successfully");
144
- } catch (error) {
145
- const errorMsg = error instanceof Error ? error.message : "Unknown error";
146
- logger.error(`Failed to inject middleware: ${errorMsg}`);
147
- throw error;
148
- }
149
- const vueIntegrationIndex = config.integrations.findIndex(
150
- (i) => i.name === "@astrojs/vue"
151
- );
152
- if (vueIntegrationIndex === -1) {
153
- logger.warn(
154
- "@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."
155
- );
156
- } else {
157
- logger.info("Vue app setup with Amplify configuration enabled");
158
- }
159
- const hasTailwind = config.integrations.some(
160
- (i) => i.name === "@astrojs/tailwind" || i.name === "astro:tailwind"
161
- );
162
- if (hasTailwind) {
163
- logger.info("Tailwind CSS integration configured");
164
- }
165
- if (loginPage !== false) {
166
- try {
167
- const loginPath = loginPage.path || "/login";
168
- injectRoute({
169
- pattern: loginPath,
170
- entrypoint: "@htlkg/astro/auth/LoginPage.astro",
171
- prerender: false
172
- });
173
- logger.info(`Injected default login page at ${loginPath}`);
174
- } catch (error) {
175
- const errorMsg = error instanceof Error ? error.message : "Unknown error";
176
- logger.warn(`Failed to inject login page: ${errorMsg}`);
177
- }
178
- }
179
- logger.info("htlkg integration configured successfully");
180
- } catch (error) {
181
- const errorMsg = error instanceof Error ? error.message : "Unknown error";
182
- logger.error(
183
- `Failed to configure htlkg integration: ${errorMsg}`
184
- );
185
- throw error;
186
- }
187
- },
188
- "astro:config:done": ({ injectTypes }) => {
189
- injectTypes({
190
- filename: "htlkg.d.ts",
191
- content: `
192
- import type { AuthUser } from '@htlkg/core/types';
193
-
194
- declare global {
195
- namespace App {
196
- interface Locals {
197
- user: AuthUser | null;
198
- }
199
- }
200
- }
201
-
202
- ${virtualModuleTypes}
203
-
204
- export {};
205
- `
206
- });
207
- }
208
- }
209
- });
210
- return integrations.length === 1 ? integrations[0] : integrations;
211
- }
212
-
213
- export {
214
- htlkg
215
- };
216
- //# sourceMappingURL=chunk-IWK5QCVD.js.map
@@ -1 +0,0 @@
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';\nimport vueDevTools from 'vite-plugin-vue-devtools';\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\tconst vitePlugins: any[] = [virtualModulePlugin];\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Add Vue DevTools plugin in development\n\t\t\t\t\t\tif (import.meta.env?.DEV !== false) {\n\t\t\t\t\t\t\tvitePlugins.push(vueDevTools());\n\t\t\t\t\t\t\tlogger.info('Vue DevTools plugin enabled for development');\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: vitePlugins,\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":";AAWA,OAAO,cAAc;AACrB,OAAO,SAAS;;;ACFhB,SAAS,iBAAiB,SAAkC;AAC3D,MAAI,mBAAmB,QAAQ;AAC9B,WAAO,cAAc,KAAK,UAAU,QAAQ,MAAM,CAAC,KAAK,KAAK,UAAU,QAAQ,KAAK,CAAC;AAAA,EACtF;AACA,SAAO,KAAK,UAAU,OAAO;AAC9B;AAKA,SAAS,kBAAkB,UAAkC;AAC5D,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO;AAC/C,SAAO,IAAI,SAAS,IAAI,gBAAgB,EAAE,KAAK,IAAI,CAAC;AACrD;AAMO,SAAS,0BACf,YACA,iBACA,eACC;AACD,SAAO;AAAA,IACN,MAAM;AAAA,IACN,UAAU,IAAY;AACrB,UAAI,OAAO,wBAAwB;AAClC,eAAO;AAAA,MACR;AAAA,IACD;AAAA,IACA,KAAK,IAAY;AAChB,UAAI,OAAO,0BAA0B;AAEpC,cAAM,uBAAuB;AAAA,qBACZ,kBAAkB,WAAW,gBAAgB,CAAC,CAAC,CAAC;AAAA,4BACzC,kBAAkB,WAAW,uBAAuB,CAAC,CAAC,CAAC;AAAA,oBAC/D,kBAAkB,WAAW,eAAe,CAAC,CAAC,CAAC;AAAA,oBAC/C,KAAK,UAAU,WAAW,eAAe,CAAC,CAAC,CAAC;AAAA,iBAC/C,KAAK,UAAU,WAAW,YAAY,QAAQ,CAAC;AAAA;AAG5D,cAAM,0BAA0B,gBAC7B,KAAK,UAAU,aAAa,IAC5B;AAEH,cAAM,4BAA4B,oBAAoB,SAAS,oBAAoB,OAChF,KAAK,UAAU,eAAe,IAC9B;AAEH,eAAO,mCAAmC,oBAAoB;AAAA,iCACjC,yBAAyB;AAAA,+BAC3B,uBAAuB;AAAA,MACnD;AAAA,IACD;AAAA,EACD;AACD;AAMO,IAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ADxDlC,OAAO,iBAAiB;AAKxB,IAAM,mBAAmB;AAAA,EACxB;AAAA,EACA;AACD;AAkCO,SAAS,MACf,UAAmC,CAAC,GACI;AACxC,QAAM;AAAA,IACL,OAAO,CAAC;AAAA,IACR,YAAY,EAAE,MAAM,UAAU,OAAO,WAAW,aAAa,SAAS;AAAA,IACtE,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV;AAAA,EACD,IAAI;AAEJ,QAAM,eAAmC,CAAC;AAG1C,MAAI,oBAAoB,OAAO;AAC9B,UAAM,iBACL,OAAO,oBAAoB,WAAW,kBAAkB;AACzD,iBAAa;AAAA,MACZ,SAAS,cAAgD;AAAA,IAC1D;AAAA,EACD;AAIA,eAAa;AAAA,IACZ,IAAI;AAAA,MACH,eAAe;AAAA,IAChB,CAAC;AAAA,EACF;AAGA,eAAa,KAAK;AAAA,IACjB,MAAM;AAAA,IACN,OAAO;AAAA,MACN,sBAAsB,CAAC;AAAA,QACtB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD,MAAM;AACL,YAAI;AAEH,gBAAM,SAAS,OAAO,aAAa;AAAA,YAClC,CAAC,MAAM,EAAE,SAAS;AAAA,UACnB;AACA,cAAI,QAAQ;AACX,mBAAO,KAAK,mDAAmD;AAAA,UAChE;AAGA,cAAI,SAAS;AACZ,mBAAO,KAAK,sEAAsE;AAAA,UACnF,OAAO;AACN,mBAAO,KAAK,oEAAoE;AAAA,UACjF;AAGA,cAAI,eAAe,CAAC,SAAS;AAC5B,kBAAM,UAAU,gBAAgB;AAAA,cAC/B,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO;AAAA,YAClC;AAEA,gBAAI,QAAQ,SAAS,GAAG;AACvB,qBAAO;AAAA,gBACN,2CAA2C,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,EAAiF,QAAQ,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,cACxL;AAAA,YACD,OAAO;AACN,qBAAO,KAAK,gDAAgD;AAAA,YAC7D;AAAA,UACD;AAGA,cAAI;AACH,kBAAM,sBAAsB;AAAA,cAC3B;AAAA,cACA;AAAA,cACA,WAAW;AAAA,YACZ;AAEA,kBAAM,cAAqB,CAAC,mBAAmB;AAG/C,gBAAI,YAAY,KAAK,QAAQ,OAAO;AACnC,0BAAY,KAAK,YAAY,CAAC;AAC9B,qBAAO,KAAK,6CAA6C;AAAA,YAC1D;AAEA,yBAAa;AAAA,cACZ,MAAM;AAAA,gBACL,SAAS;AAAA,cACV;AAAA,YACD,CAAC;AAAA,UACF,SAAS,OAAO;AACf,kBAAM,WACL,iBAAiB,QAAQ,MAAM,UAAU;AAC1C,mBAAO;AAAA,cACN,4DAA4D,QAAQ;AAAA,YACrE;AACA,kBAAM;AAAA,UACP;AAGA,cAAI;AACH,0BAAc;AAAA,cACb,YAAY;AAAA,cACZ,OAAO;AAAA,YACR,CAAC;AACD,mBAAO,KAAK,iDAAiD;AAAA,UAC9D,SAAS,OAAO;AACf,kBAAM,WACL,iBAAiB,QAAQ,MAAM,UAAU;AAC1C,mBAAO,MAAM,gCAAgC,QAAQ,EAAE;AACvD,kBAAM;AAAA,UACP;AAGA,gBAAM,sBAAsB,OAAO,aAAa;AAAA,YAC/C,CAAC,MAAM,EAAE,SAAS;AAAA,UACnB;AAEA,cAAI,wBAAwB,IAAI;AAC/B,mBAAO;AAAA,cACN;AAAA,YAGD;AAAA,UACD,OAAO;AACN,mBAAO,KAAK,kDAAkD;AAAA,UAC/D;AAGA,gBAAM,cAAc,OAAO,aAAa;AAAA,YACvC,CAAC,MACA,EAAE,SAAS,uBAAuB,EAAE,SAAS;AAAA,UAC/C;AAEA,cAAI,aAAa;AAChB,mBAAO,KAAK,qCAAqC;AAAA,UAClD;AAGA,cAAI,cAAc,OAAO;AACxB,gBAAI;AACH,oBAAM,YAAY,UAAU,QAAQ;AACpC,0BAAY;AAAA,gBACX,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,WAAW;AAAA,cACZ,CAAC;AACD,qBAAO,KAAK,kCAAkC,SAAS,EAAE;AAAA,YAC1D,SAAS,OAAO;AACf,oBAAM,WACL,iBAAiB,QAAQ,MAAM,UAAU;AAC1C,qBAAO,KAAK,gCAAgC,QAAQ,EAAE;AAAA,YACvD;AAAA,UACD;AAEA,iBAAO,KAAK,2CAA2C;AAAA,QACxD,SAAS,OAAO;AACf,gBAAM,WACL,iBAAiB,QAAQ,MAAM,UAAU;AAC1C,iBAAO;AAAA,YACN,0CAA0C,QAAQ;AAAA,UACnD;AACA,gBAAM;AAAA,QACP;AAAA,MACD;AAAA,MACA,qBAAqB,CAAC,EAAE,YAAY,MAAM;AAEzC,oBAAY;AAAA,UACX,UAAU;AAAA,UACV,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWZ,kBAAkB;AAAA;AAAA;AAAA;AAAA,QAIhB,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD,CAAC;AAGD,SAAO,aAAa,WAAW,IAAI,aAAa,CAAC,IAAI;AACtD;","names":[]}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=chunk-ZQ4XMJH7.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}