@websolutespa/bom-mixer-models 2.0.2 → 3.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 (48) hide show
  1. package/CHANGELOG.md +5 -10
  2. package/dist/exports/proxy.d.ts +12 -0
  3. package/dist/exports/proxy.d.ts.map +1 -0
  4. package/dist/exports/proxy.js +172 -0
  5. package/dist/exports/proxy.js.map +1 -0
  6. package/dist/exports/server.d.ts +184 -0
  7. package/dist/exports/server.d.ts.map +1 -0
  8. package/dist/exports/server.js +960 -0
  9. package/dist/exports/server.js.map +1 -0
  10. package/dist/index.d.ts +254 -424
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +41 -1450
  13. package/dist/index.js.map +1 -0
  14. package/dist/lazy-JamSYYoh.d.ts +84 -0
  15. package/dist/lazy-JamSYYoh.d.ts.map +1 -0
  16. package/dist/page-BLbZbnWg.js +12 -0
  17. package/dist/page-BLbZbnWg.js.map +1 -0
  18. package/dist/route-k0W3AKyo.js +53 -0
  19. package/dist/route-k0W3AKyo.js.map +1 -0
  20. package/package.json +75 -27
  21. package/src/app/app.service.ts +1 -1
  22. package/src/captions/captions.handler.ts +1 -1
  23. package/src/category/category.service.ts +3 -3
  24. package/src/consent_preference/consent_preference.service.ts +4 -4
  25. package/src/consent_preference/consent_preference.ts +1 -1
  26. package/src/country/country.service.ts +4 -4
  27. package/src/exports/proxy.ts +2 -0
  28. package/src/exports/server.ts +22 -0
  29. package/src/index.ts +3 -20
  30. package/src/label/label.service.ts +3 -3
  31. package/src/lazy/lazy.service.ts +28 -0
  32. package/src/lazy/lazy.ts +0 -26
  33. package/src/locale/locale.service.ts +3 -13
  34. package/src/locale/locale.ts +9 -0
  35. package/src/market/market.service.ts +3 -3
  36. package/src/menu/menu.service.ts +3 -3
  37. package/src/page/page.service.ts +47 -7
  38. package/src/page/page.ts +9 -0
  39. package/src/province/province.service.ts +4 -4
  40. package/src/redirect/redirect.service.ts +4 -4
  41. package/src/region/region.service.ts +4 -4
  42. package/src/route/route-revalidate.handler.ts +54 -43
  43. package/src/route/route.interceptor.ts +18 -3
  44. package/src/route/route.service.ts +11 -49
  45. package/src/route/route.ts +64 -0
  46. package/src/session/session.service.ts +12 -4
  47. package/src/sitemap/sitemap.service.ts +5 -5
  48. package/dist/index.mjs +0 -1363
@@ -1,10 +1,10 @@
1
- import { ICategorized, ICategory, IComponent, IEquatable, ILayout, IPage, IRoute, IRouteLink, PageProps, QueryParams, SchemaType, asCategoryId, asServerProps, defaultLocale, defaultMarket } from '@websolutespa/bom-core';
2
- import { getStore } from '@websolutespa/bom-mixer-store';
1
+ import { asCategoryId, asServerProps, defaultLocale, defaultMarket, ICategorized, ICategory, IComponent, IEquatable, ILayout, IPage, IRoute, IRouteLink, PageProps, QueryParams, SchemaType } from '@websolutespa/bom-core';
2
+ import { getStore } from '@websolutespa/bom-mixer-store/server';
3
3
  import { Redirect } from 'next';
4
4
  import { getSegments } from '../category/category.service';
5
5
  import { resolveLabel } from '../label/label.service';
6
6
  import { getLayout } from '../layout/layout.service';
7
- import { getDecoratedComponents } from '../lazy/lazy';
7
+ import { getDecoratedComponents } from '../lazy/lazy.service';
8
8
  import { getBreadcrumbFromSegments, getRoutes } from '../route/route.service';
9
9
  import { IModelStore } from '../store/store';
10
10
 
@@ -77,6 +77,43 @@ export async function getPage<T extends ICategorized = ICategorized>(schema: str
77
77
  }
78
78
  }
79
79
 
