@remkoj/optimizely-cms-nextjs 1.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/LICENSE +13 -0
- package/README.md +2 -0
- package/dist/auth.d.ts +73 -0
- package/dist/auth.js +154 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +8 -0
- package/dist/client.js +22 -0
- package/dist/client.js.map +1 -0
- package/dist/cms-page/data.d.ts +39 -0
- package/dist/cms-page/data.js +43 -0
- package/dist/cms-page/data.js.map +1 -0
- package/dist/cms-page/index.d.ts +5 -0
- package/dist/cms-page/index.js +3 -0
- package/dist/cms-page/index.js.map +1 -0
- package/dist/cms-page/layout.d.ts +16 -0
- package/dist/cms-page/layout.js +81 -0
- package/dist/cms-page/layout.js.map +1 -0
- package/dist/cms-page/page.d.ts +28 -0
- package/dist/cms-page/page.js +108 -0
- package/dist/cms-page/page.js.map +1 -0
- package/dist/cms-page/utils.d.ts +5 -0
- package/dist/cms-page/utils.js +19 -0
- package/dist/cms-page/utils.js.map +1 -0
- package/dist/components/on-page-edit.d.ts +24 -0
- package/dist/components/on-page-edit.js +85 -0
- package/dist/components/on-page-edit.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata.d.ts +18 -0
- package/dist/metadata.js +36 -0
- package/dist/metadata.js.map +1 -0
- package/dist/ope/data.d.ts +2 -0
- package/dist/ope/data.js +28 -0
- package/dist/ope/data.js.map +1 -0
- package/dist/ope/index.d.ts +4 -0
- package/dist/ope/index.js +5 -0
- package/dist/ope/index.js.map +1 -0
- package/dist/ope/page.d.ts +17 -0
- package/dist/ope/page.js +141 -0
- package/dist/ope/page.js.map +1 -0
- package/dist/ope/types.d.ts +73 -0
- package/dist/ope/types.js +2 -0
- package/dist/ope/types.js.map +1 -0
- package/dist/page.d.ts +2 -0
- package/dist/page.js +6 -0
- package/dist/page.js.map +1 -0
- package/dist/publish/index.d.ts +10 -0
- package/dist/publish/index.js +54 -0
- package/dist/publish/index.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +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
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { User, Session } from "next-auth";
|
|
2
|
+
import type { OAuthConfig } from "next-auth/providers";
|
|
3
|
+
export type OptimizelyCmsOIDCProviderOptions = {
|
|
4
|
+
id?: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret?: string;
|
|
7
|
+
cmsBaseUrl: string | URL;
|
|
8
|
+
name: string;
|
|
9
|
+
scopes?: string[];
|
|
10
|
+
};
|
|
11
|
+
type OptimizelyProfile = {
|
|
12
|
+
sub: string;
|
|
13
|
+
oi_au_id: string;
|
|
14
|
+
azp: string;
|
|
15
|
+
at_hash: string;
|
|
16
|
+
oi_tkn_id: string;
|
|
17
|
+
aud: string;
|
|
18
|
+
exp: number;
|
|
19
|
+
iss: string;
|
|
20
|
+
iat: number;
|
|
21
|
+
};
|
|
22
|
+
export declare function OptimizelyCmsOIDCProvider(options: OptimizelyCmsOIDCProviderOptions): OAuthConfig<OptimizelyProfile>;
|
|
23
|
+
/**
|
|
24
|
+
* Generate the JWT callback handler to ensure sessions - with JWT storage - are properly prolonged based on the
|
|
25
|
+
* refresh token.
|
|
26
|
+
*
|
|
27
|
+
* @param options The configuration of the connection with Optimizely CMS
|
|
28
|
+
* @returns The callback handler
|
|
29
|
+
*/
|
|
30
|
+
export declare function OptimizelyCmsRefreshJwtCallbackHandler(options: OptimizelyCmsOIDCProviderOptions): (params: {
|
|
31
|
+
token: import("next-auth/jwt").JWT;
|
|
32
|
+
user: User | import("next-auth/adapters").AdapterUser;
|
|
33
|
+
account: import("next-auth").Account | null;
|
|
34
|
+
profile?: import("next-auth").Profile | undefined;
|
|
35
|
+
trigger?: "signIn" | "signUp" | "update" | undefined;
|
|
36
|
+
isNewUser?: boolean | undefined;
|
|
37
|
+
session?: any;
|
|
38
|
+
}) => import("next-auth").Awaitable<import("next-auth/jwt").JWT>;
|
|
39
|
+
/**
|
|
40
|
+
* Generate the Session callback handler to ensure sessions - with JWT storage - contain the needed information to inform users
|
|
41
|
+
* about errors with the login status.
|
|
42
|
+
*
|
|
43
|
+
* @param options The configuration of the connection with Optimizely CMS
|
|
44
|
+
* @returns The callback handler
|
|
45
|
+
*/
|
|
46
|
+
export declare const OptimizelyCmsRefreshSessionCallbackHander: (options: OptimizelyCmsOIDCProviderOptions) => (params: {
|
|
47
|
+
session: Session;
|
|
48
|
+
token: import("next-auth/jwt").JWT;
|
|
49
|
+
user: import("next-auth/adapters").AdapterUser;
|
|
50
|
+
} & {
|
|
51
|
+
newSession: any;
|
|
52
|
+
trigger: "update";
|
|
53
|
+
}) => import("next-auth").Awaitable<Session | import("next-auth").DefaultSession>;
|
|
54
|
+
declare module "next-auth/core/types" {
|
|
55
|
+
interface Session {
|
|
56
|
+
error?: string;
|
|
57
|
+
user?: Omit<User, 'id'>;
|
|
58
|
+
}
|
|
59
|
+
interface User {
|
|
60
|
+
roles?: string;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
declare module "next-auth/jwt/types" {
|
|
64
|
+
interface DefaultJWT {
|
|
65
|
+
roles?: string;
|
|
66
|
+
access_token?: string;
|
|
67
|
+
provider?: string;
|
|
68
|
+
expires_at?: number;
|
|
69
|
+
refresh_token?: string;
|
|
70
|
+
error?: "tokenRefreshError" | "unknownError" | "tokenExpiredError" | null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export {};
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const defaultScopes = ['openid', 'offline_access', 'profile', 'email'];
|
|
2
|
+
const defaultRoles = "Everyone Authenticated";
|
|
3
|
+
const defaultProviderId = "optimizely_cms";
|
|
4
|
+
export function OptimizelyCmsOIDCProvider(options) {
|
|
5
|
+
// Merge default scopes & requested scopes
|
|
6
|
+
const scopes = [...defaultScopes];
|
|
7
|
+
options.scopes?.forEach(scope => {
|
|
8
|
+
if (!scopes.includes(scope))
|
|
9
|
+
scopes.push(scope);
|
|
10
|
+
});
|
|
11
|
+
const finalConfig = {
|
|
12
|
+
type: "oauth",
|
|
13
|
+
id: options.id ?? defaultProviderId,
|
|
14
|
+
name: options.name,
|
|
15
|
+
clientId: options.clientId,
|
|
16
|
+
clientSecret: options.clientSecret,
|
|
17
|
+
wellKnown: new URL("/.well-known/openid-configuration", options.cmsBaseUrl).href,
|
|
18
|
+
userinfo: new URL("/api/episerver/connect/userinfo", options.cmsBaseUrl).href,
|
|
19
|
+
accessTokenUrl: new URL("/api/episerver/connect/token", options.cmsBaseUrl).href,
|
|
20
|
+
authorization: { params: { scope: scopes.join(' ') } },
|
|
21
|
+
profileUrl: new URL("/api/episerver/connect/userinfo", options.cmsBaseUrl).href,
|
|
22
|
+
idToken: true,
|
|
23
|
+
checks: ['pkce', 'state'],
|
|
24
|
+
client: {
|
|
25
|
+
token_endpoint_auth_method: options.clientSecret ? 'client_secret_basic' : 'none',
|
|
26
|
+
introspection_endpoint_auth_method: options.clientSecret ? 'client_secret_basic' : 'none',
|
|
27
|
+
revocation_endpoint_auth_method: options.clientSecret ? 'client_secret_basic' : 'none',
|
|
28
|
+
},
|
|
29
|
+
httpOptions: {
|
|
30
|
+
//@ts-expect-error
|
|
31
|
+
cache: "no-store",
|
|
32
|
+
next: {
|
|
33
|
+
revalidate: 0
|
|
34
|
+
},
|
|
35
|
+
revalidate: 0
|
|
36
|
+
},
|
|
37
|
+
async profile(profile, tokens) {
|
|
38
|
+
const auth_header = `${tokens.token_type} ${tokens.access_token}`;
|
|
39
|
+
const response = await fetch(new URL("/api/episerver/connect/userinfo", options.cmsBaseUrl), { headers: { Authorization: auth_header } });
|
|
40
|
+
if (!response.ok)
|
|
41
|
+
return { id: profile.sub, roles: defaultRoles };
|
|
42
|
+
const userinfo = await response.json();
|
|
43
|
+
const u = {
|
|
44
|
+
id: profile.sub,
|
|
45
|
+
email: userinfo.email,
|
|
46
|
+
name: userinfo.name,
|
|
47
|
+
roles: userinfo.role ? userinfo.role.join(' ') : defaultRoles
|
|
48
|
+
};
|
|
49
|
+
return u;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
return finalConfig;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Generate the JWT callback handler to ensure sessions - with JWT storage - are properly prolonged based on the
|
|
56
|
+
* refresh token.
|
|
57
|
+
*
|
|
58
|
+
* @param options The configuration of the connection with Optimizely CMS
|
|
59
|
+
* @returns The callback handler
|
|
60
|
+
*/
|
|
61
|
+
export function OptimizelyCmsRefreshJwtCallbackHandler(options) {
|
|
62
|
+
const providerId = options.id ?? defaultProviderId;
|
|
63
|
+
const OptimizelyCmsRefreshJwtCallback = async ({ account, token, user }) => {
|
|
64
|
+
if (account) // This is the first login
|
|
65
|
+
{
|
|
66
|
+
if (account.provider != providerId)
|
|
67
|
+
return token;
|
|
68
|
+
return {
|
|
69
|
+
sub: account.providerAccountId,
|
|
70
|
+
provider: account.provider,
|
|
71
|
+
access_token: account.access_token,
|
|
72
|
+
expires_at: account.expires_at,
|
|
73
|
+
refresh_token: account.refresh_token,
|
|
74
|
+
name: user?.name,
|
|
75
|
+
email: user?.email,
|
|
76
|
+
roles: user?.roles
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (token.provider != providerId) {
|
|
80
|
+
return token;
|
|
81
|
+
}
|
|
82
|
+
if (Date.now() < (token.expires_at ?? 0) * 1000) {
|
|
83
|
+
return {
|
|
84
|
+
...token,
|
|
85
|
+
error: null
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (token.refresh_token) {
|
|
89
|
+
const requestBody = {
|
|
90
|
+
client_id: options.clientId,
|
|
91
|
+
grant_type: "refresh_token",
|
|
92
|
+
refresh_token: token.refresh_token
|
|
93
|
+
};
|
|
94
|
+
if (options.clientSecret)
|
|
95
|
+
requestBody.client_secret = options.clientSecret;
|
|
96
|
+
const response = await fetch(new URL("/api/episerver/connect/token", options.cmsBaseUrl), {
|
|
97
|
+
headers: {
|
|
98
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
99
|
+
},
|
|
100
|
+
body: new URLSearchParams(requestBody),
|
|
101
|
+
method: 'POST',
|
|
102
|
+
cache: 'no-cache'
|
|
103
|
+
});
|
|
104
|
+
const tokens = await response.json();
|
|
105
|
+
if (!response.ok)
|
|
106
|
+
throw tokens;
|
|
107
|
+
const newToken = {
|
|
108
|
+
...token,
|
|
109
|
+
access_token: tokens.access_token,
|
|
110
|
+
expires_at: tokens.expires_at,
|
|
111
|
+
refresh_token: tokens.id_token
|
|
112
|
+
};
|
|
113
|
+
if (newToken.error)
|
|
114
|
+
delete newToken.error;
|
|
115
|
+
return newToken;
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
...token,
|
|
119
|
+
error: "tokenExpiredError"
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
return OptimizelyCmsRefreshJwtCallback;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Generate the Session callback handler to ensure sessions - with JWT storage - contain the needed information to inform users
|
|
126
|
+
* about errors with the login status.
|
|
127
|
+
*
|
|
128
|
+
* @param options The configuration of the connection with Optimizely CMS
|
|
129
|
+
* @returns The callback handler
|
|
130
|
+
*/
|
|
131
|
+
export const OptimizelyCmsRefreshSessionCallbackHander = (options) => {
|
|
132
|
+
const providerId = options.id ?? defaultProviderId;
|
|
133
|
+
const OptimizelyCmsRefreshSessionCallback = async ({ session, token, user }) => {
|
|
134
|
+
const newSession = { ...session };
|
|
135
|
+
if (token?.provider == providerId) {
|
|
136
|
+
newSession.user = {
|
|
137
|
+
email: token.email,
|
|
138
|
+
name: token.name,
|
|
139
|
+
roles: token.roles
|
|
140
|
+
};
|
|
141
|
+
if (token.error) {
|
|
142
|
+
newSession.error = token.error;
|
|
143
|
+
}
|
|
144
|
+
else if (newSession.error) {
|
|
145
|
+
delete newSession.error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (user)
|
|
149
|
+
newSession.user = user;
|
|
150
|
+
return newSession;
|
|
151
|
+
};
|
|
152
|
+
return OptimizelyCmsRefreshSessionCallback;
|
|
153
|
+
};
|
|
154
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import { type IOptiGraphClient } from '@remkoj/optimizely-graph-client';
|
|
3
|
+
export declare const getServerClient: () => IOptiGraphClient;
|
|
4
|
+
export declare const getAuthorizedServerClient: (token?: string) => IOptiGraphClient;
|
|
5
|
+
export declare const createClient: () => IOptiGraphClient;
|
|
6
|
+
export declare const createAuthorizedClient: (token?: string) => IOptiGraphClient;
|
|
7
|
+
declare const _default: IOptiGraphClient;
|
|
8
|
+
export default _default;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import createBaseClient from '@remkoj/optimizely-graph-client';
|
|
4
|
+
import { isDebug } from '@remkoj/optimizely-cms-react/rsc';
|
|
5
|
+
export const getServerClient = React.cache(() => {
|
|
6
|
+
if (isDebug())
|
|
7
|
+
console.log('⚪ [ContentGraph Shared Client] Creating new Optimizely Graph client');
|
|
8
|
+
return createBaseClient();
|
|
9
|
+
});
|
|
10
|
+
export const getAuthorizedServerClient = (token) => {
|
|
11
|
+
if (isDebug())
|
|
12
|
+
console.log('⚪ [ContentGraph Shared Client] Creating new Optimizely Graph client with authentication details');
|
|
13
|
+
const client = createBaseClient();
|
|
14
|
+
client.updateAuthentication(token);
|
|
15
|
+
if (isDebug())
|
|
16
|
+
console.log(`🟡 [ContentGraph Shared Client] Updated authentication, current mode: ${client.currentAuthMode}`);
|
|
17
|
+
return client;
|
|
18
|
+
};
|
|
19
|
+
export const createClient = getServerClient;
|
|
20
|
+
export const createAuthorizedClient = getAuthorizedServerClient;
|
|
21
|
+
export default getServerClient();
|
|
22
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AACpB,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,gBAA2C,MAAM,iCAAiC,CAAA;AACzF,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA;AAE1D,MAAM,CAAC,MAAM,eAAe,GAA4B,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE;IACrE,IAAI,OAAO,EAAE;QACT,OAAO,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAA;IACtF,OAAO,gBAAgB,EAAE,CAAA;AAC7B,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAyC,CAAC,KAAK,EAAE,EAAE;IACrF,IAAI,OAAO,EAAE;QACT,OAAO,CAAC,GAAG,CAAC,iGAAiG,CAAC,CAAA;IAClH,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAA;IACjC,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAA;IAClC,IAAI,OAAO,EAAE;QACT,OAAO,CAAC,GAAG,CAAC,yEAA0E,MAAM,CAAC,eAAgB,EAAE,CAAC,CAAA;IACpH,OAAO,MAAM,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,eAAe,CAAA;AAC3C,MAAM,CAAC,MAAM,sBAAsB,GAAG,yBAAyB,CAAA;AAC/D,eAAe,eAAe,EAAE,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { GraphQLClient } from "graphql-request";
|
|
2
|
+
export type GetContentByPathVariables = {
|
|
3
|
+
path: string;
|
|
4
|
+
locale?: Array<string | null>[] | string | null;
|
|
5
|
+
siteId?: string | null;
|
|
6
|
+
};
|
|
7
|
+
export type GetContentByPathResponse = {
|
|
8
|
+
Content?: {
|
|
9
|
+
items?: {
|
|
10
|
+
contentType?: Array<string | null> | null;
|
|
11
|
+
id?: {
|
|
12
|
+
id?: number | null;
|
|
13
|
+
workId?: number | null;
|
|
14
|
+
guidValue?: string | null;
|
|
15
|
+
} | null;
|
|
16
|
+
locale?: {
|
|
17
|
+
name?: string | null;
|
|
18
|
+
} | null;
|
|
19
|
+
path?: string | null;
|
|
20
|
+
}[];
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export type GetMetaDataByPathResponse = {
|
|
24
|
+
getGenericMetaData?: {
|
|
25
|
+
items?: Array<{
|
|
26
|
+
name?: string;
|
|
27
|
+
alternatives?: Array<{
|
|
28
|
+
locale?: string | null;
|
|
29
|
+
href?: string | null;
|
|
30
|
+
} | null> | null;
|
|
31
|
+
canonical?: string | null;
|
|
32
|
+
} | null>;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export type GetContentByPathMethod = (client: GraphQLClient, variables: GetContentByPathVariables) => Promise<GetContentByPathResponse>;
|
|
36
|
+
export type GetMetaDataByPathMethod = (client: GraphQLClient, variables: GetContentByPathVariables) => Promise<GetMetaDataByPathResponse>;
|
|
37
|
+
export declare const getMetaDataByPath: GetMetaDataByPathMethod;
|
|
38
|
+
export declare const getContentByPath: GetContentByPathMethod;
|
|
39
|
+
export default getContentByPath;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { gql } from "graphql-request";
|
|
2
|
+
export const getMetaDataByPath = (client, variables) => {
|
|
3
|
+
return client.request(metadataQuery, variables);
|
|
4
|
+
};
|
|
5
|
+
export const getContentByPath = (client, variables) => {
|
|
6
|
+
return client.request(contentQuery, variables);
|
|
7
|
+
};
|
|
8
|
+
export default getContentByPath;
|
|
9
|
+
const contentQuery = gql `query getContentByPathBase($path: String!, $locale: [Locales], $siteId: String) {
|
|
10
|
+
Content(
|
|
11
|
+
where: { RelativePath: { eq: $path }, SiteId: { eq: $siteId } }
|
|
12
|
+
locale: $locale
|
|
13
|
+
) {
|
|
14
|
+
items {
|
|
15
|
+
contentType: ContentType
|
|
16
|
+
id: ContentLink {
|
|
17
|
+
id: Id
|
|
18
|
+
workId: WorkId
|
|
19
|
+
guidValue: GuidValue
|
|
20
|
+
}
|
|
21
|
+
locale: Language {
|
|
22
|
+
name: Name
|
|
23
|
+
}
|
|
24
|
+
path: RelativePath
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}`;
|
|
28
|
+
const metadataQuery = gql `query getGenericMetaData($path: String!, $locale: [Locales], $siteId: String) {
|
|
29
|
+
getGenericMetaData: Content (
|
|
30
|
+
where: { RelativePath: { eq: $path }, SiteId: { eq: $siteId } }
|
|
31
|
+
locale: $locale
|
|
32
|
+
) {
|
|
33
|
+
items {
|
|
34
|
+
name: Name,
|
|
35
|
+
alternatives: ExistingLanguages {
|
|
36
|
+
locale: Name
|
|
37
|
+
href: Link
|
|
38
|
+
}
|
|
39
|
+
canonical: Url
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}`;
|
|
43
|
+
//# sourceMappingURL=data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/cms-page/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAiB,MAAM,iBAAiB,CAAA;AAyCpD,MAAM,CAAC,MAAM,iBAAiB,GAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE;IAE5E,OAAO,MAAM,CAAC,OAAO,CAAsD,aAAa,EAAE,SAAS,CAAC,CAAA;AACxG,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAA2B,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE;IAE1E,OAAO,MAAM,CAAC,OAAO,CAAqD,YAAY,EAAE,SAAS,CAAC,CAAA;AACtG,CAAC,CAAA;AAED,eAAe,gBAAgB,CAAA;AAE/B,MAAM,YAAY,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;EAkBtB,CAAA;AAEF,MAAM,aAAa,GAAG,GAAG,CAAA;;;;;;;;;;;;;;EAcvB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { GetContentByPathMethod, GetMetaDataByPathMethod } from './data';
|
|
2
|
+
export type { CreatePageOptions, Props as CmsPageProps, Params as CmsPageParams } from './page';
|
|
3
|
+
export type { CreateLayoutOptions } from './layout';
|
|
4
|
+
export { createPage } from './page';
|
|
5
|
+
export { createLayout } from './layout';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cms-page/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type PropsWithChildren, type ReactNode } from "react";
|
|
2
|
+
import { type Metadata, type ResolvingMetadata } from "next";
|
|
3
|
+
import type { ChannelDefinition, ClientFactory } from "@remkoj/optimizely-graph-client";
|
|
4
|
+
import type { Props } from './page';
|
|
5
|
+
import { type GetMetaDataByPathMethod } from './data';
|
|
6
|
+
export type CmsPageLayout = {
|
|
7
|
+
generateMetadata: (props: Omit<Props, 'searchParams'>, resolving: ResolvingMetadata) => Promise<Metadata>;
|
|
8
|
+
PageLayout: (props: PropsWithChildren<Omit<Props, 'searchParams'>>) => JSX.Element | ReactNode;
|
|
9
|
+
};
|
|
10
|
+
export type CreateLayoutOptions = {
|
|
11
|
+
defaultLocale: string;
|
|
12
|
+
getMetaDataByPath: GetMetaDataByPathMethod;
|
|
13
|
+
client: ClientFactory;
|
|
14
|
+
};
|
|
15
|
+
export declare function createLayout(channel: ChannelDefinition, options?: Partial<CreateLayoutOptions>): CmsPageLayout;
|
|
16
|
+
export default createLayout;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Utils } from "@remkoj/optimizely-cms-react";
|
|
2
|
+
import { getMetaDataByPath as getMetaDataByPathBase } from './data';
|
|
3
|
+
import { slugToLocale, slugToGraphLocale } from "./utils";
|
|
4
|
+
import { getServerClient } from "../client";
|
|
5
|
+
import { isDebug } from '@remkoj/optimizely-cms-react/rsc';
|
|
6
|
+
const defaultCreateLayoutOptions = {
|
|
7
|
+
defaultLocale: "en",
|
|
8
|
+
getMetaDataByPath: getMetaDataByPathBase,
|
|
9
|
+
client: getServerClient
|
|
10
|
+
};
|
|
11
|
+
export function createLayout(channel, options) {
|
|
12
|
+
const { defaultLocale, getMetaDataByPath, client: clientFactory } = {
|
|
13
|
+
...defaultCreateLayoutOptions,
|
|
14
|
+
...{ defaultLocale: channel.defaultLocale },
|
|
15
|
+
...options
|
|
16
|
+
};
|
|
17
|
+
const pageLayoutDefinition = {
|
|
18
|
+
/**
|
|
19
|
+
* Make sure that there's a sane default for the title, canonical URL
|
|
20
|
+
* and the language alternatives
|
|
21
|
+
*
|
|
22
|
+
* @param props The layout properties
|
|
23
|
+
* @returns The metadata that must be merged into the defaults
|
|
24
|
+
*/
|
|
25
|
+
generateMetadata: async ({ params }, resolving) => {
|
|
26
|
+
const locale = slugToLocale(channel, params?.lang ?? '', defaultLocale);
|
|
27
|
+
const relativePath = `/${params.lang}${params.path ? '/' + params.path.join('/') : ''}`;
|
|
28
|
+
if (isDebug())
|
|
29
|
+
console.log(`⚪ [CmsPageLayout] Generating metadata for: ${relativePath}`);
|
|
30
|
+
const variables = {
|
|
31
|
+
path: relativePath,
|
|
32
|
+
locale: slugToGraphLocale(channel, params.lang ?? '', defaultLocale)
|
|
33
|
+
};
|
|
34
|
+
const client = clientFactory();
|
|
35
|
+
const response = await getMetaDataByPath(client, variables).catch(e => {
|
|
36
|
+
console.error(`[CmsPageLayout] Metadata error:`, e);
|
|
37
|
+
return undefined;
|
|
38
|
+
});
|
|
39
|
+
const metadata = (response?.getGenericMetaData?.items ?? [])[0];
|
|
40
|
+
if (!metadata) {
|
|
41
|
+
if (isDebug())
|
|
42
|
+
console.log(`🟡 [CmsPageLayout] Unable to locate metadata for: ${relativePath}`);
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
const base = await resolving;
|
|
46
|
+
const title = base?.title?.template ? {
|
|
47
|
+
template: base?.title?.template,
|
|
48
|
+
default: metadata.name
|
|
49
|
+
} : metadata.name;
|
|
50
|
+
let pageMetadata = {
|
|
51
|
+
title,
|
|
52
|
+
alternates: {
|
|
53
|
+
canonical: metadata.canonical,
|
|
54
|
+
languages: {}
|
|
55
|
+
},
|
|
56
|
+
openGraph: {
|
|
57
|
+
...base.openGraph,
|
|
58
|
+
title,
|
|
59
|
+
url: metadata.canonical,
|
|
60
|
+
alternateLocale: []
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
// Add alternative URLs
|
|
64
|
+
const alternates = (metadata?.alternatives || []).filter(Utils.isNotNullOrUndefined).filter(x => x.locale != locale);
|
|
65
|
+
alternates.forEach(alt => {
|
|
66
|
+
if (pageMetadata.openGraph && Array.isArray(pageMetadata.openGraph.alternateLocale)) {
|
|
67
|
+
pageMetadata.openGraph.alternateLocale.push(alt.locale);
|
|
68
|
+
}
|
|
69
|
+
if (pageMetadata.alternates && pageMetadata.alternates.languages) {
|
|
70
|
+
//@ts-expect-error We need the locale to be dynamic, based upon the locales provided by the CMS
|
|
71
|
+
pageMetadata.alternates.languages[alt.locale] = alt.href;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return pageMetadata;
|
|
75
|
+
},
|
|
76
|
+
PageLayout: ({ children }) => children
|
|
77
|
+
};
|
|
78
|
+
return pageLayoutDefinition;
|
|
79
|
+
}
|
|
80
|
+
export default createLayout;
|
|
81
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/cms-page/layout.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import 'server-only';
|
|
3
|
+
import type { Metadata, ResolvingMetadata } from 'next';
|
|
4
|
+
import { type ClientFactory, type ChannelDefinition } from '@remkoj/optimizely-graph-client';
|
|
5
|
+
import { type ComponentFactory } from '@remkoj/optimizely-cms-react/rsc';
|
|
6
|
+
import { type GetContentByPathMethod } from './data';
|
|
7
|
+
export type Params = {
|
|
8
|
+
path: string[] | undefined;
|
|
9
|
+
lang: string | undefined;
|
|
10
|
+
};
|
|
11
|
+
export type Props = {
|
|
12
|
+
params: Params;
|
|
13
|
+
searchParams: {};
|
|
14
|
+
};
|
|
15
|
+
export type GenerateMetadataProps<TParams extends {} = {}, TSearch extends {} = {}> = {
|
|
16
|
+
params: Params;
|
|
17
|
+
};
|
|
18
|
+
export type NextJsPage = {
|
|
19
|
+
generateStaticParams: () => Promise<Params[]>;
|
|
20
|
+
generateMetadata: (props: Props, resolving: ResolvingMetadata) => Promise<Metadata>;
|
|
21
|
+
CmsPage: (props: Props) => Promise<JSX.Element>;
|
|
22
|
+
};
|
|
23
|
+
export type CreatePageOptions = {
|
|
24
|
+
defaultLocale: string;
|
|
25
|
+
getContentByPath: GetContentByPathMethod;
|
|
26
|
+
client: ClientFactory;
|
|
27
|
+
};
|
|
28
|
+
export declare function createPage(factory: ComponentFactory, channel: ChannelDefinition, options?: Partial<CreatePageOptions>): NextJsPage;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import 'server-only';
|
|
3
|
+
import deepmerge from 'deepmerge';
|
|
4
|
+
import { notFound } from 'next/navigation';
|
|
5
|
+
import { RouteResolver } from '@remkoj/optimizely-graph-client';
|
|
6
|
+
import { CmsContent, isDebug, getServerContext } from '@remkoj/optimizely-cms-react/rsc';
|
|
7
|
+
import { Utils } from '@remkoj/optimizely-cms-react';
|
|
8
|
+
import { MetaDataResolver } from '../metadata';
|
|
9
|
+
import { urlToPath, localeToGraphLocale } from './utils';
|
|
10
|
+
import getContentByPathBase from './data';
|
|
11
|
+
import { getServerClient } from '../client';
|
|
12
|
+
const CreatePageOptionDefaults = {
|
|
13
|
+
defaultLocale: "en",
|
|
14
|
+
getContentByPath: getContentByPathBase,
|
|
15
|
+
client: getServerClient
|
|
16
|
+
};
|
|
17
|
+
export function createPage(factory, channel, options) {
|
|
18
|
+
const { defaultLocale, getContentByPath, client: clientFactory } = {
|
|
19
|
+
...CreatePageOptionDefaults,
|
|
20
|
+
...{ defaultLocale: channel.defaultLocale },
|
|
21
|
+
...options
|
|
22
|
+
};
|
|
23
|
+
const pageDefintion = {
|
|
24
|
+
generateStaticParams: async () => {
|
|
25
|
+
const client = clientFactory();
|
|
26
|
+
const resolver = new RouteResolver(client);
|
|
27
|
+
return (await resolver.getRoutes()).map(r => {
|
|
28
|
+
return {
|
|
29
|
+
lang: channel.localeToSlug(r.language),
|
|
30
|
+
path: urlToPath(r.url, r.language)
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
generateMetadata: async ({ params: { lang, path } }, resolving) => {
|
|
35
|
+
// Read variables from request
|
|
36
|
+
const client = clientFactory();
|
|
37
|
+
const requestPath = buildRequestPath({ lang, path });
|
|
38
|
+
const routeResolver = new RouteResolver(client);
|
|
39
|
+
const metaResolver = new MetaDataResolver(client);
|
|
40
|
+
// Resolve the route to a content link
|
|
41
|
+
const route = await routeResolver.getContentInfoByPath(requestPath);
|
|
42
|
+
if (!route)
|
|
43
|
+
return Promise.resolve({});
|
|
44
|
+
// Set context
|
|
45
|
+
getServerContext().setLocale(localeToGraphLocale(channel, route.language));
|
|
46
|
+
getServerContext().setOptimizelyGraphClient(client);
|
|
47
|
+
// Prepare metadata fetching
|
|
48
|
+
const contentLink = routeResolver.routeToContentLink(route);
|
|
49
|
+
const contentType = route.contentType;
|
|
50
|
+
const graphLocale = localeToGraphLocale(channel, route.language);
|
|
51
|
+
// Fetch the metadata based upon the actual content type and resolve parent
|
|
52
|
+
const [pageMetadata, baseMetadata] = await Promise.all([
|
|
53
|
+
metaResolver.resolve(factory, contentLink, contentType, graphLocale),
|
|
54
|
+
resolving
|
|
55
|
+
]);
|
|
56
|
+
// Make sure merging of objects goes correctly
|
|
57
|
+
for (const metaKey of Object.getOwnPropertyNames(pageMetadata)) {
|
|
58
|
+
if (typeof (pageMetadata[metaKey]) == "object" && pageMetadata[metaKey] != null && baseMetadata[metaKey] != undefined && baseMetadata[metaKey] != null) {
|
|
59
|
+
//@ts-expect-error Silence error due to failed introspection...
|
|
60
|
+
pageMetadata[metaKey] = deepmerge(baseMetadata[metaKey], pageMetadata[metaKey], { arrayMerge: (target, source) => [...source] });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Not sure, but needed somehow...
|
|
64
|
+
if (typeof (baseMetadata.metadataBase) == "string" && baseMetadata.metadataBase.length > 1) {
|
|
65
|
+
pageMetadata.metadataBase = new URL(baseMetadata.metadataBase);
|
|
66
|
+
}
|
|
67
|
+
return pageMetadata;
|
|
68
|
+
},
|
|
69
|
+
CmsPage: async ({ params: { lang, path } }) => {
|
|
70
|
+
if (!lang || lang.length == 0)
|
|
71
|
+
return notFound();
|
|
72
|
+
// Prepare the context
|
|
73
|
+
const context = getServerContext();
|
|
74
|
+
const client = context.client ?? clientFactory();
|
|
75
|
+
if (!context.client)
|
|
76
|
+
context.setOptimizelyGraphClient(client);
|
|
77
|
+
context.setComponentFactory(factory);
|
|
78
|
+
// Resolve the content based upon the route
|
|
79
|
+
const requestPath = buildRequestPath({ lang, path });
|
|
80
|
+
const graphLocale = channel.slugToGraphLocale(lang);
|
|
81
|
+
const response = await getContentByPath(client, { path: requestPath, locale: graphLocale, siteId: channel.id });
|
|
82
|
+
const info = (response.Content?.items ?? [])[0];
|
|
83
|
+
context.setLocale(graphLocale);
|
|
84
|
+
if (!info) {
|
|
85
|
+
if (isDebug()) {
|
|
86
|
+
console.error(`🔴 [CmsPage] Unable to load content for ${requestPath}, data received: `, response);
|
|
87
|
+
}
|
|
88
|
+
return notFound();
|
|
89
|
+
}
|
|
90
|
+
// Extract the type & link
|
|
91
|
+
const contentType = Utils.normalizeContentType(info.contentType);
|
|
92
|
+
const contentLink = Utils.normalizeContentLinkWithLocale({ ...info.id, locale: info.locale?.name });
|
|
93
|
+
if (!contentLink) {
|
|
94
|
+
console.error("🔴 [CmsPage] Unable to infer the contentLink from the retrieved content, this should not have happened!");
|
|
95
|
+
return notFound();
|
|
96
|
+
}
|
|
97
|
+
// Render the content link
|
|
98
|
+
return _jsx(CmsContent, { contentType: contentType, contentLink: contentLink, fragmentData: info });
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
return pageDefintion;
|
|
102
|
+
}
|
|
103
|
+
function buildRequestPath({ lang, path }) {
|
|
104
|
+
return (path?.length ?? 0) > 0 ?
|
|
105
|
+
`/${lang ?? ""}/${path?.join("/") ?? ""}` :
|
|
106
|
+
`/${lang ?? ""}`;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/cms-page/page.tsx"],"names":[],"mappings":"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"}
|