@htlkg/astro 0.0.1 → 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.
Files changed (41) hide show
  1. package/README.md +24 -8
  2. package/dist/chunk-2GML443T.js +273 -0
  3. package/dist/chunk-2GML443T.js.map +1 -0
  4. package/dist/{chunk-Z2ZAL7KX.js → chunk-UBF5F2RG.js} +1 -1
  5. package/dist/{chunk-Z2ZAL7KX.js.map → chunk-UBF5F2RG.js.map} +1 -1
  6. package/dist/chunk-XOY5BM3N.js +151 -0
  7. package/dist/chunk-XOY5BM3N.js.map +1 -0
  8. package/dist/htlkg/config.js +1 -1
  9. package/dist/htlkg/index.js +1 -1
  10. package/dist/index.js +126 -14
  11. package/dist/index.js.map +1 -1
  12. package/dist/middleware/index.js +27 -28
  13. package/dist/middleware/index.js.map +1 -1
  14. package/dist/utils/index.js +31 -12
  15. package/dist/vue-app-setup.js +47 -0
  16. package/dist/vue-app-setup.js.map +1 -0
  17. package/package.json +60 -26
  18. package/src/auth/auth.md +77 -0
  19. package/src/components/Island.astro +56 -0
  20. package/src/components/components.md +79 -0
  21. package/src/factories/createListPage.ts +290 -0
  22. package/src/factories/index.ts +16 -0
  23. package/src/htlkg/config.ts +10 -0
  24. package/src/htlkg/htlkg.md +63 -0
  25. package/src/htlkg/index.ts +49 -157
  26. package/src/index.ts +3 -0
  27. package/src/layouts/AdminLayout.astro +103 -92
  28. package/src/layouts/layouts.md +87 -0
  29. package/src/middleware/auth.ts +42 -0
  30. package/src/middleware/middleware.md +82 -0
  31. package/src/middleware/route-guards.ts +4 -28
  32. package/src/patterns/patterns.md +104 -0
  33. package/src/utils/filters.ts +320 -0
  34. package/src/utils/index.ts +8 -2
  35. package/src/utils/params.ts +260 -0
  36. package/src/utils/utils.md +86 -0
  37. package/src/vue-app-setup.ts +21 -28
  38. package/dist/chunk-WLOFOVCL.js +0 -210
  39. package/dist/chunk-WLOFOVCL.js.map +0 -1
  40. package/dist/chunk-ZQ4XMJH7.js +0 -1
  41. package/dist/chunk-ZQ4XMJH7.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,10 +1,30 @@
