@remkoj/optimizely-cms-nextjs 6.0.0-pre8 → 6.0.0-rc.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.
- package/LICENSE +12 -12
- package/README.md +5 -1
- package/dist/client.d.ts +6 -1
- package/dist/client.js +29 -3
- package/dist/client.js.map +1 -1
- package/dist/cms-page/_base.js +1 -10
- package/dist/cms-page/_base.js.map +1 -1
- package/dist/cms-page/_getInfoByPath.d.ts +1 -1
- package/dist/cms-page/_getInfoByPath.js +4 -4
- package/dist/cms-page/_getInfoByPath.js.map +1 -1
- package/dist/cms-page/_globals.d.ts +1 -0
- package/dist/cms-page/_globals.js +2 -0
- package/dist/cms-page/_globals.js.map +1 -0
- package/dist/cms-page/_loadContentByPath.d.ts +1 -1
- package/dist/cms-page/_loadContentByPath.js +2 -1
- package/dist/cms-page/_loadContentByPath.js.map +1 -1
- package/dist/cms-page/data.d.ts +3 -2
- package/dist/cms-page/middleware.d.ts +4 -2
- package/dist/cms-page/middleware.js +25 -7
- package/dist/cms-page/middleware.js.map +1 -1
- package/dist/cms-page/page.d.ts +13 -3
- package/dist/cms-page/page.js +57 -84
- package/dist/cms-page/page.js.map +1 -1
- package/dist/ope/load-content.d.ts +21 -0
- package/dist/ope/load-content.js +69 -0
- package/dist/ope/load-content.js.map +1 -0
- package/dist/ope/middleware.js +1 -1
- package/dist/ope/middleware.js.map +1 -1
- package/dist/ope/page.js +25 -46
- package/dist/ope/page.js.map +1 -1
- package/dist/ope/tools.d.ts +1 -1
- package/dist/ope/tools.js +7 -7
- package/dist/ope/tools.js.map +1 -1
- package/dist/ope/types.d.ts +7 -5
- package/dist/publish/index.js +1 -1
- package/dist/publish/index.js.map +1 -1
- package/dist/types.d.ts +3 -2
- package/package.json +19 -19
- package/dist/ope/data.d.ts +0 -2
- package/dist/ope/data.js +0 -28
- package/dist/ope/data.js.map +0 -1
package/LICENSE
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
Copyright 2024 Remko Jantzen
|
|
2
|
-
|
|
3
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
you may not use this file except in compliance with the License.
|
|
5
|
-
You may obtain a copy of the License at
|
|
6
|
-
|
|
7
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
|
|
9
|
-
Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
See the License for the specific language governing permissions and
|
|
1
|
+
Copyright 2024 Remko Jantzen
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
13
|
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
# Optimizely SaaS CMS - Next.js Integration
|
|
2
|
+
|
|
3
|
+
> [!WARNING]
|
|
4
|
+
> There'll be an update of Optimizely SaaS CMS that is incompatible with all SDK versions prior to 5.1.6. If you don't upgrade, you will see empty pages (main website) and "Component not found" messages (preview).
|
|
5
|
+
|
|
2
6
|
[](./LICENSE)
|
|
3
7
|
|
|
4
8
|
> [!TIP]
|
|
@@ -76,4 +80,4 @@ The package provides the following enhancements for Next.js middleware:
|
|
|
76
80
|
| withEditFallback | `@remkoj/optimizely-cms-nextjs/preview` | Rewrite incoming Optimizely CMS 12 preview / on-page-edit URLs to Optimizely SaaS CMS preview URLs |
|
|
77
81
|
| withLanguagePrefix | `@remkoj/optimizely-cms-nextjs/page` | Handle the redirect of the homepage `/` to the locale that best matches the incoming request, such as `/en`. The locales and their URLs are taken from the second parameter - the ChannelDefinition.
|
|
78
82
|
|
|
79
|
-
If you use both wrappers, the `withEditFallback` wrapper must wrap the `withLanguagePrefix` wrapper, to ensure that the edit mode URL is rewritten before the language prefix is applied.
|
|
83
|
+
If you use both wrappers, the `withEditFallback` wrapper must wrap the `withLanguagePrefix` wrapper, to ensure that the edit mode URL is rewritten before the language prefix is applied.
|
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import 'server-only';
|
|
|
2
2
|
import { type IOptiGraphClient, type OptimizelyGraphConfig } from '@remkoj/optimizely-graph-client';
|
|
3
3
|
/**
|
|
4
4
|
* Create a new client instance. This is a direct wrapper for the `createClient` function
|
|
5
|
-
* exported from `@remkoj/optimizely-graph-client`.
|
|
5
|
+
* exported from `@remkoj/optimizely-graph-client`. It creates the instance with the
|
|
6
|
+
* recommended configuration for published content in a Next.JS frontend.
|
|
6
7
|
*
|
|
7
8
|
* @returns The newly created GraphQL Client
|
|
8
9
|
*/
|
|
@@ -12,6 +13,10 @@ export declare function createClient(): IOptiGraphClient;
|
|
|
12
13
|
* wraps the `createClient` function from `@remkoj/optimizely-graph-client` and applies some
|
|
13
14
|
* configuration defaults.
|
|
14
15
|
*
|
|
16
|
+
* It creates the instance with the recommended configuration for published content in a Next.JS
|
|
17
|
+
* frontend. When the token is a non-empty string, the configuration applied is intended to access
|
|
18
|
+
* non-published content in a Next.JS frontend, for example in the preview endpoint of Optimizely CMS.
|
|
19
|
+
*
|
|
15
20
|
* @returns The newly created GraphQL Client
|
|
16
21
|
*/
|
|
17
22
|
export declare function createAuthorizedClient(token?: string, config?: OptimizelyGraphConfig): IOptiGraphClient;
|
package/dist/client.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
2
|
import { createClient as createBaseClient, AuthMode } from '@remkoj/optimizely-graph-client';
|
|
3
|
+
import { isNonEmptyString } from '@remkoj/optimizely-cms-react/utils';
|
|
4
|
+
const AuthModeValues = Object.getOwnPropertyNames(AuthMode).reduce((a, b) => {
|
|
5
|
+
//@ts-ignore
|
|
6
|
+
a.push(AuthMode[b]);
|
|
7
|
+
return a;
|
|
8
|
+
}, []);
|
|
3
9
|
/**
|
|
4
10
|
* Create a new client instance. This is a direct wrapper for the `createClient` function
|
|
5
|
-
* exported from `@remkoj/optimizely-graph-client`.
|
|
11
|
+
* exported from `@remkoj/optimizely-graph-client`. It creates the instance with the
|
|
12
|
+
* recommended configuration for published content in a Next.JS frontend.
|
|
6
13
|
*
|
|
7
14
|
* @returns The newly created GraphQL Client
|
|
8
15
|
*/
|
|
@@ -14,18 +21,37 @@ export function createClient() {
|
|
|
14
21
|
* wraps the `createClient` function from `@remkoj/optimizely-graph-client` and applies some
|
|
15
22
|
* configuration defaults.
|
|
16
23
|
*
|
|
24
|
+
* It creates the instance with the recommended configuration for published content in a Next.JS
|
|
25
|
+
* frontend. When the token is a non-empty string, the configuration applied is intended to access
|
|
26
|
+
* non-published content in a Next.JS frontend, for example in the preview endpoint of Optimizely CMS.
|
|
27
|
+
*
|
|
17
28
|
* @returns The newly created GraphQL Client
|
|
18
29
|
*/
|
|
19
30
|
export function createAuthorizedClient(token, config) {
|
|
20
|
-
|
|
31
|
+
// Check the token
|
|
32
|
+
const isPotentialValidToken = isNonEmptyString(token);
|
|
33
|
+
// Create the client, but keep the cache disabled if we've got a non-empty string as token
|
|
34
|
+
const client = createBaseClient(config, undefined, {
|
|
35
|
+
nextJsFetchDirectives: true,
|
|
36
|
+
cache: !isPotentialValidToken,
|
|
37
|
+
queryCache: !isPotentialValidToken,
|
|
38
|
+
});
|
|
21
39
|
if (client.debug)
|
|
22
40
|
console.log('⚪ [ContentGraph Client] Created new Optimizely Graph client');
|
|
23
41
|
// Apply token if needed
|
|
24
|
-
if (
|
|
42
|
+
if (isPotentialValidToken) {
|
|
25
43
|
if (token == client.siteInfo.publishToken) {
|
|
26
44
|
console.warn(`🔐 [ContentGraph Client] Allowed authenticated access by publish token, switching to HMAC`);
|
|
27
45
|
client.updateAuthentication(AuthMode.HMAC);
|
|
28
46
|
}
|
|
47
|
+
else if (AuthModeValues.includes(token)) {
|
|
48
|
+
if (client.isDebugOrDevelopment() && (token === AuthMode.HMAC || token === AuthMode.Basic)) {
|
|
49
|
+
console.warn(`🔐 [ContentGraph Client] Allowing authenticated access by using a mode as token in development or debug`);
|
|
50
|
+
client.updateAuthentication(token);
|
|
51
|
+
}
|
|
52
|
+
else
|
|
53
|
+
console.warn(`🔐 [ContentGraph Client] Blocked authenticated access by using a mode as token`);
|
|
54
|
+
}
|
|
29
55
|
else {
|
|
30
56
|
client.updateAuthentication(token);
|
|
31
57
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,QAAQ,EAAqD,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,QAAQ,EAAqD,MAAM,iCAAiC,CAAA;AAC/I,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AAErE,MAAM,cAAc,GAAG,MAAM,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAW,CAAC,CAAW,EAAE,CAAS,EAAE,EAAE;IACtG,YAAY;IACZ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACpB,OAAO,CAAC,CAAA;AACV,CAAC,EAAE,EAAc,CAAC,CAAA;AAElB;;;;;;GAMG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,sBAAsB,EAAE,CAAA;AACjC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAc,EAAE,MAA8B;IACnF,kBAAkB;IAClB,MAAM,qBAAqB,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IAErD,0FAA0F;IAC1F,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE;QACjD,qBAAqB,EAAE,IAAI;QAC3B,KAAK,EAAE,CAAC,qBAAqB;QAC7B,UAAU,EAAE,CAAC,qBAAqB;KACnC,CAAC,CAAA;IACF,IAAI,MAAM,CAAC,KAAK;QACd,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAA;IAE5E,wBAAwB;IACxB,IAAI,qBAAqB,EAAE,CAAC;QAC1B,IAAI,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,2FAA2F,CAAC,CAAA;YACzG,MAAM,CAAC,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5C,CAAC;aAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,IAAI,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,IAAI,IAAI,KAAK,KAAK,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3F,OAAO,CAAC,IAAI,CAAC,yGAAyG,CAAC,CAAA;gBACvH,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAA;YACpC,CAAC;;gBACC,OAAO,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAA;QAClG,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAA;QACpC,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,kEAAkE,MAAM,CAAC,eAAe,EAAE,CAAC,CAAA;YACxG,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAA;QAC5E,CAAC;QACD,MAAM,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,KAAK,CAAC,CAAA;IACnF,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,sBAAsB,CAAA;AAE/D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAA;AAE3C,eAAe,YAAY,CAAA"}
|
package/dist/cms-page/_base.js
CHANGED
|
@@ -11,16 +11,7 @@ export function getChannelId(client, channel) {
|
|
|
11
11
|
return channel;
|
|
12
12
|
return client.currentOptiCmsSchema == OptiCmsSchema.CMS12
|
|
13
13
|
? channel.id
|
|
14
|
-
:
|
|
15
|
-
}
|
|
16
|
-
function getPrimaryURL(chnl) {
|
|
17
|
-
const dd = chnl.domains.filter((x) => x.isPrimary).at(0) ?? chnl.domains.at(0);
|
|
18
|
-
if (!dd)
|
|
19
|
-
return chnl.getPrimaryDomain();
|
|
20
|
-
const s = dd.name.startsWith('localhost') || dd.name.indexOf('.local') > 0
|
|
21
|
-
? 'http:'
|
|
22
|
-
: 'https:';
|
|
23
|
-
return new URL(`${s}//${dd.name}`);
|
|
14
|
+
: channel.getPrimaryDomain().origin;
|
|
24
15
|
}
|
|
25
16
|
function isString(toTest) {
|
|
26
17
|
return typeof toTest === 'string';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_base.js","sourceRoot":"","sources":["../../src/cms-page/_base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAyB,MAAM,wCAAwC,CAAA;AAK7F,MAAM,CAAN,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,4BAAW,CAAA;IACX,oCAAmB,CAAA;AACrB,CAAC,EAHW,aAAa,KAAb,aAAa,QAGxB;AAUD,MAAM,UAAU,YAAY,CAAC,MAAwB,EAAE,OAAoC;IACzF,IAAI,CAAC,OAAO;QACV,OAAO,SAAS,CAAA;IAClB,IAAI,QAAQ,CAAC,OAAO,CAAC;QACnB,OAAO,OAAO,CAAA;IAChB,OAAO,MAAM,CAAC,oBAAoB,IAAI,aAAa,CAAC,KAAK;QACvD,CAAC,CAAC,OAAO,CAAC,EAAE;QACZ,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"_base.js","sourceRoot":"","sources":["../../src/cms-page/_base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAyB,MAAM,wCAAwC,CAAA;AAK7F,MAAM,CAAN,IAAY,aAGX;AAHD,WAAY,aAAa;IACvB,4BAAW,CAAA;IACX,oCAAmB,CAAA;AACrB,CAAC,EAHW,aAAa,KAAb,aAAa,QAGxB;AAUD,MAAM,UAAU,YAAY,CAAC,MAAwB,EAAE,OAAoC;IACzF,IAAI,CAAC,OAAO;QACV,OAAO,SAAS,CAAA;IAClB,IAAI,QAAQ,CAAC,OAAO,CAAC;QACnB,OAAO,OAAO,CAAA;IAChB,OAAO,MAAM,CAAC,oBAAoB,IAAI,aAAa,CAAC,KAAK;QACvD,CAAC,CAAC,OAAO,CAAC,EAAE;QACZ,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAA;AACvC,CAAC;AAED,SAAS,QAAQ,CAAC,MAAW;IAC3B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC;AACpC,CAAC"}
|
|
@@ -2,4 +2,4 @@ import { type IOptiGraphClient } from "@remkoj/optimizely-graph-client/client";
|
|
|
2
2
|
import { type IRouteResolver } from "@remkoj/optimizely-graph-client/router";
|
|
3
3
|
import { type ChannelDefinition } from "@remkoj/optimizely-graph-client/channels";
|
|
4
4
|
import { type LookupResponse } from "./_base.js";
|
|
5
|
-
export declare function getInfoByPath(client: IOptiGraphClient, routerFactory: (client?: IOptiGraphClient) => IRouteResolver, requestPath: string, channel?: ChannelDefinition | string): Promise<LookupResponse | undefined>;
|
|
5
|
+
export declare function getInfoByPath(client: IOptiGraphClient, routerFactory: (client?: IOptiGraphClient) => IRouteResolver, requestPath: string, channel?: ChannelDefinition | string, variation?: string): Promise<LookupResponse | undefined>;
|
|
@@ -3,12 +3,10 @@ import { ifChannelDefinition } from "@remkoj/optimizely-graph-client/channels";
|
|
|
3
3
|
import { getChannelId } from "./_base.js";
|
|
4
4
|
import { localeToGraphLocale } from "./utils.js";
|
|
5
5
|
// Helper function to obtain the info by path
|
|
6
|
-
export async function getInfoByPath(client, routerFactory, requestPath, channel) {
|
|
7
|
-
if (client.debug)
|
|
8
|
-
console.log(`⚪ [CmsPage.getInfoByPath] Loading content for path "${requestPath}" using RouteResolver`);
|
|
6
|
+
export async function getInfoByPath(client, routerFactory, requestPath, channel, variation) {
|
|
9
7
|
const channelId = getChannelId(client, channel);
|
|
10
8
|
const router = routerFactory(client);
|
|
11
|
-
const route = await router.getContentInfoByPath(requestPath, channelId);
|
|
9
|
+
const route = await router.getContentInfoByPath(requestPath, channelId, variation);
|
|
12
10
|
if (!route) {
|
|
13
11
|
if (client.debug)
|
|
14
12
|
console.warn(`🟠 [CmsPage.getInfoByPath] The RouteResolver was unable to resolve the route information for "${requestPath}"`);
|
|
@@ -17,6 +15,8 @@ export async function getInfoByPath(client, routerFactory, requestPath, channel)
|
|
|
17
15
|
const contentLink = router.routeToContentLink(route);
|
|
18
16
|
const contentType = route.contentType;
|
|
19
17
|
const graphLocale = localeToGraphLocale(route.locale, ifChannelDefinition(channel));
|
|
18
|
+
if (client.debug)
|
|
19
|
+
console.log(`⚪ [CmsPage.getInfoByPath] Resolved path "${requestPath}"${variation ? ` in variation ${variation}` : ""} to content ${JSON.stringify(contentLink)} of type ${contentType.join('/')} using RouteResolver`);
|
|
20
20
|
return [route, contentLink, contentType, graphLocale, null];
|
|
21
21
|
}
|
|
22
22
|
//# sourceMappingURL=_getInfoByPath.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_getInfoByPath.js","sourceRoot":"","sources":["../../src/cms-page/_getInfoByPath.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAIZ,OAAO,EAA0B,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAEvG,OAAO,EAAE,YAAY,EAAuB,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,6CAA6C;AAC7C,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAwB,EACxB,aAA4D,EAC5D,WAAmB,EACnB,OAAoC
|
|
1
|
+
{"version":3,"file":"_getInfoByPath.js","sourceRoot":"","sources":["../../src/cms-page/_getInfoByPath.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAIZ,OAAO,EAA0B,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAEvG,OAAO,EAAE,YAAY,EAAuB,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,6CAA6C;AAC7C,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAwB,EACxB,aAA4D,EAC5D,WAAmB,EACnB,OAAoC,EACpC,SAAkB;IAElB,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;IACpC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;IAClF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,MAAM,CAAC,KAAK;YACd,OAAO,CAAC,IAAI,CACV,iGAAiG,WAAW,GAAG,CAChH,CAAA;QACH,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAA;IACpD,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAA;IACrC,MAAM,WAAW,GAAG,mBAAmB,CAAC,KAAK,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAA;IACnF,IAAI,MAAM,CAAC,KAAK;QACd,OAAO,CAAC,GAAG,CACT,4CAA4C,WAAW,IAAI,SAAS,CAAC,CAAC,CAAC,iBAAiB,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,YAAY,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,sBAAsB,CAC1M,CAAA;IACH,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,CAAmB,CAAA;AAC/E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_globals.js","sourceRoot":"","sources":["../../src/cms-page/_globals.ts"],"names":[],"mappings":""}
|
|
@@ -2,4 +2,4 @@ import { type IOptiGraphClient } from "@remkoj/optimizely-graph-client";
|
|
|
2
2
|
import { type ChannelDefinition } from "@remkoj/optimizely-graph-client/channels";
|
|
3
3
|
import { type GetContentByPathMethod } from './data.js';
|
|
4
4
|
import { SystemLocales, type LookupResponse } from "./_base.js";
|
|
5
|
-
export declare function loadContentByPath<LocaleEnum = SystemLocales>(client: IOptiGraphClient, getContentByPath: GetContentByPathMethod<LocaleEnum>, requestPath: string, channel?: ChannelDefinition | string, locale?: LocaleEnum | LocaleEnum[]): Promise<LookupResponse | undefined | null>;
|
|
5
|
+
export declare function loadContentByPath<LocaleEnum = SystemLocales>(client: IOptiGraphClient, getContentByPath: GetContentByPathMethod<LocaleEnum>, requestPath: string, channel?: ChannelDefinition | string, locale?: LocaleEnum | LocaleEnum[], variation?: string): Promise<LookupResponse | undefined | null>;
|
|
@@ -4,7 +4,7 @@ import { normalizeContentLinkWithLocale, isContentLinkWithSetLocale } from '@rem
|
|
|
4
4
|
import { Utils } from '@remkoj/optimizely-cms-react/rsc';
|
|
5
5
|
import { getChannelId } from "./_base.js";
|
|
6
6
|
import { localeToGraphLocale } from './utils.js';
|
|
7
|
-
export async function loadContentByPath(client, getContentByPath, requestPath, channel, locale) {
|
|
7
|
+
export async function loadContentByPath(client, getContentByPath, requestPath, channel, locale, variation) {
|
|
8
8
|
if (client.debug)
|
|
9
9
|
console.log(`⚪ [CmsPage.loadContentByPath] Loading content for path "${requestPath}" using getContentByPath method`);
|
|
10
10
|
const channelId = getChannelId(client, channel);
|
|
@@ -18,6 +18,7 @@ export async function loadContentByPath(client, getContentByPath, requestPath, c
|
|
|
18
18
|
path: pathForRequest,
|
|
19
19
|
siteId: channelId,
|
|
20
20
|
locale,
|
|
21
|
+
variation: variation ? { include: "SOME", value: [variation] } : undefined
|
|
21
22
|
};
|
|
22
23
|
if (client.isPreviewEnabled())
|
|
23
24
|
requestVars.changeset = client?.getChangeset();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_loadContentByPath.js","sourceRoot":"","sources":["../../src/cms-page/_loadContentByPath.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAGZ,OAAO,EAA0B,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AACvG,OAAO,EAAE,8BAA8B,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAEnH,OAAO,EAAE,KAAK,EAAE,MAAM,kCAAkC,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAsC,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAEhD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAwB,EACxB,gBAAoD,EACpD,WAAmB,EACnB,OAAoC,EACpC,MAAkC;
|
|
1
|
+
{"version":3,"file":"_loadContentByPath.js","sourceRoot":"","sources":["../../src/cms-page/_loadContentByPath.ts"],"names":[],"mappings":"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"}
|
package/dist/cms-page/data.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { IOptiGraphClient, VariationInput } from "@remkoj/optimizely-graph-client";
|
|
2
|
+
export type { VariationInput } from "@remkoj/optimizely-graph-client";
|
|
2
3
|
export type GetContentByPathVariables<LocaleType = string> = {
|
|
3
4
|
path: string | string[];
|
|
4
5
|
locale?: Array<LocaleType> | LocaleType;
|
|
5
6
|
siteId?: string;
|
|
6
7
|
changeset?: string | null;
|
|
8
|
+
variation?: VariationInput | null;
|
|
7
9
|
};
|
|
8
10
|
type MayBe<T> = T extends Array<infer R> ? Array<R | null> | null : T | null;
|
|
9
11
|
export type GetContentByPathResponse = {
|
|
@@ -32,4 +34,3 @@ export type GetMetaDataByPathResponse = {
|
|
|
32
34
|
};
|
|
33
35
|
export type GetContentByPathMethod<LocaleType = string> = (client: IOptiGraphClient, variables: GetContentByPathVariables<LocaleType>) => Promise<GetContentByPathResponse>;
|
|
34
36
|
export type GetMetaDataByPathMethod<LocaleType = string> = (client: IOptiGraphClient, variables: GetContentByPathVariables<LocaleType>) => Promise<GetMetaDataByPathResponse>;
|
|
35
|
-
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
|
-
import { type
|
|
2
|
+
import { type NextProxy } from "next/server.js";
|
|
3
3
|
import { type ChannelDefinition } from "@remkoj/optimizely-graph-client";
|
|
4
4
|
/**
|
|
5
5
|
* Wrap the provided middleware with enforcement of the language code as the first
|
|
@@ -7,6 +7,8 @@ import { type ChannelDefinition } from "@remkoj/optimizely-graph-client";
|
|
|
7
7
|
*
|
|
8
8
|
* @param next The Next.JS Middleware to wrap, will be invoked if there's no redirect needed
|
|
9
9
|
* @param channel The Optimizely CMS Application definition
|
|
10
|
+
* @param debug When set to debug, redirects will be temporary (302) and information will be
|
|
11
|
+
* logged. If omitted, it will determine debug mode based upon the NODE_ENV value.
|
|
10
12
|
* @returns The newly constructed Next.JS Middleware
|
|
11
13
|
*/
|
|
12
|
-
export declare function withLanguagePrefix<T extends
|
|
14
|
+
export declare function withLanguagePrefix<T extends NextProxy>(next: T, channel: ChannelDefinition, enableDebug?: boolean): T;
|
|
@@ -8,9 +8,12 @@ import Negotiator from 'negotiator';
|
|
|
8
8
|
*
|
|
9
9
|
* @param next The Next.JS Middleware to wrap, will be invoked if there's no redirect needed
|
|
10
10
|
* @param channel The Optimizely CMS Application definition
|
|
11
|
+
* @param debug When set to debug, redirects will be temporary (302) and information will be
|
|
12
|
+
* logged. If omitted, it will determine debug mode based upon the NODE_ENV value.
|
|
11
13
|
* @returns The newly constructed Next.JS Middleware
|
|
12
14
|
*/
|
|
13
|
-
export function withLanguagePrefix(next, channel) {
|
|
15
|
+
export function withLanguagePrefix(next, channel, enableDebug) {
|
|
16
|
+
const debug = enableDebug === undefined ? process.env.NODE_ENV === 'development' : enableDebug;
|
|
14
17
|
if (!channel)
|
|
15
18
|
throw new Error("The language prefix handling requires a CMS Channel Definition");
|
|
16
19
|
const defaultLocale = channel.defaultLocale;
|
|
@@ -24,19 +27,34 @@ export function withLanguagePrefix(next, channel) {
|
|
|
24
27
|
}
|
|
25
28
|
const newMiddleware = (request, ...params) => {
|
|
26
29
|
const pathname = request.nextUrl.pathname;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
// Only process non internal routes
|
|
31
|
+
if (pathname.startsWith("/_") || pathname.startsWith("/."))
|
|
32
|
+
return next(request, ...params);
|
|
33
|
+
// Get the locale slug from the URL
|
|
34
|
+
const pathSlugs = pathname.split('/').filter(x => x);
|
|
35
|
+
const localeSlug = pathSlugs.length >= 1 && slugs.includes(pathSlugs.at(0) ?? '-') ? pathSlugs.at(0) : undefined;
|
|
36
|
+
if (!localeSlug) {
|
|
37
|
+
// We don't have a locale, so we're going to redirect to the best matching
|
|
38
|
+
// locale.
|
|
30
39
|
const locale = getLocale(request);
|
|
31
40
|
const slug = channel.resolveSlug(locale);
|
|
32
|
-
if (
|
|
33
|
-
console.log(`💬 [Middleware] Detected locale missing in ${pathname}, redirecting to /${slug}${pathname}`);
|
|
41
|
+
if (debug)
|
|
42
|
+
console.log(`💬 [Language Prefix Middleware] Detected locale missing in ${pathname}, redirecting to /${slug}${pathname}`);
|
|
34
43
|
const newUrl = request.nextUrl.clone();
|
|
35
44
|
newUrl.pathname = `/${slug}${pathname}`;
|
|
36
45
|
return NextResponse.redirect(newUrl, {
|
|
37
|
-
status:
|
|
46
|
+
status: debug ? 302 : 301
|
|
38
47
|
});
|
|
39
48
|
}
|
|
49
|
+
else {
|
|
50
|
+
// We have a locale, so we're going to make it available to the application
|
|
51
|
+
// using request headers.
|
|
52
|
+
const locale = channel.slugToLocale(localeSlug);
|
|
53
|
+
request.headers.append("x-app-locale", locale ?? channel.defaultLocale);
|
|
54
|
+
request.headers.append("x-app-locale-slug", localeSlug);
|
|
55
|
+
if (debug)
|
|
56
|
+
console.log(`💬 [Language Prefix Middleware] Detected locale ${locale}`);
|
|
57
|
+
}
|
|
40
58
|
return next(request, ...params);
|
|
41
59
|
};
|
|
42
60
|
return newMiddleware;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/cms-page/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AACpB,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/cms-page/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/cms-page/page.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export type OptiCmsNextJsPage<TParams extends Record<string, string | Array<stri
|
|
|
32
32
|
* @param resolving The metadata that is currently resolving
|
|
33
33
|
* @returns Updated metadat
|
|
34
34
|
*/
|
|
35
|
-
generateMetadata: (props: DefaultCmsPageProps<TParams, TSearchParams>, resolving: ResolvingMetadata) => Promise<Metadata
|
|
35
|
+
generateMetadata: (props: DefaultCmsPageProps<TParams, TSearchParams>, resolving: ResolvingMetadata) => Promise<Metadata> | Metadata;
|
|
36
36
|
/**
|
|
37
37
|
* The actual component that performs the page rendering
|
|
38
38
|
*
|
|
@@ -55,7 +55,7 @@ export type CreatePageOptions<LocaleEnum = SystemLocales, TParams extends Record
|
|
|
55
55
|
* draftMode in configuring the client
|
|
56
56
|
* @returns The client instance
|
|
57
57
|
*/
|
|
58
|
-
client: (token?: string, scope?: 'request' | 'metadata') => IOptiGraphClient | Promise<IOptiGraphClient
|
|
58
|
+
client: ((token?: string, scope?: 'request' | 'metadata') => IOptiGraphClient) | ((token?: string, scope?: 'request' | 'metadata') => Promise<IOptiGraphClient>);
|
|
59
59
|
/**
|
|
60
60
|
* The channel information used to resolve locales, domains and more.
|
|
61
61
|
*
|
|
@@ -84,7 +84,17 @@ export type CreatePageOptions<LocaleEnum = SystemLocales, TParams extends Record
|
|
|
84
84
|
* @return The path to be retrieved from Router or getContentByPath
|
|
85
85
|
* function
|
|
86
86
|
*/
|
|
87
|
-
propsToCmsPath: (props: DefaultCmsPageProps<TParams, TSearchParams
|
|
87
|
+
propsToCmsPath: (props: DefaultCmsPageProps<TParams, TSearchParams>, channel?: ChannelDefinition) => Promise<string | null>;
|
|
88
|
+
/**
|
|
89
|
+
* Take the props received by the CmsPage from Next.JS and tranform those
|
|
90
|
+
* into a the page variant used by the CMS.
|
|
91
|
+
*
|
|
92
|
+
* @param props The Properties (slugs & search params) received
|
|
93
|
+
* by Next.JS
|
|
94
|
+
* @return The path to be retrieved from Router or getContentByPath
|
|
95
|
+
* function
|
|
96
|
+
*/
|
|
97
|
+
propsToVariant: (props: DefaultCmsPageProps<TParams, TSearchParams>, channel?: ChannelDefinition) => Promise<string | null | undefined>;
|
|
88
98
|
/**
|
|
89
99
|
* Take the route from the Routing Service and transform that to the route
|
|
90
100
|
* params used by Next.JS. The default implementation assumes that the CMS
|
package/dist/cms-page/page.js
CHANGED
|
@@ -1,28 +1,50 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import 'server-only';
|
|
3
|
-
import deepmerge from 'deepmerge';
|
|
4
3
|
import { notFound } from 'next/navigation.js';
|
|
4
|
+
import { cache } from 'react';
|
|
5
5
|
// GraphQL Client & Services
|
|
6
6
|
import { RouteResolver, } from '@remkoj/optimizely-graph-client/router';
|
|
7
7
|
import { ifChannelDefinition, } from '@remkoj/optimizely-graph-client/channels';
|
|
8
8
|
// React Support
|
|
9
|
-
import { CmsContent, ServerContext,
|
|
9
|
+
import { CmsContent, ServerContext, isNonEmptyString, } from '@remkoj/optimizely-cms-react/rsc';
|
|
10
10
|
// Within package
|
|
11
11
|
import { MetaDataResolver } from '../metadata.js';
|
|
12
12
|
import { urlToPath } from './utils.js';
|
|
13
13
|
import { createClient } from '../client.js';
|
|
14
14
|
import { getChannelId } from './_base.js';
|
|
15
|
-
import { loadContentByPath } from './_loadContentByPath.js';
|
|
16
|
-
import { getInfoByPath } from './_getInfoByPath.js';
|
|
15
|
+
import { loadContentByPath as loadContentByPathBase } from './_loadContentByPath.js';
|
|
16
|
+
import { getInfoByPath as getInfoByPathBase } from './_getInfoByPath.js';
|
|
17
|
+
const getInfoByPath = cache(getInfoByPathBase);
|
|
18
|
+
const loadContentByPath = cache(loadContentByPathBase);
|
|
17
19
|
export { SystemLocales } from './_base.js';
|
|
18
20
|
const CreatePageOptionDefaults = {
|
|
19
21
|
client: createClient,
|
|
20
22
|
routerFactory: (client) => new RouteResolver(client),
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
async propsToCmsPath(props) {
|
|
24
|
+
const params = await props.params; // Read the parameters
|
|
25
|
+
const slugs = [params.lang, ...(params.path ?? [])] // Build the full set of slugs for the path
|
|
26
|
+
.filter(isNonEmptyString) // Remove empty values
|
|
27
|
+
.filter((x) => !x.startsWith(encodeURIComponent('var:'))) // Remove any variant specification
|
|
28
|
+
.map((x) => decodeURIComponent(x)); // Decode the URI components
|
|
29
|
+
if (slugs.length === 0)
|
|
30
|
+
return '/'; // We're requesting the homepage, so just return that path
|
|
31
|
+
// Build the URL
|
|
32
|
+
const fullPath = !slugs[slugs.length - 1].includes('.') ? '/' + slugs.join('/') + '/' : '/' + slugs.join('/');
|
|
33
|
+
return fullPath;
|
|
24
34
|
},
|
|
25
|
-
|
|
35
|
+
async propsToVariant({ params }) {
|
|
36
|
+
const pathSegments = (await params).path;
|
|
37
|
+
const variantPrefix = encodeURIComponent('var:');
|
|
38
|
+
const variantSegment = Array.isArray(pathSegments) ? pathSegments.filter(x => typeof x === 'string' && x.startsWith(variantPrefix)).at(0) : undefined;
|
|
39
|
+
return variantSegment ? variantSegment.substring(variantPrefix.length) : undefined;
|
|
40
|
+
},
|
|
41
|
+
routeToParams(route) {
|
|
42
|
+
const pathSegments = urlToPath(route.url);
|
|
43
|
+
if (route.variation)
|
|
44
|
+
pathSegments.push(`var:${route.variation}`);
|
|
45
|
+
return { path: pathSegments, lang: route.locale };
|
|
46
|
+
},
|
|
47
|
+
async paramsToLocale(params, channel) {
|
|
26
48
|
// If there's no channel, just return undefined
|
|
27
49
|
if (!channel)
|
|
28
50
|
return undefined;
|
|
@@ -51,7 +73,7 @@ const CreatePageOptionDefaults = {
|
|
|
51
73
|
*/
|
|
52
74
|
export function createPage(factory, options) {
|
|
53
75
|
// Build the global/shared configuration for the Optimizely CMS Page
|
|
54
|
-
const { getContentByPath, client: clientFactory, channel, propsToCmsPath, routeToParams, routerFactory, paramsToLocale, } = {
|
|
76
|
+
const { getContentByPath, client: clientFactory, channel, propsToCmsPath, propsToVariant, routeToParams, routerFactory, paramsToLocale, } = {
|
|
55
77
|
...CreatePageOptionDefaults,
|
|
56
78
|
...options,
|
|
57
79
|
};
|
|
@@ -68,74 +90,53 @@ export function createPage(factory, options) {
|
|
|
68
90
|
const client = await clientFactory(undefined, 'metadata');
|
|
69
91
|
const router = routerFactory(client);
|
|
70
92
|
const channelId = getChannelId(client, channel);
|
|
71
|
-
const allRoutes = await router.getRoutes(channelId, channel ? undefined : true);
|
|
93
|
+
const allRoutes = await router.getRoutes(channelId, channel ? undefined : true, true);
|
|
72
94
|
return allRoutes.map((r) => routeToParams(r));
|
|
73
95
|
},
|
|
74
|
-
generateMetadata: async ({ params, searchParams },
|
|
75
|
-
//
|
|
96
|
+
generateMetadata: async ({ params, searchParams }, resolvingMetadata) => {
|
|
97
|
+
// Prepare the context
|
|
76
98
|
const context = await buildContext();
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
propsToCmsPath({ params, searchParams }),
|
|
99
|
+
// Analyze the Next.JS Request props
|
|
100
|
+
const [requestPath, initialLocale, variation] = await Promise.all([
|
|
101
|
+
propsToCmsPath({ params, searchParams }, ifChannelDefinition(channel)),
|
|
81
102
|
paramsToLocale(params, ifChannelDefinition(channel)),
|
|
103
|
+
propsToVariant({ params, searchParams }, ifChannelDefinition(channel)).then(variant => variant || undefined)
|
|
82
104
|
]);
|
|
105
|
+
// Valdiate path
|
|
83
106
|
if (!requestPath)
|
|
84
|
-
return
|
|
107
|
+
return {};
|
|
108
|
+
// Track initial locale
|
|
85
109
|
if (initialLocale)
|
|
86
110
|
context.setLocale(initialLocale);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (context.isDebug)
|
|
95
|
-
console.log('⚪ [CmsPage.generateMetadata] No data received');
|
|
96
|
-
return Promise.resolve({});
|
|
97
|
-
}
|
|
98
|
-
const [route, contentLink, contentType, graphLocale] = routeInfo;
|
|
99
|
-
if (context.isDebug)
|
|
100
|
-
console.log(`⚪ [CmsPage.generateMetadata] Retrieved content info:`, route);
|
|
111
|
+
// Resolve route
|
|
112
|
+
const pathInfo = await getInfoByPath(context.client, routerFactory, requestPath, channel, variation);
|
|
113
|
+
if (!pathInfo)
|
|
114
|
+
return {};
|
|
115
|
+
const [route, contentLink, contentType, graphLocale] = pathInfo;
|
|
116
|
+
if (!contentLink || !contentType)
|
|
117
|
+
return {};
|
|
101
118
|
// Update context from route
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
updateSharedServerContext(context);
|
|
119
|
+
if (route)
|
|
120
|
+
context.setLocale(route.locale);
|
|
105
121
|
// Fetch the metadata based upon the actual content type and resolve parent
|
|
106
122
|
const metaResolver = new MetaDataResolver(context.client);
|
|
107
123
|
const [pageMetadata, baseMetadata] = await Promise.all([
|
|
108
124
|
metaResolver.resolve(factory, contentLink, contentType, graphLocale),
|
|
109
|
-
|
|
125
|
+
resolvingMetadata,
|
|
110
126
|
]);
|
|
111
|
-
if (context.isDebug)
|
|
112
|
-
console.log(`⚪ [CmsPage.generateMetadata] Component yielded metadata:`, pageMetadata);
|
|
113
|
-
// Make sure merging of objects goes correctly
|
|
114
|
-
for (const metaKey of Object.getOwnPropertyNames(pageMetadata)) {
|
|
115
|
-
if (isObject(pageMetadata[metaKey]) &&
|
|
116
|
-
isObject(baseMetadata[metaKey])) {
|
|
117
|
-
//@ts-expect-error Silence error due to failed introspection...
|
|
118
|
-
pageMetadata[metaKey] = deepmerge(baseMetadata[metaKey], pageMetadata[metaKey], { arrayMerge: (target, source) => [...source] });
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
// Not sure, but needed somehow...
|
|
122
|
-
if (typeof baseMetadata.metadataBase == 'string' &&
|
|
123
|
-
baseMetadata.metadataBase.length > 1) {
|
|
124
|
-
pageMetadata.metadataBase = new URL(baseMetadata.metadataBase);
|
|
125
|
-
}
|
|
126
127
|
return pageMetadata;
|
|
127
128
|
},
|
|
128
129
|
CmsPage: async ({ params, searchParams }) => {
|
|
129
130
|
// Prepare the context
|
|
130
131
|
const context = await buildContext();
|
|
131
|
-
//const params = await asyncParams;
|
|
132
132
|
// Analyze the Next.JS Request props
|
|
133
|
-
const [requestPath, initialLocale] = await Promise.all([
|
|
134
|
-
propsToCmsPath({ params, searchParams }),
|
|
133
|
+
const [requestPath, initialLocale, requestVariant] = await Promise.all([
|
|
134
|
+
propsToCmsPath({ params, searchParams }, ifChannelDefinition(channel)),
|
|
135
135
|
paramsToLocale(params, ifChannelDefinition(channel)),
|
|
136
|
+
(await propsToVariant({ params, searchParams })) ?? undefined
|
|
136
137
|
]);
|
|
137
138
|
if (context.isDebug)
|
|
138
|
-
console.log(`⚪ [CmsPage] Processed Next.JS route: ${JSON.stringify(await params)} => Optimizely CMS route: ${JSON.stringify({ path: requestPath })}`);
|
|
139
|
+
console.log(`⚪ [CmsPage] Processed Next.JS route: ${JSON.stringify(await params)} => Optimizely CMS route: ${JSON.stringify({ path: requestPath, variant: requestVariant })}`);
|
|
139
140
|
// If we don't have the path, or the path is an internal Next.js route reject it.
|
|
140
141
|
if (!requestPath || requestPath.startsWith('/_next/'))
|
|
141
142
|
return notFound();
|
|
@@ -144,8 +145,8 @@ export function createPage(factory, options) {
|
|
|
144
145
|
context.setLocale(initialLocale);
|
|
145
146
|
// Resolve the content based upon the path
|
|
146
147
|
const lookupData = await (getContentByPath
|
|
147
|
-
? loadContentByPath(context.client, getContentByPath, requestPath, channel, initialLocale)
|
|
148
|
-
: getInfoByPath(context.client, routerFactory, requestPath, channel));
|
|
148
|
+
? loadContentByPath(context.client, getContentByPath, requestPath, channel, initialLocale, requestVariant)
|
|
149
|
+
: getInfoByPath(context.client, routerFactory, requestPath, channel, requestVariant));
|
|
149
150
|
if (!lookupData) {
|
|
150
151
|
console.error(`🔴 [CmsPage] Unable to resolve the content for ${JSON.stringify(await params)}!`);
|
|
151
152
|
return notFound();
|
|
@@ -153,38 +154,10 @@ export function createPage(factory, options) {
|
|
|
153
154
|
const [route, contentLink, contentType, graphLocale, contentData] = lookupData;
|
|
154
155
|
if (contentLink?.locale)
|
|
155
156
|
context.setLocale(contentLink.locale);
|
|
156
|
-
// Make the shared server context available
|
|
157
|
-
updateSharedServerContext(context);
|
|
158
157
|
// Render the content link
|
|
159
158
|
return (_jsx(CmsContent, { contentType: contentType, contentLink: contentLink, fragmentData: contentData ?? undefined, ctx: context }));
|
|
160
159
|
},
|
|
161
160
|
};
|
|
162
161
|
return pageDefintion;
|
|
163
162
|
}
|
|
164
|
-
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* @param param0 The URL parameters
|
|
168
|
-
* @returns The request path as understood by Graph
|
|
169
|
-
*/
|
|
170
|
-
function buildRequestPath({ lang, path, }) {
|
|
171
|
-
const slugs = [];
|
|
172
|
-
if (path)
|
|
173
|
-
slugs.push(...path.filter((x) => x));
|
|
174
|
-
if (lang)
|
|
175
|
-
slugs.unshift(lang);
|
|
176
|
-
if (slugs.length == 0)
|
|
177
|
-
return '/';
|
|
178
|
-
const fullPath = '/' +
|
|
179
|
-
slugs
|
|
180
|
-
.filter((x) => x && x.length > 0)
|
|
181
|
-
.map((x) => decodeURIComponent(x))
|
|
182
|
-
.join('/');
|
|
183
|
-
if (!slugs[slugs.length - 1].includes('.'))
|
|
184
|
-
return fullPath + '/';
|
|
185
|
-
return fullPath;
|
|
186
|
-
}
|
|
187
|
-
function isObject(toTest) {
|
|
188
|
-
return typeof toTest == 'object' && toTest != null && toTest != undefined;
|
|
189
|
-
}
|
|
190
163
|
//# sourceMappingURL=page.js.map
|