@pantheon-systems/p1-next-sdk 0.13.0 → 0.14.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/bin/lib/transform.js +100 -1
- package/dist/create-published-page.d.ts +110 -0
- package/dist/create-published-page.d.ts.map +1 -0
- package/dist/create-published-page.js +86 -0
- package/dist/create-published-page.js.map +1 -0
- package/dist/published-page.d.ts +19 -6
- package/dist/published-page.d.ts.map +1 -1
- package/dist/published-page.js +15 -1
- package/dist/published-page.js.map +1 -1
- package/dist/routes/remote-datasources-api.d.ts +2 -2
- package/dist/server.d.ts +2 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/package.json +4 -3
package/bin/lib/transform.js
CHANGED
|
@@ -245,13 +245,112 @@ export function rewriteLoadingOverlay(source) {
|
|
|
245
245
|
return out;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* The auto-create-on-404 behaviour is gone. It POSTed to `/p1/api/structure/page`,
|
|
250
|
+
* a route no SDK handler ever served, so opening an editor path for a page that
|
|
251
|
+
* did not exist silently did nothing. The editor now renders a page-not-found
|
|
252
|
+
* panel in the canvas — chrome and all — offering to create the page, and both
|
|
253
|
+
* halves of that live in the SDK so they version together. Every trace of the old
|
|
254
|
+
* client-side half comes out.
|
|
255
|
+
*
|
|
256
|
+
* Every anchor has to match: an app already on the SDK flow is left alone, and an
|
|
257
|
+
* app that edited part of this region keeps its own version rather than being left
|
|
258
|
+
* with a broken mix of the two.
|
|
259
|
+
*/
|
|
260
|
+
const NOT_FOUND_EDITS = [
|
|
261
|
+
[
|
|
262
|
+
`const DEFAULT_PAGE_DATA = {
|
|
263
|
+
root: { props: { title: "New page" } },
|
|
264
|
+
content: [],
|
|
265
|
+
zones: {},
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const DEFAULT_ROOT_PAGE_DATA = {
|
|
269
|
+
root: { props: { title: "Welcome | P1 site" } },
|
|
270
|
+
content: [
|
|
271
|
+
{
|
|
272
|
+
type: "P1WelcomeBlock",
|
|
273
|
+
props: {
|
|
274
|
+
id: "seed-welcome",
|
|
275
|
+
heading: "Welcome to your new Pantheon P1 Site.",
|
|
276
|
+
description: "You just created this new site from Pantheon P1 starter kit, congrats! You'll need a Pantheon P1 user account to edit it and create new pages.",
|
|
277
|
+
ctaLabel: "Sign-in to P1",
|
|
278
|
+
ctaHref: "/p1",
|
|
279
|
+
footnote: "Visit [P1 documentation](https://docs.pantheon.io) for more information.",
|
|
280
|
+
loggedInHeading: "Welcome to your new Pantheon P1 Site.",
|
|
281
|
+
loggedInDescription: "You just created this new site from Pantheon P1 starter kit, congrats! Start editing this page or visit the P1 dashboard to manage your site.",
|
|
282
|
+
loggedInCtaLabel: "Edit this page with P1 Visual Editor",
|
|
283
|
+
loggedInCtaHref: "/p1",
|
|
284
|
+
loggedInSecondaryLabel: "Go to P1 Dashboard",
|
|
285
|
+
loggedInFootnote: "Visit [P1 documentation](https://docs.pantheon.io) for more information.",
|
|
286
|
+
showLogo: true,
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
zones: {},
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
`,
|
|
294
|
+
``,
|
|
295
|
+
],
|
|
296
|
+
[
|
|
297
|
+
` const router = useRouter();
|
|
298
|
+
const { getToken } = useP1Auth();
|
|
299
|
+
`,
|
|
300
|
+
` const router = useRouter();
|
|
301
|
+
`,
|
|
302
|
+
],
|
|
303
|
+
[
|
|
304
|
+
` const handleDocumentNotFound = useCallback(
|
|
305
|
+
async (docPath: string, _error: Error) => {
|
|
306
|
+
const initialData = docPath === "/" ? DEFAULT_ROOT_PAGE_DATA : DEFAULT_PAGE_DATA;
|
|
307
|
+
const token = await getToken();
|
|
308
|
+
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
309
|
+
if (token) headers["Authorization"] = \`Bearer \${token}\`;
|
|
310
|
+
const res = await fetch("/p1/api/structure/page", {
|
|
311
|
+
method: "POST",
|
|
312
|
+
headers,
|
|
313
|
+
body: JSON.stringify({ path: docPath, initialData }),
|
|
314
|
+
});
|
|
315
|
+
return res.ok;
|
|
316
|
+
},
|
|
317
|
+
[getToken],
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
`,
|
|
321
|
+
``,
|
|
322
|
+
],
|
|
323
|
+
[
|
|
324
|
+
` additionalPlugins,
|
|
325
|
+
onDocumentNotFound: handleDocumentNotFound,
|
|
326
|
+
`,
|
|
327
|
+
` additionalPlugins,
|
|
328
|
+
`,
|
|
329
|
+
],
|
|
330
|
+
];
|
|
331
|
+
|
|
332
|
+
/** Strip the dead auto-create-on-404 call; the SDK owns the page-not-found flow now. */
|
|
333
|
+
export function rewriteDocumentNotFound(source) {
|
|
334
|
+
const found = NOT_FOUND_EDITS.filter(([find]) => source.includes(find));
|
|
335
|
+
if (found.length === 0) return source;
|
|
336
|
+
if (found.length !== NOT_FOUND_EDITS.length) {
|
|
337
|
+
throw new BailError(
|
|
338
|
+
"editor-client.tsx has a partly-customized page-not-found flow; migrate this file by hand.",
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
let out = source;
|
|
342
|
+
for (const [find, replace] of NOT_FOUND_EDITS) out = out.replace(find, replace);
|
|
343
|
+
return out;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** Full editor-client transform: deepen imports, add the named imports, rewrite the signature, adopt the SDK overlay and page-not-found flow. */
|
|
249
347
|
export function rewriteEditorClient(source) {
|
|
250
348
|
let out = deepenRelativeImports(source);
|
|
251
349
|
out = addNamedImport(out, "next/navigation", "usePathname", "prepend");
|
|
252
350
|
out = addNamedImport(out, "@pantheon-systems/p1-next-sdk", "editorPagePathFromUrlPath", "append");
|
|
253
351
|
out = rewriteWrapperSignature(out);
|
|
254
352
|
out = rewriteLoadingOverlay(out);
|
|
353
|
+
out = rewriteDocumentNotFound(out);
|
|
255
354
|
return out;
|
|
256
355
|
}
|
|
257
356
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route builders for the published-page render pipeline.
|
|
3
|
+
*
|
|
4
|
+
* The pipeline itself — read the page, branch on the outcome, resolve route
|
|
5
|
+
* templates and remote datasources, render — is the same for every P1 site, and
|
|
6
|
+
* carries the invariants documented in published-page.ts. Hand-assembling it in
|
|
7
|
+
* each app's route files froze a copy of it into every scaffold, so improvements
|
|
8
|
+
* to caching or datasource resolution could never reach a project once it was
|
|
9
|
+
* created. It lives here instead, and the routes become shims.
|
|
10
|
+
*
|
|
11
|
+
* What genuinely differs per app flows in as options: the render client (which
|
|
12
|
+
* holds that app's puck.config), the components shown when content is
|
|
13
|
+
* unavailable or the home page has no document yet, the app's datasource
|
|
14
|
+
* fetcher registry, and how it turns page data into <head> metadata.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* // app/published-pages.tsx (shared module — one instance, both routes)
|
|
18
|
+
* import { createPublishedPage } from "@pantheon-systems/p1-next-sdk/server";
|
|
19
|
+
* export const published = createPublishedPage({ ... });
|
|
20
|
+
*
|
|
21
|
+
* // app/[...puckPath]/page.tsx
|
|
22
|
+
* export const revalidate = 300;
|
|
23
|
+
* export default published.Page;
|
|
24
|
+
* export const generateMetadata = published.generateMetadata;
|
|
25
|
+
* export const generateStaticParams = published.generateStaticParams;
|
|
26
|
+
*
|
|
27
|
+
* // app/page.tsx
|
|
28
|
+
* export const revalidate = 300;
|
|
29
|
+
* export default published.HomePage;
|
|
30
|
+
* export const generateMetadata = published.generateHomeMetadata;
|
|
31
|
+
*
|
|
32
|
+
* `revalidate` must stay a literal in the route file. Next.js statically
|
|
33
|
+
* analyzes segment-config exports, so re-exporting one through the factory
|
|
34
|
+
* leaves it undetected and the route silently loses its revalidation window —
|
|
35
|
+
* the same constraint that keeps `dynamic` in the route file for createP1Pages.
|
|
36
|
+
*/
|
|
37
|
+
import type { Metadata } from "next";
|
|
38
|
+
import { type RemoteDatasourceFetcher } from "@pantheon-systems/puck-css/server";
|
|
39
|
+
import type { Data } from "@puckeditor/core";
|
|
40
|
+
/**
|
|
41
|
+
* Describes the rendered document to the render client, which uses it for the
|
|
42
|
+
* edit affordances that only make sense once a real document is on screen.
|
|
43
|
+
*/
|
|
44
|
+
export type PublishedPageMetadata = {
|
|
45
|
+
route: string;
|
|
46
|
+
documentName?: string;
|
|
47
|
+
pageType?: "page" | "template" | "override";
|
|
48
|
+
};
|
|
49
|
+
export type PublishedPageClientProps = {
|
|
50
|
+
data: Data;
|
|
51
|
+
pageMetadata: PublishedPageMetadata;
|
|
52
|
+
};
|
|
53
|
+
export type CreatePublishedPageConfig = {
|
|
54
|
+
/**
|
|
55
|
+
* Renders resolved Puck data. Holds the app's puck.config, which is why this
|
|
56
|
+
* cannot live in the SDK.
|
|
57
|
+
*/
|
|
58
|
+
Client: React.ComponentType<PublishedPageClientProps>;
|
|
59
|
+
/**
|
|
60
|
+
* Rendered instead of a 404 when the backend could not be reached. A
|
|
61
|
+
* published page must not 404 over a blip — that deindexes live content — so
|
|
62
|
+
* this is a 200 holding page on a render the SDK has already made uncacheable.
|
|
63
|
+
*/
|
|
64
|
+
Unavailable: React.ComponentType;
|
|
65
|
+
/**
|
|
66
|
+
* Rendered at "/" when no home document exists. Unlike the catch-all, "/"
|
|
67
|
+
* never 404s: it is a single fixed URL rather than an unbounded crawler
|
|
68
|
+
* surface, and a welcome state is the right answer for a freshly scaffolded
|
|
69
|
+
* site — including one with no backend configured yet.
|
|
70
|
+
*/
|
|
71
|
+
Fallback: React.ComponentType;
|
|
72
|
+
/** The app's remote-datasource fetcher registry. */
|
|
73
|
+
fetchers?: RemoteDatasourceFetcher[];
|
|
74
|
+
/**
|
|
75
|
+
* Turns published page data into <head> metadata. Called only for a page that
|
|
76
|
+
* actually resolved; the miss and outage titles come from `titles`.
|
|
77
|
+
*/
|
|
78
|
+
resolveMetadata?: (args: {
|
|
79
|
+
pageData: Data;
|
|
80
|
+
path: string;
|
|
81
|
+
}) => Metadata | Promise<Metadata>;
|
|
82
|
+
titles?: {
|
|
83
|
+
/** Catch-all, no such page. Default "Not Found". */
|
|
84
|
+
notFound?: string;
|
|
85
|
+
/** Backend unreachable. Default "Temporarily unavailable". */
|
|
86
|
+
unavailable?: string;
|
|
87
|
+
/** "/" with no home document yet — pairs with `Fallback`. Default "Home". */
|
|
88
|
+
home?: string;
|
|
89
|
+
};
|
|
90
|
+
/** Extra internal path prefixes to refuse, on top of the SDK's own list. */
|
|
91
|
+
internalPathPrefixes?: readonly string[];
|
|
92
|
+
};
|
|
93
|
+
export declare function createPublishedPage(config: CreatePublishedPageConfig): {
|
|
94
|
+
Page: ({ params, }: {
|
|
95
|
+
params: Promise<{
|
|
96
|
+
puckPath: string[];
|
|
97
|
+
}>;
|
|
98
|
+
}) => Promise<import("react").JSX.Element>;
|
|
99
|
+
HomePage: () => Promise<import("react").JSX.Element>;
|
|
100
|
+
generateMetadata: ({ params, }: {
|
|
101
|
+
params: Promise<{
|
|
102
|
+
puckPath: string[];
|
|
103
|
+
}>;
|
|
104
|
+
}) => Promise<Metadata>;
|
|
105
|
+
generateHomeMetadata: () => Promise<Metadata>;
|
|
106
|
+
generateStaticParams: () => {
|
|
107
|
+
puckPath: string[];
|
|
108
|
+
}[];
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=create-published-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-published-page.d.ts","sourceRoot":"","sources":["../src/create-published-page.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAErC,OAAO,EAKL,KAAK,uBAAuB,EAC7B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAS7C;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,IAAI,CAAC;IACX,YAAY,EAAE,qBAAqB,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;OAGG;IACH,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC;IACtD;;;;OAIG;IACH,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC;IACjC;;;;;OAKG;IACH,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC;IAC9B,oDAAoD;IACpD,QAAQ,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrC;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QACvB,QAAQ,EAAE,IAAI,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE;QACP,oDAAoD;QACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,8DAA8D;QAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,6EAA6E;QAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,4EAA4E;IAC5E,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,yBAAyB;wBAuFhE;QACD,MAAM,EAAE,OAAO,CAAC;YAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAC;KACzC;;oCAZE;QACD,MAAM,EAAE,OAAO,CAAC;YAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAC;KACzC,KAAG,OAAO,CAAC,QAAQ,CAAC;gCA2BkB,OAAO,CAAC,QAAQ,CAAC;gCAnCvB;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE;EA0D1D"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cache } from "react";
|
|
3
|
+
import { notFound } from "next/navigation";
|
|
4
|
+
import { loadRemoteDatasourceContext, extractReferencedDatasourceIds, resolveDataTemplates, pagePathFromCatchAllSegments, } from "@pantheon-systems/puck-css/server";
|
|
5
|
+
import { createCssQueryFetchers } from "./css-query-fetchers";
|
|
6
|
+
import { loadPublishedPage, loadRouteTemplateKeys, } from "./published-page";
|
|
7
|
+
export function createPublishedPage(config) {
|
|
8
|
+
const { Client, Unavailable, Fallback, fetchers = [], resolveMetadata, titles, internalPathPrefixes, } = config;
|
|
9
|
+
const loadOptions = internalPathPrefixes ? { internalPathPrefixes } : undefined;
|
|
10
|
+
const getCssQueryFetchers = cache(() => createCssQueryFetchers());
|
|
11
|
+
async function resolve(path, data) {
|
|
12
|
+
const [routeTemplateKeys, cssQueryFetchers] = await Promise.all([
|
|
13
|
+
loadRouteTemplateKeys(),
|
|
14
|
+
getCssQueryFetchers(),
|
|
15
|
+
]);
|
|
16
|
+
const context = await loadRemoteDatasourceContext({
|
|
17
|
+
fetchImpl: fetch,
|
|
18
|
+
pagePath: path,
|
|
19
|
+
routeTemplateKeys,
|
|
20
|
+
builtinFetchers: [...fetchers, ...cssQueryFetchers],
|
|
21
|
+
referencedDatasourceIds: extractReferencedDatasourceIds(data),
|
|
22
|
+
});
|
|
23
|
+
return resolveDataTemplates(data, context);
|
|
24
|
+
}
|
|
25
|
+
async function render(path, data) {
|
|
26
|
+
const resolvedData = await resolve(path, data);
|
|
27
|
+
return (_jsx(Client, { data: resolvedData, pageMetadata: {
|
|
28
|
+
route: path,
|
|
29
|
+
documentName: data.root.props?.title,
|
|
30
|
+
pageType: "page",
|
|
31
|
+
} }));
|
|
32
|
+
}
|
|
33
|
+
async function metadataFor(result, path) {
|
|
34
|
+
if (result.status === "missing") {
|
|
35
|
+
return { title: titles?.notFound ?? "Not Found" };
|
|
36
|
+
}
|
|
37
|
+
if (result.status === "unavailable") {
|
|
38
|
+
return { title: titles?.unavailable ?? "Temporarily unavailable" };
|
|
39
|
+
}
|
|
40
|
+
return resolveMetadata
|
|
41
|
+
? resolveMetadata({ pageData: result.data, path })
|
|
42
|
+
: {};
|
|
43
|
+
}
|
|
44
|
+
function generateStaticParams() {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
async function generateMetadata({ params, }) {
|
|
48
|
+
const { puckPath = [] } = await params;
|
|
49
|
+
const path = pagePathFromCatchAllSegments(puckPath);
|
|
50
|
+
return metadataFor(await loadPublishedPage(path, loadOptions), path);
|
|
51
|
+
}
|
|
52
|
+
async function Page({ params, }) {
|
|
53
|
+
const { puckPath = [] } = await params;
|
|
54
|
+
const path = pagePathFromCatchAllSegments(puckPath);
|
|
55
|
+
const result = await loadPublishedPage(path, loadOptions);
|
|
56
|
+
if (result.status === "missing") {
|
|
57
|
+
notFound();
|
|
58
|
+
}
|
|
59
|
+
if (result.status === "unavailable") {
|
|
60
|
+
return _jsx(Unavailable, {});
|
|
61
|
+
}
|
|
62
|
+
return render(path, result.data);
|
|
63
|
+
}
|
|
64
|
+
async function generateHomeMetadata() {
|
|
65
|
+
const result = await loadPublishedPage("/", loadOptions);
|
|
66
|
+
if (result.status !== "ok") {
|
|
67
|
+
return { title: titles?.home ?? "Home" };
|
|
68
|
+
}
|
|
69
|
+
return metadataFor(result, "/");
|
|
70
|
+
}
|
|
71
|
+
async function HomePage() {
|
|
72
|
+
const result = await loadPublishedPage("/", loadOptions);
|
|
73
|
+
if (result.status !== "ok") {
|
|
74
|
+
return _jsx(Fallback, {});
|
|
75
|
+
}
|
|
76
|
+
return render("/", result.data);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
Page,
|
|
80
|
+
HomePage,
|
|
81
|
+
generateMetadata,
|
|
82
|
+
generateHomeMetadata,
|
|
83
|
+
generateStaticParams,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=create-published-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-published-page.js","sourceRoot":"","sources":["../src/create-published-page.tsx"],"names":[],"mappings":"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"}
|
package/dist/published-page.d.ts
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* invariants that keep public routes cacheable and correct: initialization is
|
|
6
6
|
* awaited per read so a failed cold start can recover, a miss is reported
|
|
7
7
|
* distinctly from an outage so it can become a real 404 instead of a cached
|
|
8
|
-
* 200,
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* 200, internal document namespaces are refused before they can render as
|
|
9
|
+
* public pages, and prerendering is aborted rather than baking an empty page
|
|
10
|
+
* into the build. A renderer that gets any of those wrong fails in ways that
|
|
11
|
+
* only show up under CDN caching or a backend blip.
|
|
11
12
|
*
|
|
12
13
|
* How a miss is presented — the copy, the styling, the editor links — is the
|
|
13
14
|
* app's business, and stays in the app.
|
|
@@ -30,13 +31,25 @@ export type PublishedPageResult = {
|
|
|
30
31
|
} | {
|
|
31
32
|
status: "unavailable";
|
|
32
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Options for a published-page read.
|
|
36
|
+
*/
|
|
37
|
+
export type LoadPublishedPageOptions = {
|
|
38
|
+
/**
|
|
39
|
+
* Extra path prefixes to refuse, added to the built-in list rather than
|
|
40
|
+
* replacing it. Additive on purpose: a site that needs its own internal
|
|
41
|
+
* namespace should not be able to un-block `/_registry` by supplying a
|
|
42
|
+
* shorter list.
|
|
43
|
+
*/
|
|
44
|
+
internalPathPrefixes?: readonly string[];
|
|
45
|
+
};
|
|
33
46
|
/**
|
|
34
47
|
* Published Puck data for `path`.
|
|
35
48
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
49
|
+
* Internal namespaces report `missing` without reaching the backend, so a
|
|
50
|
+
* renderer that carries no denylist of its own still 404s them.
|
|
38
51
|
*/
|
|
39
|
-
export declare
|
|
52
|
+
export declare function loadPublishedPage(path: string, options?: LoadPublishedPageOptions): Promise<PublishedPageResult>;
|
|
40
53
|
/**
|
|
41
54
|
* Collection template keys for the current render.
|
|
42
55
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"published-page.d.ts","sourceRoot":"","sources":["../src/published-page.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"published-page.d.ts","sourceRoot":"","sources":["../src/published-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AASH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAC5B;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC;AAE9B;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C,CAAC;AAuEF;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,mBAAmB,CAAC,CAK9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAmB,OAAO,CAAC,MAAM,EAAE,CAGnE,CAAC"}
|
package/dist/published-page.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { cache } from "react";
|
|
2
2
|
import { connection } from "next/server";
|
|
3
3
|
import { ensureInitialized, getPage, listRouteTemplateKeysFromDatabase, } from "@pantheon-systems/puck-css/server";
|
|
4
|
+
const INTERNAL_PATH_PREFIXES = ["/_registry", "/_redirects"];
|
|
5
|
+
function isInternalPath(path, extra) {
|
|
6
|
+
const normalized = path.toLowerCase();
|
|
7
|
+
return [...INTERNAL_PATH_PREFIXES, ...(extra ?? [])].some((prefix) => {
|
|
8
|
+
const target = prefix.toLowerCase();
|
|
9
|
+
return normalized === target || normalized.startsWith(`${target}/`);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
4
12
|
const initP1 = () => ensureInitialized({
|
|
5
13
|
p1BaseUrl: process.env.NEXT_PUBLIC_CSS_BASE_URL,
|
|
6
14
|
p1ApiKey: process.env.CSS_API_KEY,
|
|
@@ -12,7 +20,7 @@ async function unavailable(path, error) {
|
|
|
12
20
|
await connection();
|
|
13
21
|
return { status: "unavailable" };
|
|
14
22
|
}
|
|
15
|
-
|
|
23
|
+
const readPublishedPage = cache(async (path) => {
|
|
16
24
|
try {
|
|
17
25
|
await initP1();
|
|
18
26
|
const data = await getPage(path);
|
|
@@ -22,6 +30,12 @@ export const loadPublishedPage = cache(async (path) => {
|
|
|
22
30
|
return unavailable(path, error);
|
|
23
31
|
}
|
|
24
32
|
});
|
|
33
|
+
export async function loadPublishedPage(path, options) {
|
|
34
|
+
if (isInternalPath(path, options?.internalPathPrefixes)) {
|
|
35
|
+
return { status: "missing" };
|
|
36
|
+
}
|
|
37
|
+
return readPublishedPage(path);
|
|
38
|
+
}
|
|
25
39
|
export const loadRouteTemplateKeys = cache(async () => {
|
|
26
40
|
await initP1();
|
|
27
41
|
return listRouteTemplateKeysFromDatabase();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"published-page.js","sourceRoot":"","sources":["../src/published-page.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"published-page.js","sourceRoot":"","sources":["../src/published-page.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,iBAAiB,EACjB,OAAO,EACP,iCAAiC,GAClC,MAAM,mCAAmC,CAAC;AAiC3C,MAAM,sBAAsB,GAAG,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;AAO7D,SAAS,cAAc,CAAC,IAAY,EAAE,KAAyB;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACtC,OAAO,CAAC,GAAG,sBAAsB,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACnE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACpC,OAAO,UAAU,KAAK,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC;AAQD,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,iBAAiB,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB;IAC/C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;IACjC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;IAG7C,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,MAAM;CAC5D,CAAC,CAAC;AAEL,KAAK,UAAU,WAAW,CACxB,IAAY,EACZ,KAAc;IAEd,OAAO,CAAC,IAAI,CACV,mDAAmD,IAAI,GAAG,EAC1D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;IAKF,MAAM,UAAU,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACnC,CAAC;AASD,MAAM,iBAAiB,GAAG,KAAK,CAC7B,KAAK,EAAE,IAAY,EAAgC,EAAE;IACnD,IAAI,CAAC;QACH,MAAM,MAAM,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;AACH,CAAC,CACF,CAAC;AAQF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAY,EACZ,OAAkC;IAElC,IAAI,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,oBAAoB,CAAC,EAAE,CAAC;QACxD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAQD,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC,KAAK,IAAuB,EAAE;IACvE,MAAM,MAAM,EAAE,CAAC;IACf,OAAO,iCAAiC,EAAE,CAAC;AAC7C,CAAC,CAAC,CAAC"}
|
|
@@ -14,7 +14,7 @@ export declare function postRemoteDatasources(request: Request): Promise<NextRes
|
|
|
14
14
|
error: string;
|
|
15
15
|
}> | NextResponse<{
|
|
16
16
|
ok: boolean;
|
|
17
|
-
scope: "
|
|
17
|
+
scope: "page" | "global";
|
|
18
18
|
path: string;
|
|
19
19
|
id: string;
|
|
20
20
|
}>>;
|
|
@@ -23,7 +23,7 @@ export declare function deleteRemoteDatasources(request: Request): Promise<NextR
|
|
|
23
23
|
error: string;
|
|
24
24
|
}> | NextResponse<{
|
|
25
25
|
ok: boolean;
|
|
26
|
-
scope: "
|
|
26
|
+
scope: "page" | "global";
|
|
27
27
|
path: string;
|
|
28
28
|
id: string;
|
|
29
29
|
}>>;
|
package/dist/server.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export { createP1AuthHandler, type P1AuthHandlerConfig } from "./auth-handler";
|
|
|
3
3
|
export { createP1Pages, type P1PagesConfig } from "./pages-handler";
|
|
4
4
|
export { createCssQueryFetchers, type CreateCssQueryFetchersOptions } from "./css-query-fetchers";
|
|
5
5
|
export { createP1Middleware, type P1MiddlewareConfig } from "./middleware";
|
|
6
|
-
export {
|
|
6
|
+
export { createPublishedPage, type CreatePublishedPageConfig, type PublishedPageClientProps, type PublishedPageMetadata, } from "./create-published-page";
|
|
7
|
+
export { loadPublishedPage, loadRouteTemplateKeys, type LoadPublishedPageOptions, type PublishedPageResult, } from "./published-page";
|
|
7
8
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,KAAK,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,KAAK,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EACL,mBAAmB,EACnB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,GAC3B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -3,5 +3,6 @@ export { createP1AuthHandler } from "./auth-handler";
|
|
|
3
3
|
export { createP1Pages } from "./pages-handler";
|
|
4
4
|
export { createCssQueryFetchers } from "./css-query-fetchers";
|
|
5
5
|
export { createP1Middleware } from "./middleware";
|
|
6
|
+
export { createPublishedPage, } from "./create-published-page";
|
|
6
7
|
export { loadPublishedPage, loadRouteTemplateKeys, } from "./published-page";
|
|
7
8
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAwB,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAA4B,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAsB,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAsC,MAAM,sBAAsB,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAA2B,MAAM,cAAc,CAAC;AAC3E,OAAO,EACL,iBAAiB,EACjB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAwB,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAA4B,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAsB,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAsC,MAAM,sBAAsB,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAA2B,MAAM,cAAc,CAAC;AAC3E,OAAO,EACL,mBAAmB,GAIpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,GAGtB,MAAM,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pantheon-systems/p1-next-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"description": "Next.js SDK for P1 editor integration",
|
|
6
6
|
"publishConfig": {
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"server-only": "^0.0.1",
|
|
38
|
-
"@pantheon-systems/css-client": "0.
|
|
39
|
-
"@pantheon-systems/puck-css": "0.
|
|
38
|
+
"@pantheon-systems/css-client": "0.14.0",
|
|
39
|
+
"@pantheon-systems/puck-css": "0.14.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@puckeditor/core": ">=0.21.0",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@testing-library/dom": "^10.4.1",
|
|
49
49
|
"@testing-library/react": "^16.3.2",
|
|
50
|
+
"@types/node": "^20.19.30",
|
|
50
51
|
"@types/react": "^19.2.14",
|
|
51
52
|
"eslint": "^9.27.0",
|
|
52
53
|
"jsdom": "^24.1.3",
|