@websolutespa/bom-mixer-models 3.0.2 → 3.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.
- package/CHANGELOG.md +6 -0
- package/dist/exports/proxy.js +4 -1
- package/dist/exports/proxy.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/route/route.interceptor.ts +6 -1
package/CHANGELOG.md
CHANGED
package/dist/exports/proxy.js
CHANGED
|
@@ -88,7 +88,10 @@ async function routeInterceptor(request, next) {
|
|
|
88
88
|
try {
|
|
89
89
|
const redirectUrl = await routeAutoDetection(request, next);
|
|
90
90
|
if (redirectUrl) {
|
|
91
|
-
const
|
|
91
|
+
const resolvedUrl = resolveHref(redirectUrl);
|
|
92
|
+
const search = request.nextUrl.search;
|
|
93
|
+
const isTemporaryRedirect = isDevelopment || search;
|
|
94
|
+
const response$1 = NextResponse.redirect(resolvedUrl + search, { status: isTemporaryRedirect ? 303 : 301 });
|
|
92
95
|
response$1.cookies.set({
|
|
93
96
|
expires: new Date(Date.now() + 1440 * 60 * 1e3),
|
|
94
97
|
httpOnly: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","names":["request: NextRequest","defaultLocale?: string","defaultLocale","defaultMarket?: string","defaultMarket","markets: IMarket[]","routes: IRoute[]","next: NextFetchEvent","route: string | undefined","countries: string[]","x","market","route: IRoute | undefined","response","error: any","error","hrefBeforeRedirect: string | null"],"sources":["../../src/route/route.interceptor.ts"],"sourcesContent":["import { IMarket, IRoute, asEquatable, defaultLocale, defaultMarket, getHost, isDevelopment } from '@websolutespa/bom-core';\r\nimport { StoreStrategy, localApiGet, localApiPost, storeApiGet, storeApiPost, storeStrategy } from '@websolutespa/bom-mixer-store';\r\nimport { NextFetchEvent, NextRequest, NextResponse } from 'next/server';\r\nimport { getPublicUrl, resolveHref } from '../page/page';\r\nimport { resolveRoute } from './route';\r\n\r\nexport async function detectLocale(request: NextRequest, defaultLocale?: string) {\r\n const acceptLanguage = request.headers.get('accept-language')?.split(',')[0];\r\n const detectedLocale = request.cookies.get('NEXT_LOCALE')?.value || acceptLanguage || defaultLocale || process.env.DEFAULT_LOCALE;\r\n return detectedLocale as string;\r\n}\r\n\r\nexport async function detectCountry(request: NextRequest, defaultMarket?: string) {\r\n let ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip');\r\n if (ip) {\r\n ip = ip.split(',')[0];\r\n }\r\n const isValidIp = ip?.match(/^(\\d+?)\\.(\\d+?)\\.(\\d+?)\\.(\\d+?)$/);\r\n let detectedCountry = '';\r\n try {\r\n const token = process.env.IPINFO_TOKEN;\r\n if (token) {\r\n const url = isValidIp ?\r\n `https://api.ipinfo.io/lite/${ip}/country_code?token=${token}` :\r\n `https://api.ipinfo.io/lite/me/country_code?token=${token}`;\r\n const response = await fetch(url);\r\n if (response.ok) {\r\n const data = await response.text();\r\n detectedCountry = data.toLowerCase();\r\n }\r\n } else {\r\n const url = `https://geoip.websolute.it/Ip2Location/get_info.aspx?ipaddress=${isValidIp ? ip : ''}`;\r\n const response = await fetch(url);\r\n if (response.ok) {\r\n const xml = await response.text();\r\n detectedCountry = (\r\n ((xml.split('<CountryCode><![CDATA[')[1] || '').split(']]></CountryCode>')[0] || '')\r\n ).replace('-', '').toLowerCase();\r\n // console.log('detectedCountry', detectedCountry);\r\n }\r\n }\r\n // console.log('routeInterceptor.detectCountry', detectedCountry);\r\n return detectedCountry || defaultMarket || process.env.DEFAULT_MARKET;\r\n } catch (error) {\r\n console.log('routeInterceptor.detectCountry.error', error);\r\n }\r\n return (defaultMarket || process.env.DEFAULT_MARKET) as string;\r\n}\r\n\r\nasync function getMarkets() {\r\n const apiGet = storeStrategy === StoreStrategy.DecoratedApi ? localApiGet : storeApiGet;\r\n const markets: IMarket[] = await apiGet('/market?pagination=false');\r\n return markets;\r\n}\r\n\r\nasync function getRootRoutes() {\r\n const apiGet = storeStrategy === StoreStrategy.DecoratedApi ? localApiGet : storeApiGet;\r\n const routes: IRoute[] = await apiGet('/route?where[isRoot][equals]=true');\r\n return routes;\r\n}\r\n\r\nexport async function routeAutoDetection(request: NextRequest, next: NextFetchEvent): Promise<string | undefined> {\r\n let route: string | undefined;\r\n const url = request.nextUrl;\r\n if (url.pathname === '/') {\r\n const cookie = request.cookies.get('detectedRoute');\r\n if (cookie?.value) {\r\n return cookie.value;\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection', url.pathname);\r\n const rootRoutes = await getRootRoutes();\r\n // console.log('routeInterceptor.routeAutoDetection.rootRoutes', rootRoutes);\r\n const defaultRoute = rootRoutes.find(x => x.id === '/');\r\n // console.log('routeInterceptor.routeAutoDetection.defaultRoute', defaultRoute);\r\n if (defaultRoute) {\r\n return;\r\n }\r\n const markets = await getMarkets();\r\n // console.log('routeInterceptor.routeAutoDetection.markets', markets);\r\n const market = markets.find(x => x.isDefault) || markets.find(x => x.id === defaultMarket) || markets[0];\r\n // console.log('routeInterceptor.routeAutoDetection.market', market);\r\n const detectedCountry = await detectCountry(request, market.id);\r\n // console.log('routeInterceptor.routeAutoDetection.detectedCountry', detectedCountry);\r\n const detectedMarket = detectedCountry ? (\r\n markets.filter(x => Array.isArray(x.countries)).find(x => {\r\n const countries: string[] = (x.countries || []).map(x => typeof x === 'string' ? x : x.id as string);\r\n return countries.includes(detectedCountry);\r\n }) ||\r\n markets.find(x => !Array.isArray(x.countries))\r\n ) : undefined;\r\n // console.log('routeInterceptor.routeAutoDetection.detectedMarket', detectedMarket);\r\n let detectedMarketRoutes = rootRoutes.filter(x => x.market === detectedMarket?.id);\r\n if (detectedMarketRoutes.length === 0) {\r\n detectedMarketRoutes = rootRoutes.filter(x => x.market === market.id);\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection.detectedMarketRoutes', detectedMarketRoutes);\r\n const defaultMarketLocale = market.defaultLanguage ? (\r\n typeof market.defaultLanguage === 'string' ? market.defaultLanguage : market.defaultLanguage.id\r\n ) as string : defaultLocale;\r\n // console.log('routeInterceptor.routeAutoDetection.defaultMarketLocale', defaultMarketLocale);\r\n const detectedLocale = await detectLocale(request, defaultMarketLocale);\r\n // console.log('routeInterceptor.routeAutoDetection.detectedLocale', detectedLocale);\r\n const detectedLocaleRoutes = detectedMarketRoutes.filter(x => x.locale === detectedLocale);\r\n const detectedRoute =\r\n detectedLocaleRoutes.length > 0 ?\r\n detectedLocaleRoutes[0]! :\r\n detectedMarketRoutes.find(x => {\r\n const market = markets.find(m => m.id === x.market)!;\r\n const marketLocale = (market.defaultLanguage ? asEquatable(market.defaultLanguage as string) : defaultMarketLocale);\r\n return x.locale === marketLocale;\r\n })!;\r\n // console.log('routeInterceptor.routeAutoDetection.detectedRoute', detectedRoute);\r\n if (detectedRoute && detectedRoute.id !== url.pathname) {\r\n console.log('routeInterceptor.routeAutoDetection', detectedLocale, detectedCountry, detectedRoute.id);\r\n route = detectedRoute.id;\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection', locale, detectedCountry, rootRoutes);\r\n }\r\n return route;\r\n}\r\n\r\nexport async function routeInterceptor(request: NextRequest, next: NextFetchEvent) {\r\n let route: IRoute | undefined;\r\n let url = request.nextUrl;\r\n const hrefBeforeRedirect = getHrefBeforeRedirect(request);\r\n // console.log('routeInterceptor._live', request.nextUrl.searchParams.get('_live'));\r\n try {\r\n const redirectUrl = await routeAutoDetection(request, next);\r\n // console.log('routeInterceptor.routeAutoDetection', redirectUrl);\r\n if (redirectUrl) {\r\n const response = NextResponse.redirect(resolveHref(redirectUrl), isDevelopment ? 307 : 301);\r\n response.cookies.set({\r\n expires: new Date(Date.now() + 1 * 24 * 60 * 60 * 1000),\r\n httpOnly: true,\r\n name: 'detectedRoute',\r\n path: '/',\r\n sameSite: 'lax',\r\n secure: true,\r\n value: redirectUrl,\r\n });\r\n return response;\r\n }\r\n // console.log('routeInterceptor request.cookies', request.cookies);\r\n // console.log('routeInterceptor', url.pathname);\r\n if (storeStrategy === StoreStrategy.DecoratedApi) {\r\n route = await localApiPost('/route', { pathname: url.pathname, href: url.href, hrefBeforeRedirect });\r\n } else {\r\n route = await storeApiPost('/route', { pathname: url.pathname, href: url.href, hrefBeforeRedirect });\r\n }\r\n // console.log('route', route);\r\n if (!route) {\r\n console.log('routeInterceptor.route.notfound', url.pathname);\r\n return;\r\n }\r\n } catch (error: any) {\r\n if (error.status >= 300 && error.status < 400) {\r\n console.log('routeInterceptor.3xx', url.pathname, error.status, error.statusText);\r\n try {\r\n const { redirectUrl } = await error.json();\r\n // console.log('redirectUrl', redirectUrl);\r\n const response = NextResponse.redirect(redirectUrl, error.status);\r\n return response;\r\n } catch (error) {\r\n const publicUrl = getPublicUrl();\r\n console.log('routeInterceptor.3xx.error', `cannot parse response, redirecting to ${publicUrl}`);\r\n const response = NextResponse.redirect(publicUrl, 307);\r\n return response;\r\n }\r\n } else if (error.status === 410) {\r\n console.log('routeInterceptor.410', url.pathname, error.status, error.statusText);\r\n url = request.nextUrl.clone();\r\n url.pathname = `/${error.status}`;\r\n const response = NextResponse.rewrite(url, {\r\n status: error.status,\r\n statusText: error.statusText,\r\n request,\r\n });\r\n return response;\r\n } else if (error.status >= 400 && error.status < 500) {\r\n console.log('routeInterceptor.4xx', url.pathname, error.status, error.statusText);\r\n const response = NextResponse.next({\r\n status: error.status,\r\n statusText: error.statusText,\r\n request,\r\n });\r\n return response;\r\n }\r\n console.log('routeInterceptor.error', url.pathname, error.url, error.status, error.statusText || error);\r\n return;\r\n }\r\n // console.log('routeInterceptor.route.found', url.pathname, '->', route);\r\n url = request.nextUrl.clone();\r\n const resolvedPathname = resolveRoute(route);\r\n // console.log('resolvedPathname', resolvedPathname);\r\n url.pathname = resolvedPathname;\r\n // console.log('routeInterceptor.route', route.schema, route.page, route.market, route.locale);\r\n const response = NextResponse.rewrite(url);\r\n // const response = NextResponse.redirect(url);\r\n return response;\r\n}\r\n\r\nfunction getHrefBeforeRedirect(request: NextRequest): string | null {\r\n let hrefBeforeRedirect: string | null = null;\r\n const urlBeforeRedirect = request.nextUrl.clone();\r\n const host = getHost(request.headers);\r\n if (host) {\r\n urlBeforeRedirect.host = host;\r\n urlBeforeRedirect.port = host.split(':')[1] || '';\r\n hrefBeforeRedirect = urlBeforeRedirect.href;\r\n }\r\n return hrefBeforeRedirect;\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"proxy.js","names":["request: NextRequest","defaultLocale?: string","defaultLocale","defaultMarket?: string","defaultMarket","markets: IMarket[]","routes: IRoute[]","next: NextFetchEvent","route: string | undefined","countries: string[]","x","market","route: IRoute | undefined","response","error: any","error","hrefBeforeRedirect: string | null"],"sources":["../../src/route/route.interceptor.ts"],"sourcesContent":["import { IMarket, IRoute, asEquatable, defaultLocale, defaultMarket, getHost, isDevelopment } from '@websolutespa/bom-core';\r\nimport { StoreStrategy, localApiGet, localApiPost, storeApiGet, storeApiPost, storeStrategy } from '@websolutespa/bom-mixer-store';\r\nimport { NextFetchEvent, NextRequest, NextResponse } from 'next/server';\r\nimport { getPublicUrl, resolveHref } from '../page/page';\r\nimport { resolveRoute } from './route';\r\n\r\nexport async function detectLocale(request: NextRequest, defaultLocale?: string) {\r\n const acceptLanguage = request.headers.get('accept-language')?.split(',')[0];\r\n const detectedLocale = request.cookies.get('NEXT_LOCALE')?.value || acceptLanguage || defaultLocale || process.env.DEFAULT_LOCALE;\r\n return detectedLocale as string;\r\n}\r\n\r\nexport async function detectCountry(request: NextRequest, defaultMarket?: string) {\r\n let ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip');\r\n if (ip) {\r\n ip = ip.split(',')[0];\r\n }\r\n const isValidIp = ip?.match(/^(\\d+?)\\.(\\d+?)\\.(\\d+?)\\.(\\d+?)$/);\r\n let detectedCountry = '';\r\n try {\r\n const token = process.env.IPINFO_TOKEN;\r\n if (token) {\r\n const url = isValidIp ?\r\n `https://api.ipinfo.io/lite/${ip}/country_code?token=${token}` :\r\n `https://api.ipinfo.io/lite/me/country_code?token=${token}`;\r\n const response = await fetch(url);\r\n if (response.ok) {\r\n const data = await response.text();\r\n detectedCountry = data.toLowerCase();\r\n }\r\n } else {\r\n const url = `https://geoip.websolute.it/Ip2Location/get_info.aspx?ipaddress=${isValidIp ? ip : ''}`;\r\n const response = await fetch(url);\r\n if (response.ok) {\r\n const xml = await response.text();\r\n detectedCountry = (\r\n ((xml.split('<CountryCode><![CDATA[')[1] || '').split(']]></CountryCode>')[0] || '')\r\n ).replace('-', '').toLowerCase();\r\n // console.log('detectedCountry', detectedCountry);\r\n }\r\n }\r\n // console.log('routeInterceptor.detectCountry', detectedCountry);\r\n return detectedCountry || defaultMarket || process.env.DEFAULT_MARKET;\r\n } catch (error) {\r\n console.log('routeInterceptor.detectCountry.error', error);\r\n }\r\n return (defaultMarket || process.env.DEFAULT_MARKET) as string;\r\n}\r\n\r\nasync function getMarkets() {\r\n const apiGet = storeStrategy === StoreStrategy.DecoratedApi ? localApiGet : storeApiGet;\r\n const markets: IMarket[] = await apiGet('/market?pagination=false');\r\n return markets;\r\n}\r\n\r\nasync function getRootRoutes() {\r\n const apiGet = storeStrategy === StoreStrategy.DecoratedApi ? localApiGet : storeApiGet;\r\n const routes: IRoute[] = await apiGet('/route?where[isRoot][equals]=true');\r\n return routes;\r\n}\r\n\r\nexport async function routeAutoDetection(request: NextRequest, next: NextFetchEvent): Promise<string | undefined> {\r\n let route: string | undefined;\r\n const url = request.nextUrl;\r\n if (url.pathname === '/') {\r\n const cookie = request.cookies.get('detectedRoute');\r\n if (cookie?.value) {\r\n return cookie.value;\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection', url.pathname);\r\n const rootRoutes = await getRootRoutes();\r\n // console.log('routeInterceptor.routeAutoDetection.rootRoutes', rootRoutes);\r\n const defaultRoute = rootRoutes.find(x => x.id === '/');\r\n // console.log('routeInterceptor.routeAutoDetection.defaultRoute', defaultRoute);\r\n if (defaultRoute) {\r\n return;\r\n }\r\n const markets = await getMarkets();\r\n // console.log('routeInterceptor.routeAutoDetection.markets', markets);\r\n const market = markets.find(x => x.isDefault) || markets.find(x => x.id === defaultMarket) || markets[0];\r\n // console.log('routeInterceptor.routeAutoDetection.market', market);\r\n const detectedCountry = await detectCountry(request, market.id);\r\n // console.log('routeInterceptor.routeAutoDetection.detectedCountry', detectedCountry);\r\n const detectedMarket = detectedCountry ? (\r\n markets.filter(x => Array.isArray(x.countries)).find(x => {\r\n const countries: string[] = (x.countries || []).map(x => typeof x === 'string' ? x : x.id as string);\r\n return countries.includes(detectedCountry);\r\n }) ||\r\n markets.find(x => !Array.isArray(x.countries))\r\n ) : undefined;\r\n // console.log('routeInterceptor.routeAutoDetection.detectedMarket', detectedMarket);\r\n let detectedMarketRoutes = rootRoutes.filter(x => x.market === detectedMarket?.id);\r\n if (detectedMarketRoutes.length === 0) {\r\n detectedMarketRoutes = rootRoutes.filter(x => x.market === market.id);\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection.detectedMarketRoutes', detectedMarketRoutes);\r\n const defaultMarketLocale = market.defaultLanguage ? (\r\n typeof market.defaultLanguage === 'string' ? market.defaultLanguage : market.defaultLanguage.id\r\n ) as string : defaultLocale;\r\n // console.log('routeInterceptor.routeAutoDetection.defaultMarketLocale', defaultMarketLocale);\r\n const detectedLocale = await detectLocale(request, defaultMarketLocale);\r\n // console.log('routeInterceptor.routeAutoDetection.detectedLocale', detectedLocale);\r\n const detectedLocaleRoutes = detectedMarketRoutes.filter(x => x.locale === detectedLocale);\r\n const detectedRoute =\r\n detectedLocaleRoutes.length > 0 ?\r\n detectedLocaleRoutes[0]! :\r\n detectedMarketRoutes.find(x => {\r\n const market = markets.find(m => m.id === x.market)!;\r\n const marketLocale = (market.defaultLanguage ? asEquatable(market.defaultLanguage as string) : defaultMarketLocale);\r\n return x.locale === marketLocale;\r\n })!;\r\n // console.log('routeInterceptor.routeAutoDetection.detectedRoute', detectedRoute);\r\n if (detectedRoute && detectedRoute.id !== url.pathname) {\r\n console.log('routeInterceptor.routeAutoDetection', detectedLocale, detectedCountry, detectedRoute.id);\r\n route = detectedRoute.id;\r\n }\r\n // console.log('routeInterceptor.routeAutoDetection', locale, detectedCountry, rootRoutes);\r\n }\r\n return route;\r\n}\r\n\r\nexport async function routeInterceptor(request: NextRequest, next: NextFetchEvent) {\r\n let route: IRoute | undefined;\r\n let url = request.nextUrl;\r\n const hrefBeforeRedirect = getHrefBeforeRedirect(request);\r\n // console.log('routeInterceptor._live', request.nextUrl.searchParams.get('_live'));\r\n try {\r\n const redirectUrl = await routeAutoDetection(request, next);\r\n // console.log('routeInterceptor.routeAutoDetection', redirectUrl);\r\n if (redirectUrl) {\r\n // console.log('routeInterceptor', 'redirectUrl', redirectUrl);\r\n const resolvedUrl = resolveHref(redirectUrl);\r\n // console.log('routeInterceptor', 'resolvedUrl', resolvedUrl);\r\n const search = request.nextUrl.search;\r\n const isTemporaryRedirect = isDevelopment || search;\r\n const response = NextResponse.redirect(resolvedUrl + search, { status: isTemporaryRedirect ? 303 : 301 });\r\n response.cookies.set({\r\n expires: new Date(Date.now() + 1 * 24 * 60 * 60 * 1000),\r\n httpOnly: true,\r\n name: 'detectedRoute',\r\n path: '/',\r\n sameSite: 'lax',\r\n secure: true,\r\n value: redirectUrl,\r\n });\r\n return response;\r\n }\r\n // console.log('routeInterceptor request.cookies', request.cookies);\r\n // console.log('routeInterceptor', url.pathname);\r\n if (storeStrategy === StoreStrategy.DecoratedApi) {\r\n route = await localApiPost('/route', { pathname: url.pathname, href: url.href, hrefBeforeRedirect });\r\n } else {\r\n route = await storeApiPost('/route', { pathname: url.pathname, href: url.href, hrefBeforeRedirect });\r\n }\r\n // console.log('route', route);\r\n if (!route) {\r\n console.log('routeInterceptor.route.notfound', url.pathname);\r\n return;\r\n }\r\n } catch (error: any) {\r\n if (error.status >= 300 && error.status < 400) {\r\n console.log('routeInterceptor.3xx', url.pathname, error.status, error.statusText);\r\n try {\r\n const { redirectUrl } = await error.json();\r\n // console.log('redirectUrl', redirectUrl);\r\n const response = NextResponse.redirect(redirectUrl, error.status);\r\n return response;\r\n } catch (error) {\r\n const publicUrl = getPublicUrl();\r\n console.log('routeInterceptor.3xx.error', `cannot parse response, redirecting to ${publicUrl}`);\r\n const response = NextResponse.redirect(publicUrl, 307);\r\n return response;\r\n }\r\n } else if (error.status === 410) {\r\n console.log('routeInterceptor.410', url.pathname, error.status, error.statusText);\r\n url = request.nextUrl.clone();\r\n url.pathname = `/${error.status}`;\r\n const response = NextResponse.rewrite(url, {\r\n status: error.status,\r\n statusText: error.statusText,\r\n request,\r\n });\r\n return response;\r\n } else if (error.status >= 400 && error.status < 500) {\r\n console.log('routeInterceptor.4xx', url.pathname, error.status, error.statusText);\r\n const response = NextResponse.next({\r\n status: error.status,\r\n statusText: error.statusText,\r\n request,\r\n });\r\n return response;\r\n }\r\n console.log('routeInterceptor.error', url.pathname, error.url, error.status, error.statusText || error);\r\n return;\r\n }\r\n // console.log('routeInterceptor.route.found', url.pathname, '->', route);\r\n url = request.nextUrl.clone();\r\n const resolvedPathname = resolveRoute(route);\r\n // console.log('resolvedPathname', resolvedPathname);\r\n url.pathname = resolvedPathname;\r\n // console.log('routeInterceptor.route', route.schema, route.page, route.market, route.locale);\r\n const response = NextResponse.rewrite(url);\r\n // const response = NextResponse.redirect(url);\r\n return response;\r\n}\r\n\r\nfunction getHrefBeforeRedirect(request: NextRequest): string | null {\r\n let hrefBeforeRedirect: string | null = null;\r\n const urlBeforeRedirect = request.nextUrl.clone();\r\n const host = getHost(request.headers);\r\n if (host) {\r\n urlBeforeRedirect.host = host;\r\n urlBeforeRedirect.port = host.split(':')[1] || '';\r\n hrefBeforeRedirect = urlBeforeRedirect.href;\r\n }\r\n return hrefBeforeRedirect;\r\n}\r\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ type IApplication = IAppProps<IApplicationProps>;
|
|
|
24
24
|
|
|
25
25
|
//#endregion
|
|
26
26
|
//#region src/gtm/gtm.service.d.ts
|
|
27
|
-
[
|
|
27
|
+
[3, () => Record, sideEffect()];
|
|
28
28
|
declare function pushDataLayer(record: Record<string, any>): void;
|
|
29
29
|
//# sourceMappingURL=gtm.service.d.ts.map
|
|
30
30
|
//#endregion
|
package/package.json
CHANGED
|
@@ -128,7 +128,12 @@ export async function routeInterceptor(request: NextRequest, next: NextFetchEven
|
|
|
128
128
|
const redirectUrl = await routeAutoDetection(request, next);
|
|
129
129
|
// console.log('routeInterceptor.routeAutoDetection', redirectUrl);
|
|
130
130
|
if (redirectUrl) {
|
|
131
|
-
|
|
131
|
+
// console.log('routeInterceptor', 'redirectUrl', redirectUrl);
|
|
132
|
+
const resolvedUrl = resolveHref(redirectUrl);
|
|
133
|
+
// console.log('routeInterceptor', 'resolvedUrl', resolvedUrl);
|
|
134
|
+
const search = request.nextUrl.search;
|
|
135
|
+
const isTemporaryRedirect = isDevelopment || search;
|
|
136
|
+
const response = NextResponse.redirect(resolvedUrl + search, { status: isTemporaryRedirect ? 303 : 301 });
|
|
132
137
|
response.cookies.set({
|
|
133
138
|
expires: new Date(Date.now() + 1 * 24 * 60 * 60 * 1000),
|
|
134
139
|
httpOnly: true,
|