80
+ export async function getSchemaRoutes(schema: string, market: string, locale: string): Promise<IRoute[]> {
81
+ const routes: IRoute[] = await getRoutes({
82
+ where: {
83
+ market: {
84
+ equals: market,
85
+ },
86
+ locale: {
87
+ equals: locale,
88
+ },
89
+ schema: {
90
+ equals: schema,
91
+ },
92
+ },
93
+ });
94
+ return routes;
95
+ }
96
+
97
+ export async function getNotFoundRoute(market: string, locale: string): Promise<IRoute | undefined> {
98
+ const routes: IRoute[] = await getRoutes({
99
+ where: {
100
+ market: {
101
+ equals: market,
102
+ },
103
+ locale: {
104
+ equals: locale,
105
+ },
106
+ schema: {
107
+ equals: 'notfound',
108
+ },
109
+ },
110
+ });
111
+ if (routes.length > 0) {
112
+ return routes[0];
113
+ }
114
+ return;
115
+ }
116
+
80
117
  export async function NotFound(market: string, locale: string): Promise<{ redirect: Redirect } | void> {
81
118
  const routes: IRoute[] = await getRoutes({
82
119
  where: {
@@ -94,7 +131,7 @@ export async function NotFound(market: string, locale: string): Promise<{ redire
94
131
  if (routes.length > 0) {
95
132
  return {
96
133
  redirect: {
97
- destination: routes[0].id,
134
+ destination: routes[0]!.id,
98
135
  permanent: false,
99
136
  },
100
137
  };
@@ -106,7 +143,7 @@ export async function getPageRoutes(schema: string, id: IEquatable): Promise<IRo
106
143
  const store = await getStore<IModelStore>();
107
144
  let routes: IRoute[] = [];
108
145
  try {
109
- routes = await store.route.findMany({
146
+ routes = await store.route!.findMany({
110
147
  where: {
111
148
  page: {
112
149
  equals: id,
@@ -137,7 +174,7 @@ export async function getPageCategory<T extends ICategorized>(schema: string, pa
137
174
  const category = pages.length ? pages[0] : null;
138
175
  // console.log(page, market, locale, category);
139
176
  if (category) {
140
- const routes = await store.route.findMany({
177
+ const routes = await store.route!.findMany({
141
178
  where: {
142
179
  schema: {
143
180
  equals: schema,
@@ -206,7 +243,10 @@ export async function getErrorPageLayout(): Promise<{ layout: ILayout, page: IPa
206
243
 
207
244
  export type PartialPageProps<T extends ICategorized, B> = Omit<PageProps<T>, 'page'> & Partial<Pick<PageProps<T>, 'page'>> & B;
208
245
 
209
- export async function getPageProps<T extends ICategorized, B = any>(props: PartialPageProps<T, B>, extraComponents?: IComponent[]) {
246
+ export async function getPageProps<T extends ICategorized, B = any>(
247
+ props: PartialPageProps<T, B>,
248
+ extraComponents?: IComponent[]
249
+ ) {
210
250
  if (props.page) {
211
251
  await getDecoratedComponents(props as PageProps<T> & B, extraComponents);
212
252
  }
@@ -0,0 +1,9 @@
1
+
2
+ export function getPublicUrl() {
3
+ const publicUrl = process.env && process.env.NEXT_PUBLIC_URL ? process.env.NEXT_PUBLIC_URL : '';
4
+ return publicUrl;
5
+ }
6
+
7
+ export function resolveHref(href: string = '') {
8
+ return href.startsWith('http') ? href : `${getPublicUrl()}${href}`;
9
+ }
@@ -1,21 +1,21 @@
1
1
  import { IEquatable, INamedEntity, IPaginationResult, QueryParams } from '@websolutespa/bom-core';
2
- import { getStore } from '@websolutespa/bom-mixer-store';
2
+ import { getStore } from '@websolutespa/bom-mixer-store/server';
3
3
  import { IModelStore } from '../store/store';
4
4
 
5
5
  export async function getProvinces(locale?: string): Promise<INamedEntity[]> {
6
6
  const store = await getStore<IModelStore>();
7
- const items = await store.i18n_province.findMany({ locale });
7
+ const items = await store.i18n_province!.findMany({ locale });
8
8
  return items;
9
9
  }
10
10
 
11
11
  export async function getProvince(id: IEquatable, params: QueryParams = {}): Promise<INamedEntity | undefined> {
12
12
  const store = await getStore<IModelStore>();
13
- const item = await store.i18n_province.findOne(id, params);
13
+ const item = await store.i18n_province!.findOne(id, params);
14
14
  return item;
15
15
  }
16
16
 
17
17
  export async function getProvincesPagination(params: QueryParams = {}): Promise<IPaginationResult<INamedEntity>> {
18
18
  const store = await getStore<IModelStore>();
19
- const pagination = await store.i18n_province.findPaged<INamedEntity>(params);
19
+ const pagination = await store.i18n_province!.findPaged<INamedEntity>(params);
20
20
  return pagination;
21
21
  }
@@ -1,22 +1,22 @@
1
1
  import { IEquatable, ILayout, IPaginationResult, IRedirect, QueryParams } from '@websolutespa/bom-core';
2
- import { getStore } from '@websolutespa/bom-mixer-store';
2
+ import { getStore } from '@websolutespa/bom-mixer-store/server';
3
3
  import { IModelStore } from '../store/store';
4
4
 
5
5
  export async function getRedirects(locale?: string): Promise<IRedirect[]> {
6
6
  const store = await getStore<IModelStore>();
7
- const items = await store.redirect.findMany({ locale });
7
+ const items = await store.redirect!.findMany({ locale });
8
8
  return items;
9
9
  }
10
10
 
11
11
  export async function getRedirect(id: IEquatable, params: QueryParams = {}): Promise<IRedirect | undefined> {
12
12
  const store = await getStore<IModelStore>();
13
- const item = await store.redirect.findOne(id, params);
13
+ const item = await store.redirect!.findOne(id, params);
14
14
  return item;
15
15
  }
16
16
 
17
17
  export async function getRedirectsPagination(params: QueryParams = {}): Promise<IPaginationResult<IRedirect>> {
18
18
  const store = await getStore<IModelStore>();
19
- const pagination = await store.redirect.findPaged<IRedirect>(params);
19
+ const pagination = await store.redirect!.findPaged<IRedirect>(params);
20
20
  return pagination;
21
21
  }
22
22
 
@@ -1,21 +1,21 @@
1
1
  import { IEquatable, INamedEntity, IPaginationResult, QueryParams } from '@websolutespa/bom-core';
2
- import { getStore } from '@websolutespa/bom-mixer-store';
2
+ import { getStore } from '@websolutespa/bom-mixer-store/server';
3
3
  import { IModelStore } from '../store/store';
4
4
 
5
5
  export async function getRegions(locale?: string): Promise<INamedEntity[]> {
6
6
  const store = await getStore<IModelStore>();
7
- const items = await store.i18n_region.findMany({ locale });
7
+ const items = await store.i18n_region!.findMany({ locale });
8
8
  return items;
9
9
  }
10
10
 
11
11
  export async function getRegion(id: IEquatable, params: QueryParams = {}): Promise<INamedEntity | undefined> {
12
12
  const store = await getStore<IModelStore>();
13
- const item = await store.i18n_region.findOne(id, params);
13
+ const item = await store.i18n_region!.findOne(id, params);
14
14
  return item;
15
15
  }
16
16
 
17
17
  export async function getRegionsPagination(params: QueryParams = {}): Promise<IPaginationResult<INamedEntity>> {
18
18
  const store = await getStore<IModelStore>();
19
- const pagination = await store.i18n_region.findPaged<INamedEntity>(params);
19
+ const pagination = await store.i18n_region!.findPaged<INamedEntity>(params);
20
20
  return pagination;
21
21
  }
@@ -1,43 +1,54 @@
1
-
2
- import { apiHandler } from '@websolutespa/bom-mixer-store';
3
- import { NextApiRequest, NextApiResponse } from 'next';
4
- import { getRoutes, resolveRoute } from './route.service';
5
-
6
- export function routeRevalidateHandler() {
7
- return apiHandler({
8
- post: async (request: NextApiRequest, response: NextApiResponse) => {
9
- // console.log(request.headers);
10
- const authorization = request.headers.authorization;
11
- const bearer = authorization && authorization.replace('Bearer ', '');
12
- // Check for secret to confirm this is a valid request
13
- if (bearer !== process.env.HOOKS_SECRET) {
14
- return response.status(401).json({ message: 'Invalid token' });
15
- }
16
- try {
17
- /* { "id": 1, "schema": "product", "href": "/product/xxxx" } */
18
- const { href } = request.body;
19
- const routes = await getRoutes({
20
- where: {
21
- id: { equals: href },
22
- },
23
- });
24
- if (routes.length === 0) {
25
- // console.log('route.notfound', href);
26
- return response.status(404).send(`routeRevalidateHandler.notFound ${href}`);
27
- }
28
- // console.log('routes', routes);
29
- for (const route of routes) {
30
- // console.log('route.found', route);
31
- const resolvedRoute = resolveRoute(route);
32
- console.log('route.revalidating', resolvedRoute);
33
- await response.revalidate(resolvedRoute);
34
- }
35
- return response.json({ revalidated: true });
36
- } catch (error) {
37
- // If there was an error, Next.js will continue
38
- // to show the last successfully generated page
39
- return response.status(500).send('Error revalidating');
40
- }
41
- },
42
- });
43
- }
1
+
2
+ import { Where } from '@websolutespa/bom-core';
3
+ import { apiHandler } from '@websolutespa/bom-mixer-store/server';
4
+ import { NextApiRequest, NextApiResponse } from 'next';
5
+ import { resolveRoute } from './route';
6
+ import { getRoutes } from './route.service';
7
+
8
+ export function routeRevalidateHandler() {
9
+ return apiHandler({
10
+ post: async (request: NextApiRequest, response: NextApiResponse) => {
11
+ // console.log(request.headers);
12
+ const authorization = request.headers.authorization;
13
+ const bearer = authorization && authorization.replace('Bearer ', '');
14
+ // Check for secret to confirm this is a valid request
15
+ if (bearer !== process.env.MIXER_SECRET) {
16
+ return response.status(401).json({ message: 'Invalid token' });
17
+ }
18
+ try {
19
+ /* { "id": 1, "schema": "product", "href": "/product/xxxx" } */
20
+ const { href, schema, page } = request.body || {};
21
+
22
+ let where: Where;
23
+ if (href) {
24
+ where = { id: { equals: href } };
25
+ } else if (schema && page) {
26
+ where = { schema: { equals: schema }, page: { equals: page } };
27
+ } else {
28
+ return response.status(400).send('Missing href or schema and page');
29
+ }
30
+
31
+ const routes = await getRoutes({ where });
32
+ if (routes.length === 0) {
33
+ // console.log('route.notfound', href);
34
+ const notFoundTarget = href || `${schema}:${page}`;
35
+ return response.status(404).send(`routeRevalidateHandler.notFound ${notFoundTarget}`);
36
+ }
37
+ // console.log('routes', routes);
38
+ for (const route of routes) {
39
+ // console.log('route.found', route);
40
+ const resolvedRoute = resolveRoute(route);
41
+ // console.log('route.revalidating', resolvedRoute);
42
+ await response.revalidate(resolvedRoute);
43
+
44
+ // @TODO: CDN cache purge
45
+ }
46
+ return response.json({ revalidated: true });
47
+ } catch (error) {
48
+ // If there was an error, Next.js will continue
49
+ // to show the last successfully generated page
50
+ return response.status(500).send('Error revalidating');
51
+ }
52
+ },
53
+ });
54
+ }
@@ -1,8 +1,8 @@
1
1
  import { IMarket, IRoute, asEquatable, defaultLocale, defaultMarket, getHost, isDevelopment } from '@websolutespa/bom-core';
2
2
  import { StoreStrategy, localApiGet, localApiPost, storeApiGet, storeApiPost, storeStrategy } from '@websolutespa/bom-mixer-store';
3
3
  import { NextFetchEvent, NextRequest, NextResponse } from 'next/server';
4
- import { getPublicUrl, resolveHref } from '../page/page.service';
5
- import { resolveRoute } from './route.service';
4
+ import { getPublicUrl, resolveHref } from '../page/page';
5
+ import { resolveRoute } from './route';
6
6
 
7
7
  export async function detectLocale(request: NextRequest, defaultLocale?: string) {
8
8
  const acceptLanguage = request.headers.get('accept-language')?.split(',')[0];
@@ -11,7 +11,10 @@ export async function detectLocale(request: NextRequest, defaultLocale?: string)
11
11
  }
12
12
 
13
13
  export async function detectCountry(request: NextRequest, defaultMarket?: string) {
14
- const ip = request.ip || request.headers.get('X-Forwarded-For') || request.headers.get('x-real-ip');
14
+ let ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip');
15
+ if (ip) {
16
+ ip = ip.split(',')[0];
17
+ }
15
18
  const isValidIp = ip?.match(/^(\d+?)\.(\d+?)\.(\d+?)\.(\d+?)$/);
16
19
  let detectedCountry = '';
17
20
  try {
@@ -67,13 +70,18 @@ export async function routeAutoDetection(request: NextRequest, next: NextFetchEv
67
70
  }
68
71
  // console.log('routeInterceptor.routeAutoDetection', url.pathname);
69
72
  const rootRoutes = await getRootRoutes();
73
+ // console.log('routeInterceptor.routeAutoDetection.rootRoutes', rootRoutes);
70
74
  const defaultRoute = rootRoutes.find(x => x.id === '/');
75
+ // console.log('routeInterceptor.routeAutoDetection.defaultRoute', defaultRoute);
71
76
  if (defaultRoute) {
72
77
  return;
73
78
  }
74
79
  const markets = await getMarkets();
80
+ // console.log('routeInterceptor.routeAutoDetection.markets', markets);
75
81
  const market = markets.find(x => x.isDefault) || markets.find(x => x.id === defaultMarket) || markets[0];
82
+ // console.log('routeInterceptor.routeAutoDetection.market', market);
76
83
  const detectedCountry = await detectCountry(request, market.id);
84
+ // console.log('routeInterceptor.routeAutoDetection.detectedCountry', detectedCountry);
77
85
  const detectedMarket = detectedCountry ? (
78
86
  markets.filter(x => Array.isArray(x.countries)).find(x => {
79
87
  const countries: string[] = (x.countries || []).map(x => typeof x === 'string' ? x : x.id as string);
@@ -81,14 +89,18 @@ export async function routeAutoDetection(request: NextRequest, next: NextFetchEv
81
89
  }) ||
82
90
  markets.find(x => !Array.isArray(x.countries))
83
91
  ) : undefined;
92
+ // console.log('routeInterceptor.routeAutoDetection.detectedMarket', detectedMarket);
84
93
  let detectedMarketRoutes = rootRoutes.filter(x => x.market === detectedMarket?.id);
85
94
  if (detectedMarketRoutes.length === 0) {
86
95
  detectedMarketRoutes = rootRoutes.filter(x => x.market === market.id);
87
96
  }
97
+ // console.log('routeInterceptor.routeAutoDetection.detectedMarketRoutes', detectedMarketRoutes);
88
98
  const defaultMarketLocale = market.defaultLanguage ? (
89
99
  typeof market.defaultLanguage === 'string' ? market.defaultLanguage : market.defaultLanguage.id
90
100
  ) as string : defaultLocale;
101
+ // console.log('routeInterceptor.routeAutoDetection.defaultMarketLocale', defaultMarketLocale);
91
102
  const detectedLocale = await detectLocale(request, defaultMarketLocale);
103
+ // console.log('routeInterceptor.routeAutoDetection.detectedLocale', detectedLocale);
92
104
  const detectedLocaleRoutes = detectedMarketRoutes.filter(x => x.locale === detectedLocale);
93
105
  const detectedRoute =
94
106
  detectedLocaleRoutes.length > 0 ?
@@ -98,6 +110,7 @@ export async function routeAutoDetection(request: NextRequest, next: NextFetchEv
98
110
  const marketLocale = (market.defaultLanguage ? asEquatable(market.defaultLanguage as string) : defaultMarketLocale);
99
111
  return x.locale === marketLocale;
100
112
  })!;
113
+ // console.log('routeInterceptor.routeAutoDetection.detectedRoute', detectedRoute);
101
114
  if (detectedRoute && detectedRoute.id !== url.pathname) {
102
115
  console.log('routeInterceptor.routeAutoDetection', detectedLocale, detectedCountry, detectedRoute.id);
103
116
  route = detectedRoute.id;
@@ -111,8 +124,10 @@ export async function routeInterceptor(request: NextRequest, next: NextFetchEven
111
124
  let route: IRoute | undefined;
112
125
  let url = request.nextUrl;
113
126
  const hrefBeforeRedirect = getHrefBeforeRedirect(request);
127
+ // console.log('routeInterceptor._live', request.nextUrl.searchParams.get('_live'));
114
128
  try {
115
129
  const redirectUrl = await routeAutoDetection(request, next);
130
+ // console.log('routeInterceptor.routeAutoDetection', redirectUrl);
116
131
  if (redirectUrl) {
117
132
  const response = NextResponse.redirect(resolveHref(redirectUrl), isDevelopment ? 307 : 301);
118
133
  response.cookies.set({
@@ -1,25 +1,27 @@
1
- import { asCategoryId, defaultLocale, defaultMarket, findRouteOfCategory, getRootCategory, ICategory, IRoute, IRouteLink, localize, QueryParams } from '@websolutespa/bom-core';
2
- import { buildStrategy, BuildStrategy, getStore, StoreStrategy, storeStrategy } from '@websolutespa/bom-mixer-store';
1
+ import { asCategoryId, defaultLocale, defaultMarket, findRouteOfCategory, getRootCategory, ICategory, IRoute, IRouteLink, QueryParams } from '@websolutespa/bom-core';
2
+ import { buildStrategy, BuildStrategy, StoreStrategy, storeStrategy } from '@websolutespa/bom-mixer-store';
3
+ import { getStore } from '@websolutespa/bom-mixer-store/server';
3
4
  import { IModelStore } from '../store/store';
5
+ import { newRouteLink, routeToRouteLink } from './route';
4
6
 
5
7
  export type StaticPath = { params: { [key: string]: string } };
6
8
 
7
9
  export async function getRoutes(params: QueryParams = {}): Promise<IRoute[]> {
8
10
  const store = await getStore<IModelStore>();
9
- const routes = await store.route.findMany(params);
11
+ const routes = await store.route!.findMany(params);
10
12
  return routes;
11
13
  }
12
14
 
13
15
  export async function getRoute(id: string): Promise<IRoute | undefined> {
14
16
  const store = await getStore<IModelStore>();
15
- const route = await store.route.findOne(id);
17
+ const route = await store.route!.findOne(id);
16
18
  // console.log('RouteService.getRoute', id, '->', route);
17
19
  return route;
18
20
  }
19
21
 
20
22
  export async function getRoutesForSchemas(schemas: string[], market?: string, locale?: string): Promise<{ [key: string]: string; }> {
21
23
  const store = await getStore<IModelStore>();
22
- const routes = await store.route.findMany({
24
+ const routes = await store.route!.findMany({
23
25
  where: {
24
26
  schema: {
25
27
  in: schemas,
@@ -43,7 +45,7 @@ export async function getRoutesForSchemas(schemas: string[], market?: string, lo
43
45
 
44
46
  export async function getRoutesForTemplates(templates: string[], market?: string, locale?: string): Promise<{ [key: string]: string; }> {
45
47
  const store = await getStore<IModelStore>();
46
- const routes = await store.route.findMany({
48
+ const routes = await store.route!.findMany({
47
49
  where: {
48
50
  template: {
49
51
  in: templates,
@@ -75,7 +77,7 @@ export async function getStaticPathsForSchema(
75
77
  return [];
76
78
  }
77
79
  const store = await getStore<IModelStore>();
78
- const routes = await store.route.findMany({
80
+ const routes = await store.route!.findMany({
79
81
  where: template ? ({
80
82
  and: [{
81
83
  template: {
@@ -151,7 +153,7 @@ export async function getBreadcrumbFromSegments(segments: ICategory[], route: IR
151
153
  export async function getRouteLinkTree(market: string, locale: string): Promise<IRouteLink | undefined> {
152
154
  const store = await getStore<IModelStore>();
153
155
  // console.log('getRouteLinkTree.store', store);
154
- const routes = await store.route.findMany({
156
+ const routes = await store.route!.findMany({
155
157
  where: {
156
158
  market: {
157
159
  equals: market,
@@ -162,7 +164,7 @@ export async function getRouteLinkTree(market: string, locale: string): Promise<
162
164
  },
163
165
  });
164
166
  // console.log('getRouteLinkTree.routes', routes.map(x => x.id));
165
- const categories = await store.category.findMany({ market, locale });
167
+ const categories = await store.category!.findMany({ market, locale });
166
168
  // console.log('getRouteLinkTree.categories', categories.map(x => x.id));
167
169
  const rootCategory = getRootCategory(categories);
168
170
  // console.log('getRouteLinkTree.rootCategory', rootCategory?.id);
@@ -205,43 +207,3 @@ export function getRouteLinkCategory(
205
207
  routeLink.items = items;
206
208
  return routeLink;
207
209
  }
208
-
209
- export function newRouteLink(category: ICategory, route: IRoute | undefined, locale: string): IRouteLink {
210
- const href = (route && route.id) ? route.id.toString() : '/';
211
- const id = route?.page || category.id;
212
- const media = category.media || route?.media;
213
- const schema = route?.template || route?.schema || category?.schema || 'unknown';
214
- const title = localize(category.title || route?.title || 'untitled', locale);
215
- const routeLink = {
216
- category: category.id,
217
- href,
218
- id,
219
- items: [],
220
- media,
221
- schema,
222
- title,
223
- };
224
- return routeLink;
225
- }
226
-
227
- export function routeToRouteLink(route: IRoute): IRouteLink {
228
- const routeLink: IRouteLink = {
229
- category: asCategoryId(route.category),
230
- href: route.id,
231
- id: route.page,
232
- items: [],
233
- media: route.media,
234
- schema: route.schema,
235
- title: route.title,
236
- };
237
- return routeLink;
238
- }
239
-
240
- export function resolveRoute(route: IRoute & { splat?: string }) {
241
- // console.log('resolveRoute', route);
242
- const routepath: string = route.template || route.schema;
243
- // convert route to next.js pages folder schema
244
- const resolvedPathname = `/${route.market}/${route.locale}/${routepath}/${route.page}${route.splat || ''}`;
245
- // console.log('resolveRoute', route.schema, resolvedPathname);
246
- return resolvedPathname;
247
- }
@@ -0,0 +1,64 @@
1
+ import { asCategoryId, findRouteOfCategory, getRootCategory, ICategory, IRoute, IRouteLink, localize } from '@websolutespa/bom-core';
2
+
3
+ export type StaticPath = { params: { [key: string]: string } };
4
+
5
+ export function categoryToRouteLink(routes: IRoute[], categories: ICategory[], category: ICategory, locale: string): IRouteLink | undefined {
6
+ const route = findRouteOfCategory(routes, category.id);
7
+ if (!route) {
8
+ return undefined;
9
+ }
10
+ const rootCategory = getRootCategory(categories);
11
+ const childCategories = categories.filter(x => {
12
+ const parentId = asCategoryId(x.category);
13
+ return rootCategory && rootCategory.id === category.id ?
14
+ (x.id !== rootCategory.id && (parentId === category.id || !parentId)) :
15
+ parentId === category.id;
16
+ });
17
+ // console.log('childCategories', category.id, childCategories);
18
+ const routeLink = newRouteLink(category, route, locale);
19
+ // console.log('categoryToRouteLink', href, category.id, route);
20
+ routeLink.items = childCategories
21
+ .map(x => categoryToRouteLink(routes, categories, x, locale))
22
+ .filter(x => x !== undefined) as IRouteLink[];
23
+ return routeLink;
24
+ }
25
+
26
+ export function newRouteLink(category: ICategory, route: IRoute | undefined, locale: string): IRouteLink {
27
+ const href = (route && route.id) ? route.id.toString() : '/';
28
+ const id = route?.page || category.id;
29
+ const media = category.media || route?.media;
30
+ const schema = route?.template || route?.schema || category?.schema || 'unknown';
31
+ const title = localize(category.title || route?.title || 'untitled', locale);
32
+ const routeLink = {
33
+ category: category.id,
34
+ href,
35
+ id,
36
+ items: [],
37
+ media,
38
+ schema,
39
+ title,
40
+ };
41
+ return routeLink;
42
+ }
43
+
44
+ export function routeToRouteLink(route: IRoute): IRouteLink {
45
+ const routeLink: IRouteLink = {
46
+ category: asCategoryId(route.category),
47
+ href: route.id,
48
+ id: route.page,
49
+ items: [],
50
+ media: route.media,
51
+ schema: route.schema,
52
+ title: route.title,
53
+ };
54
+ return routeLink;
55
+ }
56
+
57
+ export function resolveRoute(route: IRoute & { splat?: string }) {
58
+ // console.log('resolveRoute', route);
59
+ const routepath: string = route.template || route.schema;
60
+ // convert route to next.js pages folder schema
61
+ const resolvedPathname = `/${route.market}/${route.locale}/${routepath}/${route.page}${route.splat || ''}`;
62
+ // console.log('resolveRoute', route.schema, resolvedPathname);
63
+ return resolvedPathname;
64
+ }
@@ -4,21 +4,29 @@ import { getIronSession, IronSession, SessionOptions } from 'iron-session';
4
4
  import { NextApiRequest, NextApiResponse } from 'next';
5
5
  import { NextRequest, NextResponse } from 'next/server';
6
6
 
7
+ function getSessionSecret() {
8
+ const secret = process.env.MIXER_SECRET || '';
9
+ if (!secret) {
10
+ throw 'getSessionSecret MIXER_SECRET not defined';
11
+ }
12
+ return secret;
13
+ }
14
+
7
15
  export async function getSession<T extends object = Record<string, any>>(
8
16
  request: NextRequest | NextApiRequest | IncomingMessage & {
9
17
  cookies: Partial<{ [key: string]: string }>;
10
18
  },
11
19
  response: NextResponse | NextApiResponse | ServerResponse<IncomingMessage>
12
20
  ): Promise<IronSession<T>> {
13
- const COOKIE_NAME = 'websolutespa-next-js';
14
- const COOKIE_PASSWORD = process.env.SECRET_COOKIE_PASSWORD as string || 'SECRET_COOKIE_PASSWORD_32_CHARS_LONG';
21
+ const cookieName = 'websolutespa-next-js';
22
+ const password = getSessionSecret();
15
23
  const sessionOptions: SessionOptions = {
16
- cookieName: COOKIE_NAME,
24
+ cookieName,
25
+ password,
17
26
  // secure: true should be used in production (HTTPS) but can't be used in development (HTTP)
18
27
  cookieOptions: {
19
28
  secure: !isDevelopment,
20
29
  },
21
- password: COOKIE_PASSWORD,
22
30
  };
23
31
  const session = await getIronSession<T>(request, response, sessionOptions);
24
32
  return session;
@@ -24,7 +24,7 @@ export async function getSiteMapIndex(origin: string): Promise<string> {
24
24
  // console.log(sitemapRoutes.shift(), sitemapRoutes.pop());
25
25
  sitemaps.push({
26
26
  id: `/${market.id}/${locale.id}/sitemap.xml`,
27
- updatedAt: sitemapRoutes.length > 0 ? sitemapRoutes[sitemapRoutes.length - 1].updatedAt : undefined,
27
+ updatedAt: sitemapRoutes.length > 0 ? sitemapRoutes[sitemapRoutes.length - 1]!.updatedAt : undefined,
28
28
  });
29
29
  });
30
30
  return `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="${origin}/sitemap.xsl"?>
@@ -122,8 +122,8 @@ export async function getSiteMapXML(origin: string, marketId?: string, localeId?
122
122
  let locales: ILocale[] = await getLocales();
123
123
  markets = markets.filter(x => x.isActive !== false);
124
124
  locales = locales.filter(x => x.isActive !== false);
125
- const defaultMarket = markets.find(x => marketId ? x.id === marketId : x.isDefault) || markets[0];
126
- const defaultLocale = locales.find(x => localeId ? x.id === localeId : x.isDefault) || locales[0];
125
+ const defaultMarket = markets.find(x => marketId ? x.id === marketId : x.isDefault) || markets[0]!;
126
+ const defaultLocale = locales.find(x => localeId ? x.id === localeId : x.isDefault) || locales[0]!;
127
127
  const defaultMarketLocale = defaultMarket && defaultMarket.defaultLanguage ? defaultMarket.defaultLanguage : defaultLocale.id;
128
128
  const routes: IRoute[] = await getRoutes();
129
129
  const isCanonicalRoute: (route: IRoute) => boolean = (marketId && localeId) ? (route) => {
@@ -155,7 +155,7 @@ ${getSiteMapXMLUrls(origin, canonicalRoutes)}
155
155
  export async function getSiteMapXSL(localeId?: string): Promise<string> {
156
156
  let locales: ILocale[] = await getLocales();
157
157
  locales = locales.filter(x => x.isActive !== false);
158
- const defaultLocale = locales.find(x => localeId ? x.id === localeId : x.isDefault) || locales[0];
158
+ const locale = locales.find(x => localeId ? x.id === localeId : x.isDefault) || locales[0]!;
159
159
  return /* html */`<?xml version="1.0" encoding="UTF-8"?>
160
160
  <xsl:stylesheet version="2.0"
161
161
  xmlns:html="http://www.w3.org/TR/REC-html40"
@@ -164,7 +164,7 @@ export async function getSiteMapXSL(localeId?: string): Promise<string> {
164
164
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
165
165
  <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
166
166
  <xsl:template match="/">
167
- <html lang="${defaultLocale.id}" xmlns="http://www.w3.org/1999/xhtml">
167
+ <html lang="${locale.id}" xmlns="http://www.w3.org/1999/xhtml">
168
168
  <head>
169
169
  <title>XML Sitemap</title>
170
170
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />