@obelism/content 0.28.3 → 0.29.0

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/dist/site.js CHANGED
@@ -1,344 +1,14 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
- var config = require('./config-ci2hxmas.js');
3
+ require('./config-ci2hxmas.js');
4
+ var site = require('./site-j5kqgtj3.js');
4
5
 
5
- // Editing on your own site, outside the visual editor
6
- // (https://content.obelism.studio/docs/guides/site-editing). One handler
7
- // serves everything under `/cms` (the `basePath`) on your site:
8
- //
9
- // - `/cms/login?return_to=/pricing` — sends the browser to Obelism Content
10
- // to sign in, with a PKCE challenge, and…
11
- // - `/cms/callback` — …takes it back: trades the one-time code for a site
12
- // token, keeps it in an httpOnly cookie, calls `onSignIn` (turn on your
13
- // framework's draft mode there) and returns to `return_to`.
14
- // - `/cms/logout` — ends the session in the CMS, clears the cookies, calls
15
- // `onSignOut`.
16
- // - `/cms/api/…` — what the bridge's prompt bar calls in the browser,
17
- // forwarded to the CMS with the token. The token never reaches page
18
- // scripts.
19
- //
20
- // While signed in, render drafts by reading the delivery API with the token
21
- // (`readSiteToken`), and the bridge shows the prompt bar with Save and
22
- // Publish.
23
- const SITE_TOKEN_COOKIE = 'obelism_content_token';
24
- // Readable by the page: tells the bridge the site is being edited, and where
25
- // this handler lives. Holds no secret.
26
- const SITE_EDITING_COOKIE = 'obelism_content_editing';
27
- const FLOW_COOKIE = 'obelism_content_flow';
28
- // The bridge sends it with every write, which a cross-site form can't.
29
- const SITE_REQUEST_HEADER = 'x-obelism-content';
30
- const SITE_PATH = '/api/site/v1';
31
- const FLOW_MAX_AGE = 10 * 60;
32
- // The site token from a Cookie header (or a framework's cookie store), or
33
- // null when not signed in to edit:
34
- //
35
- // const token = readSiteToken(request.headers.get('cookie'))
36
- // const content = token ? new ContentClient({ token, init: { cache: 'no-store' } }) : delivery
37
- const readSiteToken = (cookies)=>{
38
- if (!cookies) return null;
39
- if (typeof cookies !== 'string') return cookies.get(SITE_TOKEN_COOKIE)?.value || null;
40
- return parseCookies(cookies).get(SITE_TOKEN_COOKIE) || null;
41
- };
42
- const parseCookies = (header)=>{
43
- const cookies = new Map();
44
- for (const part of header.split(';')){
45
- const index = part.indexOf('=');
46
- if (index < 0) continue;
47
- const name = part.slice(0, index).trim();
48
- if (!name || cookies.has(name)) continue;
49
- try {
50
- cookies.set(name, decodeURIComponent(part.slice(index + 1).trim()));
51
- } catch {
52
- cookies.set(name, part.slice(index + 1).trim());
53
- }
54
- }
55
- return cookies;
56
- };
57
- const serializeCookie = (name, value, { maxAge, path, httpOnly, secure })=>[
58
- `${name}=${encodeURIComponent(value)}`,
59
- `Path=${path}`,
60
- `Max-Age=${Math.max(0, Math.floor(maxAge))}`,
61
- // Also Expires: Next.js re-serializes response cookies when draft mode
62
- // changes, and drops a Max-Age of 0.
63
- `Expires=${new Date(maxAge > 0 ? Date.now() + maxAge * 1000 : 0).toUTCString()}`,
64
- 'SameSite=Lax',
65
- httpOnly && 'HttpOnly',
66
- secure && 'Secure'
67
- ].filter(Boolean).join('; ');
68
- const base64Url = (bytes)=>{
69
- let binary = '';
70
- for (const byte of bytes)binary += String.fromCharCode(byte);
71
- return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
72
- };
73
- const randomString = (bytes = 32)=>base64Url(crypto.getRandomValues(new Uint8Array(bytes)));
74
- const pkceChallenge = async (verifier)=>base64Url(new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))));
75
- const PLACEHOLDER_ORIGIN = 'https://site.invalid';
76
- // Only a path on this site: never an open redirect. Resolved the way a
77
- // browser reads Location, which drops tabs and newlines and reads \ as /.
78
- const safeReturnTo = (value)=>{
79
- if (!value?.startsWith('/')) return '/';
80
- const url = new URL(value, PLACEHOLDER_ORIGIN);
81
- return url.origin === PLACEHOLDER_ORIGIN ? `${url.pathname}${url.search}${url.hash}` : '/';
82
- };
83
- const normalizeBasePath = (basePath)=>`/${basePath.replace(/^\/+|\/+$/g, '')}`;
84
- // What the browser may reach through `/cms/api/…`: reads, and the writes
85
- // the prompt bar makes. Nothing else of the site API is exposed.
86
- const PROXY_ROUTES = [
87
- {
88
- method: 'GET',
89
- pattern: /^session$/
90
- },
91
- {
92
- method: 'GET',
93
- pattern: /^pages$/
94
- },
95
- {
96
- method: 'GET',
97
- pattern: /^entries\/[\w-]+$/
98
- },
99
- {
100
- method: 'POST',
101
- pattern: /^entries$/
102
- },
103
- // "Add a product page" on a product the site marks (editableProduct),
104
- // "Add a collection page" on a collection (editableCollection).
105
- {
106
- method: 'POST',
107
- pattern: /^product-pages$/
108
- },
109
- {
110
- method: 'POST',
111
- pattern: /^collection-pages$/
112
- },
113
- // The one-time address of the CMS's entry form (the prompt box's Form).
114
- {
115
- method: 'POST',
116
- pattern: /^form$/
117
- },
118
- // Clicks on the links the page tags, from Numbers.
119
- {
120
- method: 'POST',
121
- pattern: /^stats$/
122
- },
123
- {
124
- method: 'POST',
125
- pattern: /^entries\/[\w-]+\/(preview|prompt|view|apply|save|publish)$/
126
- }
127
- ];
128
- // The handler for everything under `basePath`. In Next.js:
129
- //
130
- // // app/cms/[...path]/route.ts
131
- // const handler = createSiteEditing({
132
- // spaceId: process.env.CONTENT_SPACE_ID!,
133
- // environment: 'production',
134
- // onSignIn: async () => (await draftMode()).enable(),
135
- // onSignOut: async () => (await draftMode()).disable(),
136
- // })
137
- // export { handler as GET, handler as POST }
138
- const createSiteEditing = ({ spaceId, environment, url, basePath = '/cms', siteUrl, onSignIn, onSignOut, timeout = config.DEFAULT_TIMEOUT, fetch: fetchImpl })=>{
139
- const cms = config.normalizeUrl(url || config.DEFAULT_URL);
140
- const base = normalizeBasePath(basePath);
141
- const doFetch = fetchImpl ?? ((...args)=>fetch(...args));
142
- const callCms = (path, init = {})=>doFetch(`${cms}${SITE_PATH}/${path}`, {
143
- ...init,
144
- redirect: 'manual',
145
- signal: AbortSignal.timeout(timeout)
146
- });
147
- return async (request)=>{
148
- const requestUrl = new URL(request.url);
149
- const origin = siteUrl ? config.normalizeUrl(siteUrl) : requestUrl.origin;
150
- const secure = origin.startsWith('https:');
151
- const redirectUri = `${origin}${base}/callback`;
152
- const cookies = parseCookies(request.headers.get('cookie') ?? '');
153
- const path = requestUrl.pathname.startsWith(`${base}/`) ? requestUrl.pathname.slice(base.length + 1) : null;
154
- const sessionCookies = (session)=>[
155
- serializeCookie(SITE_TOKEN_COOKIE, session.token, {
156
- maxAge: session.maxAge,
157
- path: '/',
158
- httpOnly: true,
159
- secure
160
- }),
161
- serializeCookie(SITE_EDITING_COOKIE, session.token ? base : '', {
162
- maxAge: session.maxAge,
163
- path: '/',
164
- httpOnly: false,
165
- secure
166
- })
167
- ];
168
- const clearedCookies = ()=>sessionCookies({
169
- token: '',
170
- maxAge: 0
171
- });
172
- const redirect = (location, setCookies = [])=>{
173
- const headers = new Headers({
174
- Location: location,
175
- 'Cache-Control': 'no-store'
176
- });
177
- for (const cookie of setCookies)headers.append('Set-Cookie', cookie);
178
- return new Response(null, {
179
- status: 302,
180
- headers
181
- });
182
- };
183
- if (path === 'login' && request.method === 'GET') {
184
- const state = randomString(16);
185
- const verifier = randomString(48);
186
- const flow = JSON.stringify({
187
- state,
188
- verifier,
189
- returnTo: safeReturnTo(requestUrl.searchParams.get('return_to'))
190
- });
191
- const connect = new URL(`${cms}/site/connect`);
192
- connect.search = new URLSearchParams({
193
- space: spaceId,
194
- environment,
195
- redirect_uri: redirectUri,
196
- state,
197
- code_challenge: await pkceChallenge(verifier),
198
- code_challenge_method: 'S256'
199
- }).toString();
200
- return redirect(connect.toString(), [
201
- serializeCookie(FLOW_COOKIE, flow, {
202
- maxAge: FLOW_MAX_AGE,
203
- path: base,
204
- httpOnly: true,
205
- secure
206
- })
207
- ]);
208
- }
209
- if (path === 'callback' && request.method === 'GET') {
210
- const clearFlow = serializeCookie(FLOW_COOKIE, '', {
211
- maxAge: 0,
212
- path: base,
213
- httpOnly: true,
214
- secure
215
- });
216
- let flow;
217
- try {
218
- flow = JSON.parse(cookies.get(FLOW_COOKIE) ?? '');
219
- } catch {
220
- flow = {};
221
- }
222
- const code = requestUrl.searchParams.get('code');
223
- if (!code || typeof flow.state !== 'string' || typeof flow.verifier !== 'string' || flow.state !== requestUrl.searchParams.get('state')) {
224
- return textResponse(400, 'This sign-in link is invalid or expired. Start again from the login link.', [
225
- clearFlow
226
- ]);
227
- }
228
- const response = await callCms('token', {
229
- method: 'POST',
230
- headers: {
231
- 'Content-Type': 'application/json'
232
- },
233
- body: JSON.stringify({
234
- code,
235
- code_verifier: flow.verifier,
236
- redirect_uri: redirectUri
237
- })
238
- });
239
- if (!response.ok) {
240
- return textResponse(400, 'Obelism Content did not accept the sign-in. Start again from the login link.', [
241
- clearFlow
242
- ]);
243
- }
244
- const session = await response.json();
245
- await onSignIn?.(session);
246
- const maxAge = (Date.parse(session.expiresAt) - Date.now()) / 1000;
247
- return redirect(safeReturnTo(flow.returnTo), [
248
- clearFlow,
249
- ...sessionCookies({
250
- token: session.token,
251
- maxAge
252
- })
253
- ]);
254
- }
255
- if (path === 'logout') {
256
- const token = cookies.get(SITE_TOKEN_COOKIE);
257
- if (token) {
258
- await callCms('session', {
259
- method: 'DELETE',
260
- headers: {
261
- Authorization: `Bearer ${token}`
262
- }
263
- }).catch(()=>null);
264
- }
265
- await onSignOut?.();
266
- return redirect(safeReturnTo(requestUrl.searchParams.get('return_to')), clearedCookies());
267
- }
268
- if (path?.startsWith('api/')) {
269
- const route = path.slice('api/'.length);
270
- if (!PROXY_ROUTES.some(({ method, pattern })=>method === request.method && pattern.test(route))) {
271
- return Response.json({
272
- error: 'Not found'
273
- }, {
274
- status: 404
275
- });
276
- }
277
- if (request.method !== 'GET' && request.headers.get(SITE_REQUEST_HEADER) !== '1') {
278
- return Response.json({
279
- error: 'Forbidden'
280
- }, {
281
- status: 403
282
- });
283
- }
284
- const token = cookies.get(SITE_TOKEN_COOKIE);
285
- if (!token) {
286
- return Response.json({
287
- error: 'Not signed in'
288
- }, {
289
- status: 401
290
- });
291
- }
292
- const response = await callCms(route, {
293
- method: request.method,
294
- headers: {
295
- Authorization: `Bearer ${token}`,
296
- ...request.method !== 'GET' && {
297
- 'Content-Type': 'application/json'
298
- }
299
- },
300
- ...request.method !== 'GET' && {
301
- body: await request.text()
302
- }
303
- });
304
- const headers = new Headers({
305
- 'Content-Type': 'application/json',
306
- 'Cache-Control': 'no-store'
307
- });
308
- // The session ended in the CMS: stop showing the editing UI.
309
- if (response.status === 401) {
310
- for (const cookie of clearedCookies()){
311
- headers.append('Set-Cookie', cookie);
312
- }
313
- }
314
- return new Response(await response.text(), {
315
- status: response.status,
316
- headers
317
- });
318
- }
319
- return Response.json({
320
- error: 'Not found'
321
- }, {
322
- status: 404
323
- });
324
- };
325
- };
326
- const textResponse = (status, text, setCookies)=>{
327
- const headers = new Headers({
328
- 'Content-Type': 'text/plain; charset=utf-8',
329
- 'Cache-Control': 'no-store'
330
- });
331
- for (const cookie of setCookies)headers.append('Set-Cookie', cookie);
332
- return new Response(text, {
333
- status,
334
- headers
335
- });
336
- };
337
6
 