1
1
  import {
2
2
  htlkg
3
- } from "./chunk-WLOFOVCL.js";
3
+ } from "./chunk-XOY5BM3N.js";
4
4
  import {
5
5
  isAuthenticatedUser
6
- } from "./chunk-Z2ZAL7KX.js";
7
- import "./chunk-ZQ4XMJH7.js";
6
+ } from "./chunk-UBF5F2RG.js";
7
+ import {
8
+ applyClientFilters,
9
+ buildGraphQLFilter,
10
+ buildListQueryString,
11
+ buildListUrl,
12
+ getFilterCount,
13
+ hasActiveFilters,
14
+ mergeListParams,
15
+ paginateItems,
16
+ parseListParams,
17
+ processListData,
18
+ sortItems
19
+ } from "./chunk-2GML443T.js";
20
+ import {
21
+ chunkArray,
22
+ filterItems,
23
+ generateNestedPaths,
24
+ generatePaginatedPaths,
25
+ generateStaticPaths,
26
+ groupItems
27
+ } from "./chunk-33R4URZV.js";
8
28
  import {
9
29
  createHydrationScript,
10
30
  createHydrationScripts,
@@ -25,40 +45,132 @@ import {
25
45
  setCacheControl,
26
46
  setResponseHeaders
27
47
  } from "./chunk-WNMPTDCR.js";
28
- import {
29
- chunkArray,
30
- filterItems,
31
- generateNestedPaths,
32
- generatePaginatedPaths,
33
- generateStaticPaths,
34
- groupItems,
35
- sortItems
36
- } from "./chunk-33R4URZV.js";
48
+
49
+ // src/factories/createListPage.ts
50
+ function generateBreadcrumbs(pageId, title) {
51
+ return [
52
+ { label: "Admin", href: "/admin" },
53
+ { label: title }
54
+ ];
55
+ }
56
+ async function createListPage(astro, config) {
57
+ const {
58
+ title,
59
+ description,
60
+ pageId,
61
+ breadcrumbs,
62
+ fetchFn,
63
+ transform,
64
+ store,
65
+ relatedStores,
66
+ searchableFields,
67
+ filterableFields = [],
68
+ defaultSort,
69
+ defaultPageSize = 25,
70
+ fetchLimit = 1e3
71
+ } = config;
72
+ const paramConfig = {
73
+ defaultPageSize,
74
+ defaultSort,
75
+ searchableFields,
76
+ filterableFields
77
+ };
78
+ const params = parseListParams(astro.url, paramConfig);
79
+ const graphqlFilter = buildGraphQLFilter(params.filters, filterableFields, {
80
+ search: params.search,
81
+ searchFields: searchableFields
82
+ });
83
+ let allItems = [];
84
+ let nextToken = void 0;
85
+ do {
86
+ const result = await fetchFn({
87
+ filter: graphqlFilter,
88
+ limit: fetchLimit,
89
+ nextToken: nextToken ?? void 0
90
+ });
91
+ const data = result.data ?? [];
92
+ allItems = allItems.concat(data);
93
+ nextToken = result.nextToken;
94
+ } while (nextToken);
95
+ if (transform) {
96
+ allItems = allItems.map(transform);
97
+ }
98
+ allItems = applyClientFilters(allItems, params.filters, filterableFields, {
99
+ search: params.search,
100
+ searchFields: searchableFields
101
+ });
102
+ allItems = sortItems(allItems, params.sortKey, params.sortOrder);
103
+ const { paginatedItems, totalItems, totalPages, currentPage, pageSize } = paginateItems(
104
+ allItems,
105
+ params.page,
106
+ params.pageSize
107
+ );
108
+ store.set(paginatedItems);
109
+ if (relatedStores) {
110
+ await Promise.all(
111
+ Object.entries(relatedStores).map(async ([, config2]) => {
112
+ const data = await config2.fetch();
113
+ config2.store.set(data);
114
+ })
115
+ );
116
+ }
117
+ return {
118
+ layoutProps: {
119
+ title,
120
+ description,
121
+ currentPage: pageId,
122
+ breadcrumbs: breadcrumbs ?? generateBreadcrumbs(pageId, title)
123
+ },
124
+ initialState: {
125
+ currentPage,
126
+ pageSize,
127
+ sortKey: params.sortKey,
128
+ sortOrder: params.sortOrder,
129
+ totalItems,
130
+ totalPages,
131
+ filters: params.filters,
132
+ search: params.search
133
+ },
134
+ items: paginatedItems,
135
+ allItems,
136
+ params
137
+ };
138
+ }
37
139
  export {
140
+ applyClientFilters,
141
+ buildGraphQLFilter,
142
+ buildListQueryString,
143
+ buildListUrl,
38
144
  chunkArray,
39
145
  createHydrationScript,
40
146
  createHydrationScripts,
41
147
  createIslandProps,
148
+ createListPage,
42
149
  deserializeFromHydration,
43
150
  filterItems,
44
151
  generateNestedPaths,
45
152
  generatePaginatedPaths,
46
153
  generateStaticPaths,
47
154
  getClientIP,
155
+ getFilterCount,
48
156
  getHydratedData,
49
157
  getQueryParams,
50
158
  getRequestHeaders,
51
159
  getServerData,
52
160
  groupItems,
161
+ hasActiveFilters,
53
162
  htlkg,
54
163
  isAuthenticatedUser,
55
164
  isMobileDevice,
56
165
  isServerSide,
166
+ mergeListParams,
57
167
  mergeProps,
168
+ paginateItems,
169
+ parseListParams,
170
+ processListData,
58
171
  serializeForHydration,
59
172
  setCacheControl,
60
173
  setResponseHeaders,
61
- shouldHydrate,
62
- sortItems
174
+ shouldHydrate
63
175
  };
64
176
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/factories/createListPage.ts"],"sourcesContent":["/**\n * List Page Factory\n *\n * Factory function for creating standardized list pages with automatic\n * data fetching, filtering, sorting, and pagination.\n */\n\nimport type { AstroGlobal } from \"astro\";\nimport type { WritableAtom } from \"nanostores\";\n\nimport {\n\tparseListParams,\n\ttype ListParams,\n\ttype ListParamConfig,\n\ttype FilterFieldConfig,\n} from \"../utils/params\";\nimport {\n\tbuildGraphQLFilter,\n\tapplyClientFilters,\n\tsortItems,\n\tpaginateItems,\n} from \"../utils/filters\";\n\n/**\n * Breadcrumb item\n */\nexport interface BreadcrumbItem {\n\tlabel: string;\n\thref?: string;\n}\n\n/**\n * Layout props returned by the factory\n */\nexport interface LayoutProps {\n\ttitle: string;\n\tdescription?: string;\n\tcurrentPage: string;\n\tbreadcrumbs: BreadcrumbItem[];\n}\n\n/**\n * Table initial state\n */\nexport interface TableInitialState {\n\tcurrentPage: number;\n\tpageSize: number;\n\tsortKey: string;\n\tsortOrder: \"asc\" | \"desc\";\n\ttotalItems: number;\n\ttotalPages: number;\n\tfilters: Record<string, any>;\n\tsearch?: string;\n}\n\n/**\n * Related store configuration\n */\nexport interface RelatedStoreConfig<T = any> {\n\tstore: WritableAtom<T[]>;\n\tfetch: () => Promise<T[]>;\n}\n\n/**\n * Configuration for createListPage\n */\nexport interface ListPageConfig<T> {\n\t// Page metadata\n\t/** Page title */\n\ttitle: string;\n\t/** Page description */\n\tdescription?: string;\n\t/** Page identifier (for sidebar active state) */\n\tpageId: string;\n\t/** Custom breadcrumbs (auto-generated if not provided) */\n\tbreadcrumbs?: BreadcrumbItem[];\n\n\t// Data fetching\n\t/** Fetch function that retrieves data */\n\tfetchFn: (params: {\n\t\tfilter: any;\n\t\tlimit?: number;\n\t\tnextToken?: string;\n\t}) => Promise<{ data: T[]; nextToken?: string | null }>;\n\n\t// Data handling\n\t/** Transform function to apply to fetched data */\n\ttransform?: (item: any) => T;\n\t/** Main store to set with data */\n\tstore: WritableAtom<T[]>;\n\t/** Related stores to populate */\n\trelatedStores?: Record<string, RelatedStoreConfig>;\n\n\t// Filtering/sorting config\n\t/** Searchable field keys */\n\tsearchableFields?: string[];\n\t/** Filterable field configurations */\n\tfilterableFields?: FilterFieldConfig[];\n\t/** Sortable field keys (all by default) */\n\tsortableFields?: string[];\n\t/** Default sort configuration */\n\tdefaultSort?: { key: string; order: \"asc\" | \"desc\" };\n\t/** Default page size */\n\tdefaultPageSize?: number;\n\t/** Maximum items to fetch from API */\n\tfetchLimit?: number;\n}\n\n/**\n * Result from createListPage\n */\nexport interface ListPageResult<T> {\n\t/** Props to spread to Layout component */\n\tlayoutProps: LayoutProps;\n\t/** Initial state for table component */\n\tinitialState: TableInitialState;\n\t/** Processed items (paginated) */\n\titems: T[];\n\t/** All items (pre-pagination, for client-side operations) */\n\tallItems: T[];\n\t/** Parsed URL parameters */\n\tparams: ListParams;\n}\n\n/**\n * Default breadcrumb generator\n */\nfunction generateBreadcrumbs(pageId: string, title: string): BreadcrumbItem[] {\n\treturn [\n\t\t{ label: \"Admin\", href: \"/admin\" },\n\t\t{ label: title },\n\t];\n}\n\n/**\n * Create a list page with automatic data handling\n *\n * This factory handles:\n * - URL parameter parsing (page, pageSize, sortKey, sortOrder, filters)\n * - Data fetching with GraphQL filter building\n * - Data transformation\n * - Client-side filtering (for computed fields)\n * - Sorting\n * - Pagination\n * - Store population\n *\n * @example\n * ```astro\n * ---\n * import { createListPage } from '@htlkg/astro/factories';\n * import { $accounts } from '@/stores/accounts';\n *\n * const { layoutProps, initialState, items } = await createListPage(Astro, {\n * title: 'Accounts',\n * pageId: 'accounts',\n * store: $accounts,\n *\n * fetchFn: async ({ filter }) => {\n * const client = getServerClient(Astro);\n * return await client.models.Account.list({ filter });\n * },\n *\n * transform: (account) => ({\n * id: account.id,\n * name: account.name,\n * brandCount: account.brands?.length ?? 0,\n * }),\n *\n * filterableFields: [\n * { key: 'name', type: 'text', graphql: true },\n * { key: 'status', type: 'select', graphql: true, options: ['active', 'inactive'] },\n * ],\n *\n * defaultSort: { key: 'name', order: 'asc' },\n * });\n * ---\n *\n * <Layout {...layoutProps}>\n * <AccountsTable client:load initialState={initialState} />\n * </Layout>\n * ```\n */\nexport async function createListPage<T extends Record<string, any>>(\n\tastro: AstroGlobal,\n\tconfig: ListPageConfig<T>\n): Promise<ListPageResult<T>> {\n\tconst {\n\t\ttitle,\n\t\tdescription,\n\t\tpageId,\n\t\tbreadcrumbs,\n\t\tfetchFn,\n\t\ttransform,\n\t\tstore,\n\t\trelatedStores,\n\t\tsearchableFields,\n\t\tfilterableFields = [],\n\t\tdefaultSort,\n\t\tdefaultPageSize = 25,\n\t\tfetchLimit = 1000,\n\t} = config;\n\n\t// 1. Parse URL parameters\n\tconst paramConfig: ListParamConfig = {\n\t\tdefaultPageSize,\n\t\tdefaultSort,\n\t\tsearchableFields,\n\t\tfilterableFields,\n\t};\n\tconst params = parseListParams(astro.url, paramConfig);\n\n\t// 2. Build GraphQL filter from URL params\n\tconst graphqlFilter = buildGraphQLFilter(params.filters, filterableFields, {\n\t\tsearch: params.search,\n\t\tsearchFields: searchableFields,\n\t});\n\n\t// 3. Fetch data with pagination\n\tlet allItems: T[] = [];\n\tlet nextToken: string | null | undefined = undefined;\n\n\tdo {\n\t\tconst result = await fetchFn({\n\t\t\tfilter: graphqlFilter,\n\t\t\tlimit: fetchLimit,\n\t\t\tnextToken: nextToken ?? undefined,\n\t\t});\n\n\t\tconst data = result.data ?? [];\n\t\tallItems = allItems.concat(data);\n\t\tnextToken = result.nextToken;\n\t} while (nextToken);\n\n\t// 4. Transform data if needed\n\tif (transform) {\n\t\tallItems = allItems.map(transform);\n\t}\n\n\t// 5. Apply client-side filtering (for computed fields not in GraphQL)\n\tallItems = applyClientFilters(allItems, params.filters, filterableFields, {\n\t\tsearch: params.search,\n\t\tsearchFields: searchableFields,\n\t});\n\n\t// 6. Sort\n\tallItems = sortItems(allItems, params.sortKey, params.sortOrder);\n\n\t// 7. Paginate\n\tconst { paginatedItems, totalItems, totalPages, currentPage, pageSize } = paginateItems(\n\t\tallItems,\n\t\tparams.page,\n\t\tparams.pageSize\n\t);\n\n\t// 8. Set main store\n\tstore.set(paginatedItems);\n\n\t// 9. Fetch and set related stores\n\tif (relatedStores) {\n\t\tawait Promise.all(\n\t\t\tObject.entries(relatedStores).map(async ([, config]) => {\n\t\t\t\tconst data = await config.fetch();\n\t\t\t\tconfig.store.set(data);\n\t\t\t})\n\t\t);\n\t}\n\n\t// 10. Build result\n\treturn {\n\t\tlayoutProps: {\n\t\t\ttitle,\n\t\t\tdescription,\n\t\t\tcurrentPage: pageId,\n\t\t\tbreadcrumbs: breadcrumbs ?? generateBreadcrumbs(pageId, title),\n\t\t},\n\t\tinitialState: {\n\t\t\tcurrentPage,\n\t\t\tpageSize,\n\t\t\tsortKey: params.sortKey,\n\t\t\tsortOrder: params.sortOrder,\n\t\t\ttotalItems,\n\t\t\ttotalPages,\n\t\t\tfilters: params.filters,\n\t\t\tsearch: params.search,\n\t\t},\n\t\titems: paginatedItems,\n\t\tallItems,\n\t\tparams,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+HA,SAAS,oBAAoB,QAAgB,OAAiC;AAC7E,SAAO;AAAA,IACN,EAAE,OAAO,SAAS,MAAM,SAAS;AAAA,IACjC,EAAE,OAAO,MAAM;AAAA,EAChB;AACD;AAkDA,eAAsB,eACrB,OACA,QAC6B;AAC7B,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,CAAC;AAAA,IACpB;AAAA,IACA,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACd,IAAI;AAGJ,QAAM,cAA+B;AAAA,IACpC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACA,QAAM,SAAS,gBAAgB,MAAM,KAAK,WAAW;AAGrD,QAAM,gBAAgB,mBAAmB,OAAO,SAAS,kBAAkB;AAAA,IAC1E,QAAQ,OAAO;AAAA,IACf,cAAc;AAAA,EACf,CAAC;AAGD,MAAI,WAAgB,CAAC;AACrB,MAAI,YAAuC;AAE3C,KAAG;AACF,UAAM,SAAS,MAAM,QAAQ;AAAA,MAC5B,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,WAAW,aAAa;AAAA,IACzB,CAAC;AAED,UAAM,OAAO,OAAO,QAAQ,CAAC;AAC7B,eAAW,SAAS,OAAO,IAAI;AAC/B,gBAAY,OAAO;AAAA,EACpB,SAAS;AAGT,MAAI,WAAW;AACd,eAAW,SAAS,IAAI,SAAS;AAAA,EAClC;AAGA,aAAW,mBAAmB,UAAU,OAAO,SAAS,kBAAkB;AAAA,IACzE,QAAQ,OAAO;AAAA,IACf,cAAc;AAAA,EACf,CAAC;AAGD,aAAW,UAAU,UAAU,OAAO,SAAS,OAAO,SAAS;AAG/D,QAAM,EAAE,gBAAgB,YAAY,YAAY,aAAa,SAAS,IAAI;AAAA,IACzE;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,EACR;AAGA,QAAM,IAAI,cAAc;AAGxB,MAAI,eAAe;AAClB,UAAM,QAAQ;AAAA,MACb,OAAO,QAAQ,aAAa,EAAE,IAAI,OAAO,CAAC,EAAEA,OAAM,MAAM;AACvD,cAAM,OAAO,MAAMA,QAAO,MAAM;AAChC,QAAAA,QAAO,MAAM,IAAI,IAAI;AAAA,MACtB,CAAC;AAAA,IACF;AAAA,EACD;AAGA,SAAO;AAAA,IACN,aAAa;AAAA,MACZ;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,aAAa,eAAe,oBAAoB,QAAQ,KAAK;AAAA,IAC9D;AAAA,IACA,cAAc;AAAA,MACb;AAAA,MACA;AAAA,MACA,SAAS,OAAO;AAAA,MAChB,WAAW,OAAO;AAAA,MAClB;AAAA,MACA;AAAA,MACA,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,IAChB;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACD;AACD;","names":["config"]}
@@ -2,9 +2,32 @@
2
2
  import { sequence } from "astro:middleware";