338
- exports.SITE_EDITING_COOKIE = SITE_EDITING_COOKIE;
339
- exports.SITE_REQUEST_HEADER = SITE_REQUEST_HEADER;
340
- exports.SITE_TOKEN_COOKIE = SITE_TOKEN_COOKIE;
341
- exports.createSiteEditing = createSiteEditing;
342
- exports.pkceChallenge = pkceChallenge;
343
- exports.readSiteToken = readSiteToken;
344
- exports.safeReturnTo = safeReturnTo;
7
+
8
+ exports.SITE_EDITING_COOKIE = site.SITE_EDITING_COOKIE;
9
+ exports.SITE_REQUEST_HEADER = site.SITE_REQUEST_HEADER;
10
+ exports.SITE_TOKEN_COOKIE = site.SITE_TOKEN_COOKIE;
11
+ exports.createSiteEditing = site.createSiteEditing;
12
+ exports.pkceChallenge = site.pkceChallenge;
13
+ exports.readSiteToken = site.readSiteToken;
14
+ exports.safeReturnTo = site.safeReturnTo;
package/dist/site.mjs CHANGED
@@ -1,336 +1,2 @@
1
- import { n as normalizeUrl, a as DEFAULT_TIMEOUT, D as DEFAULT_URL } from './config-c6qktlz6.mjs';
2
-
3
- // Editing on your own site, outside the visual editor
4
- // (https://content.obelism.studio/docs/guides/site-editing). One handler
5
- // serves everything under `/cms` (the `basePath`) on your site:
6
- //
7
- // - `/cms/login?return_to=/pricing` — sends the browser to Obelism Content
8
- // to sign in, with a PKCE challenge, and…
9
- // - `/cms/callback` — …takes it back: trades the one-time code for a site
10
- // token, keeps it in an httpOnly cookie, calls `onSignIn` (turn on your
11
- // framework's draft mode there) and returns to `return_to`.
12
- // - `/cms/logout` — ends the session in the CMS, clears the cookies, calls
13
- // `onSignOut`.
14
- // - `/cms/api/…` — what the bridge's prompt bar calls in the browser,
15
- // forwarded to the CMS with the token. The token never reaches page
16
- // scripts.
17
- //
18
- // While signed in, render drafts by reading the delivery API with the token
19
- // (`readSiteToken`), and the bridge shows the prompt bar with Save and
20
- // Publish.
21
- const SITE_TOKEN_COOKIE = 'obelism_content_token';
22
- // Readable by the page: tells the bridge the site is being edited, and where
23
- // this handler lives. Holds no secret.
24
- const SITE_EDITING_COOKIE = 'obelism_content_editing';
25
- const FLOW_COOKIE = 'obelism_content_flow';
26
- // The bridge sends it with every write, which a cross-site form can't.
27
- const SITE_REQUEST_HEADER = 'x-obelism-content';
28
- const SITE_PATH = '/api/site/v1';
29
- const FLOW_MAX_AGE = 10 * 60;
30
- // The site token from a Cookie header (or a framework's cookie store), or
31
- // null when not signed in to edit:
32
- //
33
- // const token = readSiteToken(request.headers.get('cookie'))
34
- // const content = token ? new ContentClient({ token, init: { cache: 'no-store' } }) : delivery
35
- const readSiteToken = (cookies)=>{
36
- if (!cookies) return null;
37
- if (typeof cookies !== 'string') return cookies.get(SITE_TOKEN_COOKIE)?.value || null;
38
- return parseCookies(cookies).get(SITE_TOKEN_COOKIE) || null;
39
- };
40
- const parseCookies = (header)=>{
41
- const cookies = new Map();
42
- for (const part of header.split(';')){
43
- const index = part.indexOf('=');
44
- if (index < 0) continue;
45
- const name = part.slice(0, index).trim();
46
- if (!name || cookies.has(name)) continue;
47
- try {
48
- cookies.set(name, decodeURIComponent(part.slice(index + 1).trim()));
49
- } catch {
50
- cookies.set(name, part.slice(index + 1).trim());
51
- }
52
- }
53
- return cookies;
54
- };
55
- const serializeCookie = (name, value, { maxAge, path, httpOnly, secure })=>[
56
- `${name}=${encodeURIComponent(value)}`,
57
- `Path=${path}`,
58
- `Max-Age=${Math.max(0, Math.floor(maxAge))}`,
59
- // Also Expires: Next.js re-serializes response cookies when draft mode
60
- // changes, and drops a Max-Age of 0.
61
- `Expires=${new Date(maxAge > 0 ? Date.now() + maxAge * 1000 : 0).toUTCString()}`,
62
- 'SameSite=Lax',
63
- httpOnly && 'HttpOnly',
64
- secure && 'Secure'
65
- ].filter(Boolean).join('; ');
66
- const base64Url = (bytes)=>{
67
- let binary = '';
68
- for (const byte of bytes)binary += String.fromCharCode(byte);
69
- return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
70
- };
71
- const randomString = (bytes = 32)=>base64Url(crypto.getRandomValues(new Uint8Array(bytes)));
72
- const pkceChallenge = async (verifier)=>base64Url(new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))));
73
- const PLACEHOLDER_ORIGIN = 'https://site.invalid';
74
- // Only a path on this site: never an open redirect. Resolved the way a
75
- // browser reads Location, which drops tabs and newlines and reads \ as /.
76
- const safeReturnTo = (value)=>{
77
- if (!value?.startsWith('/')) return '/';
78
- const url = new URL(value, PLACEHOLDER_ORIGIN);
79
- return url.origin === PLACEHOLDER_ORIGIN ? `${url.pathname}${url.search}${url.hash}` : '/';
80
- };
81
- const normalizeBasePath = (basePath)=>`/${basePath.replace(/^\/+|\/+$/g, '')}`;
82
- // What the browser may reach through `/cms/api/…`: reads, and the writes
83
- // the prompt bar makes. Nothing else of the site API is exposed.
84
- const PROXY_ROUTES = [
85
- {
86
- method: 'GET',
87
- pattern: /^session$/
88
- },
89
- {
90
- method: 'GET',
91
- pattern: /^pages$/
92
- },
93
- {
94
- method: 'GET',
95
- pattern: /^entries\/[\w-]+$/
96
- },
97
- {
98
- method: 'POST',
99
- pattern: /^entries$/
100
- },
101
- // "Add a product page" on a product the site marks (editableProduct),
102
- // "Add a collection page" on a collection (editableCollection).
103
- {
104
- method: 'POST',
105
- pattern: /^product-pages$/
106
- },
107
- {
108
- method: 'POST',
109
- pattern: /^collection-pages$/
110
- },
111
- // The one-time address of the CMS's entry form (the prompt box's Form).
112
- {
113
- method: 'POST',
114
- pattern: /^form$/
115
- },
116
- // Clicks on the links the page tags, from Numbers.
117
- {
118
- method: 'POST',
119
- pattern: /^stats$/
120
- },
121
- {
122
- method: 'POST',
123
- pattern: /^entries\/[\w-]+\/(preview|prompt|view|apply|save|publish)$/
124
- }
125
- ];
126
- // The handler for everything under `basePath`. In Next.js:
127
- //
128
- // // app/cms/[...path]/route.ts
129
- // const handler = createSiteEditing({
130
- // spaceId: process.env.CONTENT_SPACE_ID!,
131
- // environment: 'production',
132
- // onSignIn: async () => (await draftMode()).enable(),
133
- // onSignOut: async () => (await draftMode()).disable(),
134
- // })
135
- // export { handler as GET, handler as POST }
136
- const createSiteEditing = ({ spaceId, environment, url, basePath = '/cms', siteUrl, onSignIn, onSignOut, timeout = DEFAULT_TIMEOUT, fetch: fetchImpl })=>{
137
- const cms = normalizeUrl(url || DEFAULT_URL);
138
- const base = normalizeBasePath(basePath);
139
- const doFetch = fetchImpl ?? ((...args)=>fetch(...args));
140
- const callCms = (path, init = {})=>doFetch(`${cms}${SITE_PATH}/${path}`, {
141
- ...init,
142
- redirect: 'manual',
143
- signal: AbortSignal.timeout(timeout)
144
- });
145
- return async (request)=>{
146
- const requestUrl = new URL(request.url);
147
- const origin = siteUrl ? normalizeUrl(siteUrl) : requestUrl.origin;
148
- const secure = origin.startsWith('https:');
149
- const redirectUri = `${origin}${base}/callback`;
150
- const cookies = parseCookies(request.headers.get('cookie') ?? '');
151
- const path = requestUrl.pathname.startsWith(`${base}/`) ? requestUrl.pathname.slice(base.length + 1) : null;
152
- const sessionCookies = (session)=>[
153
- serializeCookie(SITE_TOKEN_COOKIE, session.token, {
154
- maxAge: session.maxAge,
155
- path: '/',
156
- httpOnly: true,
157
- secure
158
- }),
159
- serializeCookie(SITE_EDITING_COOKIE, session.token ? base : '', {
160
- maxAge: session.maxAge,
161
- path: '/',
162
- httpOnly: false,
163
- secure
164
- })
165
- ];
166
- const clearedCookies = ()=>sessionCookies({
167
- token: '',
168
- maxAge: 0
169
- });
170
- const redirect = (location, setCookies = [])=>{
171
- const headers = new Headers({
172
- Location: location,
173
- 'Cache-Control': 'no-store'
174
- });
175
- for (const cookie of setCookies)headers.append('Set-Cookie', cookie);
176
- return new Response(null, {
177
- status: 302,
178
- headers
179
- });
180
- };
181
- if (path === 'login' && request.method === 'GET') {
182
- const state = randomString(16);
183
- const verifier = randomString(48);
184
- const flow = JSON.stringify({
185
- state,
186
- verifier,
187
- returnTo: safeReturnTo(requestUrl.searchParams.get('return_to'))
188
- });
189
- const connect = new URL(`${cms}/site/connect`);
190
- connect.search = new URLSearchParams({
191
- space: spaceId,
192
- environment,
193
- redirect_uri: redirectUri,
194
- state,
195
- code_challenge: await pkceChallenge(verifier),
196
- code_challenge_method: 'S256'
197
- }).toString();
198
- return redirect(connect.toString(), [
199
- serializeCookie(FLOW_COOKIE, flow, {
200
- maxAge: FLOW_MAX_AGE,
201
- path: base,
202
- httpOnly: true,
203
- secure
204
- })
205
- ]);
206
- }
207
- if (path === 'callback' && request.method === 'GET') {
208
- const clearFlow = serializeCookie(FLOW_COOKIE, '', {
209
- maxAge: 0,
210
- path: base,
211
- httpOnly: true,
212
- secure
213
- });
214
- let flow;
215
- try {
216
- flow = JSON.parse(cookies.get(FLOW_COOKIE) ?? '');
217
- } catch {
218
- flow = {};
219
- }
220
- const code = requestUrl.searchParams.get('code');
221
- if (!code || typeof flow.state !== 'string' || typeof flow.verifier !== 'string' || flow.state !== requestUrl.searchParams.get('state')) {
222
- return textResponse(400, 'This sign-in link is invalid or expired. Start again from the login link.', [
223
- clearFlow
224
- ]);
225
- }
226
- const response = await callCms('token', {
227
- method: 'POST',
228
- headers: {
229
- 'Content-Type': 'application/json'
230
- },
231
- body: JSON.stringify({
232
- code,
233
- code_verifier: flow.verifier,
234
- redirect_uri: redirectUri
235
- })
236
- });
237
- if (!response.ok) {
238
- return textResponse(400, 'Obelism Content did not accept the sign-in. Start again from the login link.', [
239
- clearFlow
240
- ]);
241
- }
242
- const session = await response.json();
243
- await onSignIn?.(session);
244
- const maxAge = (Date.parse(session.expiresAt) - Date.now()) / 1000;
245
- return redirect(safeReturnTo(flow.returnTo), [
246
- clearFlow,
247
- ...sessionCookies({
248
- token: session.token,
249
- maxAge
250
- })
251
- ]);
252
- }
253
- if (path === 'logout') {
254
- const token = cookies.get(SITE_TOKEN_COOKIE);
255
- if (token) {
256
- await callCms('session', {
257
- method: 'DELETE',
258
- headers: {
259
- Authorization: `Bearer ${token}`
260
- }
261
- }).catch(()=>null);
262
- }
263
- await onSignOut?.();
264
- return redirect(safeReturnTo(requestUrl.searchParams.get('return_to')), clearedCookies());
265
- }
266
- if (path?.startsWith('api/')) {
267
- const route = path.slice('api/'.length);
268
- if (!PROXY_ROUTES.some(({ method, pattern })=>method === request.method && pattern.test(route))) {
269
- return Response.json({
270
- error: 'Not found'
271
- }, {
272
- status: 404
273
- });
274
- }
275
- if (request.method !== 'GET' && request.headers.get(SITE_REQUEST_HEADER) !== '1') {
276
- return Response.json({
277
- error: 'Forbidden'
278
- }, {
279
- status: 403
280
- });
281
- }
282
- const token = cookies.get(SITE_TOKEN_COOKIE);
283
- if (!token) {
284
- return Response.json({
285
- error: 'Not signed in'
286
- }, {
287
- status: 401
288
- });
289
- }
290
- const response = await callCms(route, {
291
- method: request.method,
292
- headers: {
293
- Authorization: `Bearer ${token}`,
294
- ...request.method !== 'GET' && {
295
- 'Content-Type': 'application/json'
296
- }
297
- },
298
- ...request.method !== 'GET' && {
299
- body: await request.text()
300
- }
301
- });
302
- const headers = new Headers({
303
- 'Content-Type': 'application/json',
304
- 'Cache-Control': 'no-store'
305
- });
306
- // The session ended in the CMS: stop showing the editing UI.
307
- if (response.status === 401) {
308
- for (const cookie of clearedCookies()){
309
- headers.append('Set-Cookie', cookie);
310
- }
311
- }
312
- return new Response(await response.text(), {
313
- status: response.status,
314
- headers
315
- });
316
- }
317
- return Response.json({
318
- error: 'Not found'
319
- }, {
320
- status: 404
321
- });
322
- };
323
- };
324
- const textResponse = (status, text, setCookies)=>{
325
- const headers = new Headers({
326
- 'Content-Type': 'text/plain; charset=utf-8',
327
- 'Cache-Control': 'no-store'
328
- });
329
- for (const cookie of setCookies)headers.append('Set-Cookie', cookie);
330
- return new Response(text, {
331
- status,
332
- headers
333
- });
334
- };
335
-
336
- export { SITE_EDITING_COOKIE, SITE_REQUEST_HEADER, SITE_TOKEN_COOKIE, createSiteEditing, pkceChallenge, readSiteToken, safeReturnTo };
1
+ import './config-c6qktlz6.mjs';
2
+ export { S as SITE_EDITING_COOKIE, a as SITE_REQUEST_HEADER, b as SITE_TOKEN_COOKIE, c as createSiteEditing, d as pkceChallenge, r as readSiteToken, e as safeReturnTo } from './site-m85jdjid.mjs';