3
3
 
4
4
  // src/middleware/auth.ts
5
+ import { Amplify } from "aws-amplify";
5
6
  import { getUser } from "@htlkg/core/auth";
7
+ import { globalSettings } from "@htlkg/core/amplify-astro-adapter";
8
+ import { amplifyConfig } from "virtual:htlkg-config";
9
+ var amplifyConfigured = false;
10
+ function ensureAmplifyConfigured() {
11
+ if (amplifyConfigured) return;
12
+ try {
13
+ if (!amplifyConfig) {
14
+ console.warn("[htlkg Auth] No Amplify configuration provided");
15
+ return;
16
+ }
17
+ Amplify.configure(amplifyConfig, { ssr: true });
18
+ globalSettings.enableServerSideAuth();
19
+ const isSSL = typeof window !== "undefined" ? window.location.protocol === "https:" : process.env.NODE_ENV === "production";
20
+ globalSettings.setIsSSLOrigin(isSSL);
21
+ amplifyConfigured = true;
22
+ console.info("[htlkg Auth] Amplify configured for server-side auth");
23
+ } catch (error) {
24
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
25
+ console.error(`[htlkg Auth] Failed to configure Amplify: ${errorMsg}`);
26
+ }
27
+ }
6
28
  var authMiddleware = async (context, next) => {
7
29
  const { locals } = context;
30
+ ensureAmplifyConfigured();
8
31
  try {
9
32
  const user = await getUser(context);
10
33
  locals.user = user;
@@ -35,7 +58,7 @@ function matchesPattern(pathname, patterns) {
35
58
  return pattern.test(pathname);
36
59
  } catch (error) {
37
60
  console.error(
38
- "[htlkg Route Guard] Error matching pattern:",
61
+ "[htlkg] Error matching route pattern:",
39
62
  error instanceof Error ? error.message : "Unknown error"
40
63
  );
41
64
  return false;
@@ -54,20 +77,13 @@ var routeGuard = async (context, next) => {
54
77
  } = config;
55
78
  try {
56
79
  if (matchesPattern(pathname, publicRoutes)) {
57
- console.log(`[htlkg Route Guard] Public route: ${pathname}`);
58
80
  return next();
59
81
  }
60
82
  const user = locals.user;
61
83
  if (matchesPattern(pathname, adminRoutes)) {
62
84
  if (!user || !user.isAdmin) {
63
- console.log(
64
- `[htlkg Route Guard] Admin access denied for ${pathname} - User: ${user ? "authenticated (non-admin)" : "not authenticated"}`
65
- );
66
85
  return redirect(`${loginUrl}?error=admin_required`);
67
86
  }
68
- console.log(
69
- `[htlkg Route Guard] Admin access granted for ${pathname}`
70
- );
71
87
  return next();
72
88
  }
73
89
  for (const brandRoute of brandRoutes) {
@@ -76,25 +92,17 @@ var routeGuard = async (context, next) => {
76
92
  if (match) {
77
93
  const brandId = Number.parseInt(match[brandRoute.brandIdParam], 10);
78
94
  if (Number.isNaN(brandId)) {
79
- console.warn(
80
- `[htlkg Route Guard] Invalid brandId extracted from ${pathname}`
81
- );
95
+ console.warn(`[htlkg] Invalid brandId extracted from ${pathname}`);
82
96
  return redirect(`${loginUrl}?error=invalid_brand`);
83
97
  }
84
98
  if (!user || !user.isAdmin && !user.brandIds.includes(brandId)) {
85
- console.log(
86
- `[htlkg Route Guard] Brand access denied for ${pathname} (brandId: ${brandId}) - User: ${user ? `authenticated (brandIds: ${user.brandIds.join(",")})` : "not authenticated"}`
87
- );
88
99
  return redirect(`${loginUrl}?error=access_denied`);
89
100
  }
90
- console.log(
91
- `[htlkg Route Guard] Brand access granted for ${pathname} (brandId: ${brandId})`
92
- );
93
101
  return next();
94
102
  }
95
103
  } catch (error) {
96
104
  console.error(
97
- `[htlkg Route Guard] Error processing brand route for ${pathname}:`,
105
+ `[htlkg] Error processing brand route for ${pathname}:`,
98
106
  error instanceof Error ? error.message : "Unknown error"
99
107
  );
100
108
  return redirect(`${loginUrl}?error=access_denied`);
@@ -103,23 +111,14 @@ var routeGuard = async (context, next) => {
103
111
  if (matchesPattern(pathname, authenticatedRoutes)) {
104
112
  if (!user) {
105
113
  const returnUrl = encodeURIComponent(pathname + url.search);
106
- console.log(
107
- `[htlkg Route Guard] Authentication required for ${pathname}, redirecting to login`
108
- );
109
114
  return redirect(`${loginUrl}?redirect=${returnUrl}`);
110
115
  }
111
- console.log(
112
- `[htlkg Route Guard] Authenticated access granted for ${pathname}`
113
- );
114
116
  return next();
115
117
  }
116
- console.log(
117
- `[htlkg Route Guard] Default access granted for ${pathname}`
118
- );
119
118
  return next();
120
119
  } catch (error) {
121
120
  console.error(
122
- "[htlkg Route Guard] Unexpected error in route guard:",
121
+ "[htlkg] Unexpected error in route guard:",
123
122
  error instanceof Error ? error.message : "Unknown error"
124
123
  );
125
124
  return redirect(`${loginUrl}?error=server_error`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/middleware/index.ts","../../src/middleware/auth.ts","../../src/middleware/route-guards.ts"],"sourcesContent":["/**\n * Middleware for @htlkg/astro\n * \n * This module exports:\n * - authMiddleware: Retrieves authenticated user and injects into locals\n * - routeGuard: Enforces access control based on route configuration\n * - onRequest: Composed middleware chain (auth + route guard)\n * - Helper functions: requireAuth, requireAdminAccess, requireBrandAccess\n */\n\nimport { sequence } from 'astro:middleware';\nimport { authMiddleware } from './auth.js';\nimport { routeGuard } from './route-guards.js';\n\n// Export individual middleware\nexport { authMiddleware } from './auth.js';\nexport {\n\trouteGuard,\n\trequireAuth,\n\trequireAdminAccess,\n\trequireBrandAccess,\n} from './route-guards.js';\n\n/**\n * Export composed middleware chain\n * Auth middleware runs first to populate locals.user\n * Route guard middleware runs second to enforce access control\n * \n * This is the default export that gets injected by the htlkg integration\n */\nexport const onRequest = sequence(authMiddleware, routeGuard);\n","/**\n * Authentication middleware for htlkg integration\n * \n * This middleware:\n * - Retrieves the authenticated user from AWS Amplify\n * - Injects the user into Astro.locals for use in pages and API routes\n * - Handles authentication errors gracefully\n */\n\nimport type { MiddlewareHandler } from 'astro';\nimport { getUser } from '@htlkg/core/auth';\n\n/**\n * Auth middleware - retrieves authenticated user and injects into locals\n * \n * This middleware runs on every request and attempts to get the current\n * authenticated user from AWS Amplify. If successful, the user is injected\n * into context.locals.user. If authentication fails, locals.user is set to null.\n * \n * @example\n * // In an Astro page\n * const { user } = Astro.locals;\n * if (user) {\n * console.log('Authenticated user:', user.email);\n * }\n */\nexport const authMiddleware: MiddlewareHandler = async (context, next) => {\n\tconst { locals } = context;\n\n\ttry {\n\t\tconst user = await getUser(context);\n\t\tlocals.user = user;\n\t} catch (error) {\n\t\t// Set user to null on any authentication error\n\t\tlocals.user = null;\n\n\t\t// Log error without exposing sensitive information\n\t\tif (error instanceof Error) {\n\t\t\t// Filter out sensitive data from error messages\n\t\t\tconst safeMessage = error.message\n\t\t\t\t.replace(/token[=:]\\s*[^\\s,}]+/gi, 'token=***')\n\t\t\t\t.replace(/key[=:]\\s*[^\\s,}]+/gi, 'key=***')\n\t\t\t\t.replace(/secret[=:]\\s*[^\\s,}]+/gi, 'secret=***')\n\t\t\t\t.replace(/password[=:]\\s*[^\\s,}]+/gi, 'password=***');\n\n\t\t\tconsole.error('[htlkg Auth] Authentication failed:', safeMessage);\n\t\t} else {\n\t\t\tconsole.error('[htlkg Auth] Authentication failed: Unknown error');\n\t\t}\n\t}\n\n\treturn next();\n};\n","/**\n * Route guard middleware for htlkg integration\n * \n * This middleware enforces access control based on route configuration:\n * - Public routes: accessible to everyone\n * - Authenticated routes: require any logged-in user\n * - Admin routes: require admin privileges\n * - Brand routes: require brand-specific access or admin privileges\n */\n\nimport type { MiddlewareHandler } from 'astro';\nimport type { RoutePattern, RouteGuardConfig } from '../htlkg/config.js';\n\n// Import configuration from virtual module\nimport { routeGuardConfig } from 'virtual:htlkg-config';\n\n// Type assertion for the imported config\nconst config = routeGuardConfig as RouteGuardConfig;\n\n/**\n * Helper: Check if pathname matches any of the provided patterns\n */\nfunction matchesPattern(pathname: string, patterns: RoutePattern[]): boolean {\n\treturn patterns.some((pattern) => {\n\t\ttry {\n\t\t\tif (typeof pattern === 'string') {\n\t\t\t\t// Special case: \"/\" only matches exactly\n\t\t\t\tif (pattern === '/') {\n\t\t\t\t\treturn pathname === '/';\n\t\t\t\t}\n\t\t\t\t// String pattern: exact match or starts with (for sub-routes)\n\t\t\t\treturn pathname === pattern || pathname.startsWith(pattern + '/');\n\t\t\t}\n\t\t\t// RegExp pattern: test against pathname\n\t\t\treturn pattern.test(pathname);\n\t\t} catch (error) {\n\t\t\t// Log pattern matching errors but don't block the request\n\t\t\tconsole.error(\n\t\t\t\t'[htlkg Route Guard] Error matching pattern:',\n\t\t\t\terror instanceof Error ? error.message : 'Unknown error',\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t});\n}\n\n/**\n * Route guard middleware - protects routes based on configuration\n * \n * This middleware runs after authMiddleware and enforces access control\n * based on the route configuration provided to the htlkg integration.\n * \n * @example\n * // In astro.config.mjs\n * htlkg({\n * auth: {\n * publicRoutes: ['/login', '/'],\n * adminRoutes: [/^\\/admin/],\n * brandRoutes: [\n * { pattern: /^\\/brands\\/(\\d+)/, brandIdParam: 1 }\n * ],\n * loginUrl: '/login'\n * }\n * })\n */\nexport const routeGuard: MiddlewareHandler = async (context, next) => {\n\tconst { locals, url, redirect } = context;\n\tconst pathname = url.pathname;\n\n\tconst {\n\t\tpublicRoutes = [],\n\t\tauthenticatedRoutes = [],\n\t\tadminRoutes = [],\n\t\tbrandRoutes = [],\n\t\tloginUrl = '/login',\n\t} = config;\n\n\ttry {\n\t\t// Public routes - no auth required\n\t\tif (matchesPattern(pathname, publicRoutes)) {\n\t\t\tconsole.log(`[htlkg Route Guard] Public route: ${pathname}`);\n\t\t\treturn next();\n\t\t}\n\n\t\tconst user = locals.user;\n\n\t\t// Admin routes - require admin role\n\t\tif (matchesPattern(pathname, adminRoutes)) {\n\t\t\tif (!user || !user.isAdmin) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`[htlkg Route Guard] Admin access denied for ${pathname} - User: ${user ? 'authenticated (non-admin)' : 'not authenticated'}`,\n\t\t\t\t);\n\t\t\t\treturn redirect(`${loginUrl}?error=admin_required`);\n\t\t\t}\n\t\t\tconsole.log(\n\t\t\t\t`[htlkg Route Guard] Admin access granted for ${pathname}`,\n\t\t\t);\n\t\t\treturn next();\n\t\t}\n\n\t\t// Brand routes - require brand access or admin\n\t\tfor (const brandRoute of brandRoutes) {\n\t\t\ttry {\n\t\t\t\tconst match = pathname.match(brandRoute.pattern);\n\t\t\t\tif (match) {\n\t\t\t\t\tconst brandId = Number.parseInt(match[brandRoute.brandIdParam], 10);\n\n\t\t\t\t\tif (Number.isNaN(brandId)) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[htlkg Route Guard] Invalid brandId extracted from ${pathname}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn redirect(`${loginUrl}?error=invalid_brand`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!user || (!user.isAdmin && !user.brandIds.includes(brandId))) {\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t`[htlkg Route Guard] Brand access denied for ${pathname} (brandId: ${brandId}) - User: ${user ? `authenticated (brandIds: ${user.brandIds.join(',')})` : 'not authenticated'}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn redirect(`${loginUrl}?error=access_denied`);\n\t\t\t\t\t}\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`[htlkg Route Guard] Brand access granted for ${pathname} (brandId: ${brandId})`,\n\t\t\t\t\t);\n\t\t\t\t\treturn next();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[htlkg Route Guard] Error processing brand route for ${pathname}:`,\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error',\n\t\t\t\t);\n\t\t\t\t// Fail-safe: deny access on error\n\t\t\t\treturn redirect(`${loginUrl}?error=access_denied`);\n\t\t\t}\n\t\t}\n\n\t\t// Authenticated routes - require any logged-in user\n\t\tif (matchesPattern(pathname, authenticatedRoutes)) {\n\t\t\tif (!user) {\n\t\t\t\tconst returnUrl = encodeURIComponent(pathname + url.search);\n\t\t\t\tconsole.log(\n\t\t\t\t\t`[htlkg Route Guard] Authentication required for ${pathname}, redirecting to login`,\n\t\t\t\t);\n\t\t\t\treturn redirect(`${loginUrl}?redirect=${returnUrl}`);\n\t\t\t}\n\t\t\tconsole.log(\n\t\t\t\t`[htlkg Route Guard] Authenticated access granted for ${pathname}`,\n\t\t\t);\n\t\t\treturn next();\n\t\t}\n\n\t\t// Default: allow access\n\t\tconsole.log(\n\t\t\t`[htlkg Route Guard] Default access granted for ${pathname}`,\n\t\t);\n\t\treturn next();\n\t} catch (error) {\n\t\t// Catch-all error handler for route guard\n\t\tconsole.error(\n\t\t\t'[htlkg Route Guard] Unexpected error in route guard:',\n\t\t\terror instanceof Error ? error.message : 'Unknown error',\n\t\t);\n\t\t// Fail-safe: deny access and redirect to login\n\t\treturn redirect(`${loginUrl}?error=server_error`);\n\t}\n};\n\n/**\n * Helper functions for programmatic route protection in pages\n * These can be used in Astro pages for more fine-grained control\n */\n\n/**\n * Require authentication for a page\n * Redirects to login if user is not authenticated\n */\nexport async function requireAuth(context: any, loginUrl = '/login') {\n\tconst user = context.locals.user;\n\tif (!user) {\n\t\tconst currentUrl = context.url.pathname + context.url.search;\n\t\tconst encodedReturnUrl = encodeURIComponent(currentUrl);\n\t\treturn context.redirect(`${loginUrl}?redirect=${encodedReturnUrl}`);\n\t}\n\treturn user;\n}\n\n/**\n * Require admin access for a page\n * Redirects to login if user is not an admin\n */\nexport async function requireAdminAccess(context: any, loginUrl = '/login') {\n\tconst user = context.locals.user;\n\tif (!user) {\n\t\treturn context.redirect(`${loginUrl}?error=not_authenticated`);\n\t}\n\tif (!user.isAdmin) {\n\t\treturn context.redirect(`${loginUrl}?error=admin_required`);\n\t}\n\treturn user;\n}\n\n/**\n * Require brand access for a page\n * Redirects to login if user doesn't have access to the specified brand\n */\nexport async function requireBrandAccess(\n\tcontext: any,\n\tbrandId: number,\n\tloginUrl = '/login'\n) {\n\tconst user = context.locals.user;\n\tif (!user) {\n\t\treturn context.redirect(`${loginUrl}?error=not_authenticated`);\n\t}\n\tif (!user.isAdmin && !user.brandIds.includes(brandId)) {\n\t\treturn context.redirect(`${loginUrl}?error=access_denied`);\n\t}\n\treturn user;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/middleware/index.ts","../../src/middleware/auth.ts","../../src/middleware/route-guards.ts"],"sourcesContent":["/**\n * Middleware for @htlkg/astro\n * \n * This module exports:\n * - authMiddleware: Retrieves authenticated user and injects into locals\n * - routeGuard: Enforces access control based on route configuration\n * - onRequest: Composed middleware chain (auth + route guard)\n * - Helper functions: requireAuth, requireAdminAccess, requireBrandAccess\n */\n\nimport { sequence } from 'astro:middleware';\nimport { authMiddleware } from './auth.js';\nimport { routeGuard } from './route-guards.js';\n\n// Export individual middleware\nexport { authMiddleware } from './auth.js';\nexport {\n\trouteGuard,\n\trequireAuth,\n\trequireAdminAccess,\n\trequireBrandAccess,\n} from './route-guards.js';\n\n/**\n * Export composed middleware chain\n * Auth middleware runs first to populate locals.user\n * Route guard middleware runs second to enforce access control\n * \n * This is the default export that gets injected by the htlkg integration\n */\nexport const onRequest = sequence(authMiddleware, routeGuard);\n","/**\n * Authentication middleware for htlkg integration\n * \n * This middleware:\n * - Configures AWS Amplify for server-side auth\n * - Retrieves the authenticated user from AWS Amplify\n * - Injects the user into Astro.locals for use in pages and API routes\n * - Handles authentication errors gracefully\n */\n\nimport type { MiddlewareHandler } from 'astro';\nimport { Amplify } from 'aws-amplify';\nimport { getUser } from '@htlkg/core/auth';\nimport { globalSettings } from '@htlkg/core/amplify-astro-adapter';\nimport { amplifyConfig } from 'virtual:htlkg-config';\n\n// Track if Amplify has been configured\nlet amplifyConfigured = false;\n\n/**\n * Configure Amplify on first request\n */\nfunction ensureAmplifyConfigured(): void {\n\tif (amplifyConfigured) return;\n\n\ttry {\n\t\tif (!amplifyConfig) {\n\t\t\tconsole.warn('[htlkg Auth] No Amplify configuration provided');\n\t\t\treturn;\n\t\t}\n\n\t\t// Configure Amplify with SSR support\n\t\tAmplify.configure(amplifyConfig as any, { ssr: true });\n\t\t\n\t\t// Enable server-side auth in the adapter\n\t\tglobalSettings.enableServerSideAuth();\n\t\t\n\t\t// Check if we're on HTTPS (for secure cookies)\n\t\tconst isSSL = typeof window !== 'undefined' \n\t\t\t? window.location.protocol === 'https:' \n\t\t\t: process.env.NODE_ENV === 'production';\n\t\tglobalSettings.setIsSSLOrigin(isSSL);\n\t\t\n\t\tamplifyConfigured = true;\n\t\tconsole.info('[htlkg Auth] Amplify configured for server-side auth');\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : 'Unknown error';\n\t\tconsole.error(`[htlkg Auth] Failed to configure Amplify: ${errorMsg}`);\n\t}\n}\n\n/**\n * Auth middleware - retrieves authenticated user and injects into locals\n * \n * This middleware runs on every request and attempts to get the current\n * authenticated user from AWS Amplify. If successful, the user is injected\n * into context.locals.user. If authentication fails, locals.user is set to null.\n * \n * @example\n * // In an Astro page\n * const { user } = Astro.locals;\n * if (user) {\n * console.log('Authenticated user:', user.email);\n * }\n */\nexport const authMiddleware: MiddlewareHandler = async (context, next) => {\n\tconst { locals } = context;\n\n\t// Ensure Amplify is configured before attempting auth\n\tensureAmplifyConfigured();\n\n\ttry {\n\t\tconst user = await getUser(context);\n\t\tlocals.user = user;\n\t} catch (error) {\n\t\t// Set user to null on any authentication error\n\t\tlocals.user = null;\n\n\t\t// Log error without exposing sensitive information\n\t\tif (error instanceof Error) {\n\t\t\t// Filter out sensitive data from error messages\n\t\t\tconst safeMessage = error.message\n\t\t\t\t.replace(/token[=:]\\s*[^\\s,}]+/gi, 'token=***')\n\t\t\t\t.replace(/key[=:]\\s*[^\\s,}]+/gi, 'key=***')\n\t\t\t\t.replace(/secret[=:]\\s*[^\\s,}]+/gi, 'secret=***')\n\t\t\t\t.replace(/password[=:]\\s*[^\\s,}]+/gi, 'password=***');\n\n\t\t\tconsole.error('[htlkg Auth] Authentication failed:', safeMessage);\n\t\t} else {\n\t\t\tconsole.error('[htlkg Auth] Authentication failed: Unknown error');\n\t\t}\n\t}\n\n\treturn next();\n};\n","/**\n * Route guard middleware for htlkg integration\n * \n * This middleware enforces access control based on route configuration:\n * - Public routes: accessible to everyone\n * - Authenticated routes: require any logged-in user\n * - Admin routes: require admin privileges\n * - Brand routes: require brand-specific access or admin privileges\n */\n\nimport type { MiddlewareHandler } from 'astro';\nimport type { RoutePattern, RouteGuardConfig } from '../htlkg/config.js';\n\n// Import configuration from virtual module\nimport { routeGuardConfig } from 'virtual:htlkg-config';\n\n// Type assertion for the imported config\nconst config = routeGuardConfig as RouteGuardConfig;\n\n/**\n * Helper: Check if pathname matches any of the provided patterns\n */\nfunction matchesPattern(pathname: string, patterns: RoutePattern[]): boolean {\n\treturn patterns.some((pattern) => {\n\t\ttry {\n\t\t\tif (typeof pattern === 'string') {\n\t\t\t\t// Special case: \"/\" only matches exactly\n\t\t\t\tif (pattern === '/') {\n\t\t\t\t\treturn pathname === '/';\n\t\t\t\t}\n\t\t\t\t// String pattern: exact match or starts with (for sub-routes)\n\t\t\t\treturn pathname === pattern || pathname.startsWith(pattern + '/');\n\t\t\t}\n\t\t\t// RegExp pattern: test against pathname\n\t\t\treturn pattern.test(pathname);\n\t\t} catch (error) {\n\t\t\t// Log pattern matching errors but don't block the request\n\t\t\tconsole.error(\n\t\t\t\t'[htlkg] Error matching route pattern:',\n\t\t\t\terror instanceof Error ? error.message : 'Unknown error',\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t});\n}\n\n/**\n * Route guard middleware - protects routes based on configuration\n * \n * This middleware runs after authMiddleware and enforces access control\n * based on the route configuration provided to the htlkg integration.\n * \n * @example\n * // In astro.config.mjs\n * htlkg({\n * auth: {\n * publicRoutes: ['/login', '/'],\n * adminRoutes: [/^\\/admin/],\n * brandRoutes: [\n * { pattern: /^\\/brands\\/(\\d+)/, brandIdParam: 1 }\n * ],\n * loginUrl: '/login'\n * }\n * })\n */\nexport const routeGuard: MiddlewareHandler = async (context, next) => {\n\tconst { locals, url, redirect } = context;\n\tconst pathname = url.pathname;\n\n\tconst {\n\t\tpublicRoutes = [],\n\t\tauthenticatedRoutes = [],\n\t\tadminRoutes = [],\n\t\tbrandRoutes = [],\n\t\tloginUrl = '/login',\n\t} = config;\n\n\ttry {\n\t\t// Public routes - no auth required\n\t\tif (matchesPattern(pathname, publicRoutes)) {\n\t\t\treturn next();\n\t\t}\n\n\t\tconst user = locals.user;\n\n\t\t// Admin routes - require admin role\n\t\tif (matchesPattern(pathname, adminRoutes)) {\n\t\t\tif (!user || !user.isAdmin) {\n\t\t\t\treturn redirect(`${loginUrl}?error=admin_required`);\n\t\t\t}\n\t\t\treturn next();\n\t\t}\n\n\t\t// Brand routes - require brand access or admin\n\t\tfor (const brandRoute of brandRoutes) {\n\t\t\ttry {\n\t\t\t\tconst match = pathname.match(brandRoute.pattern);\n\t\t\t\tif (match) {\n\t\t\t\t\tconst brandId = Number.parseInt(match[brandRoute.brandIdParam], 10);\n\n\t\t\t\t\tif (Number.isNaN(brandId)) {\n\t\t\t\t\t\tconsole.warn(`[htlkg] Invalid brandId extracted from ${pathname}`);\n\t\t\t\t\t\treturn redirect(`${loginUrl}?error=invalid_brand`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!user || (!user.isAdmin && !user.brandIds.includes(brandId))) {\n\t\t\t\t\t\treturn redirect(`${loginUrl}?error=access_denied`);\n\t\t\t\t\t}\n\t\t\t\t\treturn next();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[htlkg] Error processing brand route for ${pathname}:`,\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error',\n\t\t\t\t);\n\t\t\t\t// Fail-safe: deny access on error\n\t\t\t\treturn redirect(`${loginUrl}?error=access_denied`);\n\t\t\t}\n\t\t}\n\n\t\t// Authenticated routes - require any logged-in user\n\t\tif (matchesPattern(pathname, authenticatedRoutes)) {\n\t\t\tif (!user) {\n\t\t\t\tconst returnUrl = encodeURIComponent(pathname + url.search);\n\t\t\t\treturn redirect(`${loginUrl}?redirect=${returnUrl}`);\n\t\t\t}\n\t\t\treturn next();\n\t\t}\n\n\t\t// Default: allow access\n\t\treturn next();\n\t} catch (error) {\n\t\t// Catch-all error handler for route guard\n\t\tconsole.error(\n\t\t\t'[htlkg] Unexpected error in route guard:',\n\t\t\terror instanceof Error ? error.message : 'Unknown error',\n\t\t);\n\t\t// Fail-safe: deny access and redirect to login\n\t\treturn redirect(`${loginUrl}?error=server_error`);\n\t}\n};\n\n/**\n * Helper functions for programmatic route protection in pages\n * These can be used in Astro pages for more fine-grained control\n */\n\n/**\n * Require authentication for a page\n * Redirects to login if user is not authenticated\n */\nexport async function requireAuth(context: any, loginUrl = '/login') {\n\tconst user = context.locals.user;\n\tif (!user) {\n\t\tconst currentUrl = context.url.pathname + context.url.search;\n\t\tconst encodedReturnUrl = encodeURIComponent(currentUrl);\n\t\treturn context.redirect(`${loginUrl}?redirect=${encodedReturnUrl}`);\n\t}\n\treturn user;\n}\n\n/**\n * Require admin access for a page\n * Redirects to login if user is not an admin\n */\nexport async function requireAdminAccess(context: any, loginUrl = '/login') {\n\tconst user = context.locals.user;\n\tif (!user) {\n\t\treturn context.redirect(`${loginUrl}?error=not_authenticated`);\n\t}\n\tif (!user.isAdmin) {\n\t\treturn context.redirect(`${loginUrl}?error=admin_required`);\n\t}\n\treturn user;\n}\n\n/**\n * Require brand access for a page\n * Redirects to login if user doesn't have access to the specified brand\n */\nexport async function requireBrandAccess(\n\tcontext: any,\n\tbrandId: number,\n\tloginUrl = '/login'\n) {\n\tconst user = context.locals.user;\n\tif (!user) {\n\t\treturn context.redirect(`${loginUrl}?error=not_authenticated`);\n\t}\n\tif (!user.isAdmin && !user.brandIds.includes(brandId)) {\n\t\treturn context.redirect(`${loginUrl}?error=access_denied`);\n\t}\n\treturn user;\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,23 @@
1
- import "../chunk-ZQ4XMJH7.js";
1
+ import {
2
+ applyClientFilters,
3
+ buildGraphQLFilter,
4
+ buildListQueryString,
5
+ buildListUrl,
6
+ getFilterCount,
7
+ hasActiveFilters,
8
+ mergeListParams,
9
+ paginateItems,
10
+ parseListParams,
11
+ processListData
12
+ } from "../chunk-2GML443T.js";
13
+ import {
14
+ chunkArray,
15
+ filterItems,
16
+ generateNestedPaths,
17
+ generatePaginatedPaths,
18
+ generateStaticPaths,
19
+ groupItems
20
+ } from "../chunk-33R4URZV.js";
2
21
  import {
3
22
  createHydrationScript,
4
23
  createHydrationScripts,
@@ -19,16 +38,11 @@ import {
19
38
  setCacheControl,
20
39
  setResponseHeaders
21
40
  } from "../chunk-WNMPTDCR.js";
22
- import {
23
- chunkArray,
24
- filterItems,
25
- generateNestedPaths,
26
- generatePaginatedPaths,
27
- generateStaticPaths,
28
- groupItems,
29
- sortItems
30
- } from "../chunk-33R4URZV.js";
31
41
  export {
42
+ applyClientFilters,
43
+ buildGraphQLFilter,
44
+ buildListQueryString,
45
+ buildListUrl,
32
46
  chunkArray,
33
47
  createHydrationScript,
34
48
  createHydrationScripts,
@@ -39,18 +53,23 @@ export {
39
53
  generatePaginatedPaths,
40
54
  generateStaticPaths,
41
55
  getClientIP,
56
+ getFilterCount,
42
57
  getHydratedData,
43
58
  getQueryParams,
44
59
  getRequestHeaders,
45
60
  getServerData,
46
61
  groupItems,
62
+ hasActiveFilters,
47
63
  isMobileDevice,
48
64
  isServerSide,
65
+ mergeListParams,
49
66
  mergeProps,
67
+ paginateItems,
68
+ parseListParams,
69
+ processListData,
50
70
  serializeForHydration,
51
71
  setCacheControl,
52
72
  setResponseHeaders,
53
- shouldHydrate,
54
- sortItems
73
+ shouldHydrate
55
74
  };
56
75
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,47 @@
1
+ // src/vue-app-setup.ts
2
+ import { amplifyConfig } from "virtual:htlkg-config";
3
+ import { Amplify } from "aws-amplify";
4
+ function setupVueApp(app) {
5
+ if (import.meta.env.DEV && typeof window !== "undefined") {
6
+ try {
7
+ import("@nanostores/vue/devtools").then(({ devtools }) => {
8
+ app.use(devtools, {});
9
+ }).catch(() => {
10
+ });
11
+ } catch {
12
+ }
13
+ }
14
+ try {
15
+ if (!amplifyConfig) {
16
+ console.warn("[htlkg] No Amplify configuration provided");
17
+ return;
18
+ }
19
+ if ("auth" in amplifyConfig || "data" in amplifyConfig || "storage" in amplifyConfig) {
20
+ Amplify.configure(amplifyConfig, { ssr: true });
21
+ } else {
22
+ const { userPoolId, userPoolClientId, region } = amplifyConfig;
23
+ if (userPoolId && userPoolClientId) {
24
+ const config = {
25
+ Auth: {
26
+ Cognito: {
27
+ userPoolId,
28
+ userPoolClientId,
29
+ ...region && { region }
30
+ }
31
+ }
32
+ };
33
+ Amplify.configure(config, { ssr: true });
34
+ } else {
35
+ console.error(
36
+ "[htlkg] Missing required Amplify configuration (userPoolId, userPoolClientId)"
37
+ );
38
+ }
39
+ }
40
+ } catch (error) {
41
+ console.error("[htlkg] Failed to setup Vue app:", error);
42
+ }
43
+ }
44
+ export {
45
+ setupVueApp as default
46
+ };
47
+ //# sourceMappingURL=vue-app-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vue-app-setup.ts"],"sourcesContent":["/**\n * Vue App Setup for htlkg Integration\n * \n * This file is automatically loaded by the Vue integration when vueAppSetup is enabled.\n * It configures AWS Amplify for client-side authentication in all Vue components.\n * It also sets up nanostores devtools integration for Vue DevTools.\n */\n\n/// <reference types=\"vite/client\" />\n\nimport { amplifyConfig } from \"virtual:htlkg-config\";\nimport type { App } from \"vue\";\nimport type { ResourcesConfig } from \"aws-amplify\";\nimport { Amplify } from \"aws-amplify\";\n\n/**\n * Setup function called by Astro's Vue integration\n * Configures Amplify for client-side authentication and nanostores devtools\n */\nexport default function setupVueApp(app: App): void {\n\t// Setup nanostores devtools in development\n\t// The devtools plugin will automatically detect stores used in components\n\tif (import.meta.env.DEV && typeof window !== 'undefined') {\n\t\ttry {\n\t\t\t// Dynamically import devtools plugin (only in browser)\n\t\t\timport('@nanostores/vue/devtools').then(({ devtools }) => {\n\t\t\t\t// Install devtools plugin - it will detect stores automatically\n\t\t\t\tapp.use(devtools, {});\n\t\t\t}).catch(() => {\n\t\t\t\t// Silently ignore - devtools are optional\n\t\t\t});\n\t\t} catch {\n\t\t\t// Silently ignore - devtools are optional\n\t\t}\n\t}\n\t\n\t// Setup Amplify\n\ttry {\n\t\tif (!amplifyConfig) {\n\t\t\tconsole.warn(\"[htlkg] No Amplify configuration provided\");\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if this is a full amplify_outputs.json config\n\t\tif (\n\t\t\t\"auth\" in amplifyConfig ||\n\t\t\t\"data\" in amplifyConfig ||\n\t\t\t\"storage\" in amplifyConfig\n\t\t) {\n\t\t\tAmplify.configure(amplifyConfig as ResourcesConfig, { ssr: true });\n\t\t} else {\n\t\t\t// Legacy individual config properties\n\t\t\tconst { userPoolId, userPoolClientId, region } = amplifyConfig as {\n\t\t\t\tuserPoolId?: string;\n\t\t\t\tuserPoolClientId?: string;\n\t\t\t\tregion?: string;\n\t\t\t};\n\n\t\t\tif (userPoolId && userPoolClientId) {\n\t\t\t\tconst config: ResourcesConfig = {\n\t\t\t\t\tAuth: {\n\t\t\t\t\t\tCognito: {\n\t\t\t\t\t\t\tuserPoolId,\n\t\t\t\t\t\t\tuserPoolClientId,\n\t\t\t\t\t\t\t...(region && { region }),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tAmplify.configure(config, { ssr: true });\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"[htlkg] Missing required Amplify configuration (userPoolId, userPoolClientId)\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(\"[htlkg] Failed to setup Vue app:\", error);\n\t\t// Don't throw - allow app to continue even if Amplify setup fails\n\t}\n}\n"],"mappings":";AAUA,SAAS,qBAAqB;AAG9B,SAAS,eAAe;AAMT,SAAR,YAA6B,KAAgB;AAGnD,MAAI,YAAY,IAAI,OAAO,OAAO,WAAW,aAAa;AACzD,QAAI;AAEH,aAAO,0BAA0B,EAAE,KAAK,CAAC,EAAE,SAAS,MAAM;AAEzD,YAAI,IAAI,UAAU,CAAC,CAAC;AAAA,MACrB,CAAC,EAAE,MAAM,MAAM;AAAA,MAEf,CAAC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACD;AAGA,MAAI;AACH,QAAI,CAAC,eAAe;AACnB,cAAQ,KAAK,2CAA2C;AACxD;AAAA,IACD;AAGA,QACC,UAAU,iBACV,UAAU,iBACV,aAAa,eACZ;AACD,cAAQ,UAAU,eAAkC,EAAE,KAAK,KAAK,CAAC;AAAA,IAClE,OAAO;AAEN,YAAM,EAAE,YAAY,kBAAkB,OAAO,IAAI;AAMjD,UAAI,cAAc,kBAAkB;AACnC,cAAM,SAA0B;AAAA,UAC/B,MAAM;AAAA,YACL,SAAS;AAAA,cACR;AAAA,cACA;AAAA,cACA,GAAI,UAAU,EAAE,OAAO;AAAA,YACxB;AAAA,UACD;AAAA,QACD;AAEA,gBAAQ,UAAU,QAAQ,EAAE,KAAK,KAAK,CAAC;AAAA,MACxC,OAAO;AACN,gBAAQ;AAAA,UACP;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD,SAAS,OAAO;AACf,YAAQ,MAAM,oCAAoC,KAAK;AAAA,EAExD;AACD;","names":[]}
package/package.json CHANGED
@@ -1,53 +1,87 @@
1
1
  {
2
2
  "name": "@htlkg/astro",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "exports": {
6
- ".": "./dist/index.js",
7
- "./htlkg": "./dist/htlkg/index.js",
8
- "./htlkg/config": "./dist/htlkg/config.js",
9
- "./middleware": "./dist/middleware/index.js",
10
- "./vue-app-setup": "./src/vue-app-setup.ts",
6
+ ".": {
7
+ "import": "./dist/index.js",
8
+ "types": "./src/index.ts"
9
+ },
10
+ "./htlkg": {
11
+ "import": "./dist/htlkg/index.js",
12
+ "types": "./src/htlkg/index.ts"
13
+ },
14
+ "./htlkg/config": {
15
+ "import": "./dist/htlkg/config.js",
16
+ "types": "./src/htlkg/config.ts"
17
+ },
18
+ "./middleware": {
19
+ "import": "./dist/middleware/index.js",
20
+ "types": "./src/middleware/index.ts"
21
+ },
22
+ "./vue-app-setup": {
23
+ "import": "./dist/vue-app-setup.js",
24
+ "types": "./src/vue-app-setup.ts"
25
+ },
11
26
  "./auth/LoginPage.astro": "./src/auth/LoginPage.astro",
12
27
  "./layouts": "./src/layouts/index.ts",
13
- "./layouts/*": "./src/layouts/*.astro",
28
+ "./layouts/*.astro": "./src/layouts/*.astro",
14
29
  "./patterns": "./src/patterns/index.ts",
15
30
  "./patterns/admin": "./src/patterns/admin/index.ts",
16
- "./patterns/admin/*": "./src/patterns/admin/*.astro",
31
+ "./patterns/admin/*.astro": "./src/patterns/admin/*.astro",
17
32
  "./patterns/brand": "./src/patterns/brand/index.ts",
18
- "./patterns/brand/*": "./src/patterns/brand/*.astro",
33
+ "./patterns/brand/*.astro": "./src/patterns/brand/*.astro",
19
34
  "./components": "./src/components/index.ts",
20
- "./components/*": "./src/components/*.astro",
21
- "./utils": "./dist/utils/index.js",
22
- "./utils/*": "./dist/utils/*.js"
35
+ "./components/*.astro": "./src/components/*.astro",
36
+ "./utils": {
37
+ "import": "./dist/utils/index.js",
38
+ "types": "./src/utils/index.ts"
39
+ },
40
+ "./utils/hydration": {
41
+ "import": "./dist/utils/hydration.js",
42
+ "types": "./src/utils/hydration.ts"
43
+ },
44
+ "./utils/ssr": {
45
+ "import": "./dist/utils/ssr.js",
46
+ "types": "./src/utils/ssr.ts"
47
+ },
48
+ "./utils/static": {
49
+ "import": "./dist/utils/static.js",
50
+ "types": "./src/utils/static.ts"
51
+ }
23
52
  },
24
53
  "files": [
25
54
  "dist",
26
55
  "src"
27
56
  ],
28
- "scripts": {
29
- "build": "tsup",
30
- "dev": "tsup --watch",
31
- "test": "vitest run",
32
- "test:watch": "vitest"
33
- },
34
57
  "dependencies": {
35
58
  "@astrojs/tailwind": "^6.0.2",
36
59
  "@astrojs/vue": "^5.0.0",
37
- "@htlkg/core": "^0.0.1",
38
- "@htlkg/components": "^0.0.1",
39
- "@hotelinking/ui": "^15.49.1",
60
+ "@hotelinking/ui": "^16.49.16",
61
+ "@nanostores/logger": "^1.0.0",
62
+ "@nanostores/vue": "^0.10.0",
40
63
  "astro": "^5.14.7",
41
64
  "aws-amplify": "^6.11.3",
65
+ "nanostores": "^0.11.3",
42
66
  "tailwindcss": "^3.4.18",
43
- "vue": "^3.5.22"
44
- },
45
- "publishConfig": {
46
- "access": "restricted"
67
+ "vue": "^3.5.22",
68
+ "@htlkg/core": "0.0.3",
69
+ "@htlkg/components": "0.0.3"
47
70
  },
48
71
  "devDependencies": {
72
+ "@vue/devtools-api": "^6.6.4",
49
73
  "tsup": "^8.0.0",
50
74
  "typescript": "^5.9.2",
75
+ "vite-plugin-vue-devtools": "^7.6.10",
51
76
  "vitest": "^3.2.4"
77
+ },
78
+ "publishConfig": {
79
+ "access": "restricted"
80
+ },
81
+ "scripts": {
82
+ "build": "tsup",
83
+ "dev": "tsup --watch",
84
+ "test": "vitest run",
85
+ "test:watch": "vitest"
52
86
  }
53
- }
87
+ }