@pantheon-systems/create-p1-starter-kit 0.12.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.
Files changed (42) hide show
  1. package/README.md +3 -3
  2. package/lib/cli.js +122 -53
  3. package/lib/cli.test.js +55 -0
  4. package/lib/copy-template.js +37 -0
  5. package/lib/copy-template.test.js +42 -1
  6. package/lib/messages.js +1 -1
  7. package/package.json +7 -4
  8. package/template/README.md +82 -0
  9. package/template/__tests__/auth-route.test.ts +1 -1
  10. package/template/__tests__/chatbot-flag-context.test.ts +55 -0
  11. package/template/__tests__/data-list-block-sub-components.test.tsx +246 -0
  12. package/template/__tests__/data-list-block-utils.test.ts +84 -0
  13. package/template/__tests__/data-list-block.test.ts +198 -0
  14. package/template/__tests__/published-page-routes.test.ts +86 -0
  15. package/template/__tests__/seo-metadata.test.ts +1 -1
  16. package/template/__tests__/styles-canvas-scope.test.ts +1 -1
  17. package/template/__tests__/widget-logout.test.ts +114 -0
  18. package/template/app/[...puckPath]/client.tsx +38 -10
  19. package/template/app/[...puckPath]/page.tsx +10 -117
  20. package/template/app/[...puckPath]/widget-logout.ts +36 -0
  21. package/template/app/p1/(editor)/[[...p1]]/editor-client.tsx +33 -140
  22. package/template/app/page.tsx +11 -69
  23. package/template/app/published-pages.tsx +23 -0
  24. package/template/app/styles.css +1 -1
  25. package/template/app/welcome-block.tsx +25 -0
  26. package/template/ci-examples/github-actions-sync-puck-registry.yml +15 -7
  27. package/template/components/ChatbotFlagProvider.tsx +3 -8
  28. package/template/components/p1-lockup.tsx +2 -1
  29. package/template/components/puck/image-block.tsx +5 -2
  30. package/template/components/puck/welcome-block-render.tsx +30 -37
  31. package/template/components/welcome-block.module.css +124 -0
  32. package/template/eslint.config.js +72 -1
  33. package/template/gitignore +43 -0
  34. package/template/lib/chatbot-flag/ai-generate.ts +1 -1
  35. package/template/lib/chatbot-flag/flag-context.ts +32 -0
  36. package/template/lib/page-seo.ts +1 -1
  37. package/template/package.json +5 -5
  38. package/template/scripts/__tests__/sync-puck-registry.test.ts +3 -3
  39. package/template/scripts/sync-puck-registry.ts +18 -18
  40. package/template/vitest.config.ts +17 -20
  41. package/template/CHANGELOG.md +0 -76
  42. package/template/__tests__/published-page-404.test.ts +0 -65
@@ -37,7 +37,7 @@ const carriesTemplate = (value: unknown): value is string =>
37
37
  typeof value === "string" && value.includes("{{");
38
38
 
39
39
  /**
40
- * Produces the per-page <head> Metadata for a route (PCC-3407). Title,
40
+ * Produces the per-page <head> Metadata for a route. Title,
41
41
  * description and the free-text metadata fields are template-allowed.
42
42
  */
43
43
  export async function resolvePageMetadata({
@@ -15,12 +15,12 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@pantheon-systems/cpub-react-sdk": "^5.2.1",
18
- "@pantheon-systems/css-client": "^0.12.0",
19
- "@pantheon-systems/p1-ai-chat": "^0.5.1",
20
- "@pantheon-systems/p1-media": "^0.4.4",
21
- "@pantheon-systems/p1-next-sdk": "^0.12.0",
18
+ "@pantheon-systems/css-client": "^0.14.0",
19
+ "@pantheon-systems/p1-ai-chat": "^0.6.0",
20
+ "@pantheon-systems/p1-media": "^0.4.5",
21
+ "@pantheon-systems/p1-next-sdk": "^0.14.0",
22
22
  "@pantheon-systems/pds-toolkit-react": "2.0.0-alpha.66",
23
- "@pantheon-systems/puck-css": "^0.12.0",
23
+ "@pantheon-systems/puck-css": "^0.14.0",
24
24
  "@puckeditor/core": "^0.21.1",
25
25
  "@tailwindcss/postcss": "^4.2.2",
26
26
  "@tailwindcss/typography": "^0.5.16",
@@ -56,7 +56,7 @@ describe("validateEnv", () => {
56
56
  });
57
57
 
58
58
  it("defaults defaultBranchName to 'main' when CSS_DEFAULT_BRANCH is not set", () => {
59
- // Safe because the CSS main content branch is always literally named
59
+ // Safe because the site's main content branch is always literally named
60
60
  // "main": a push override of "main" resolves to the same branch either
61
61
  // by name match or by isMain, so the default only adds semantics.
62
62
  const result = validateEnv(baseEnv());
@@ -145,8 +145,8 @@ describe("resolveBranchId", () => {
145
145
 
146
146
  describe("resolveBranchId default-branch semantics", () => {
147
147
  // In CI the override is always the pushed git ref's name, so a repo whose
148
- // default branch is not literally named "main" would never match the CSS
149
- // main branch (whose name is always "main") — the sync silently skips on
148
+ // default branch is not literally named "main" would never match the
149
+ // site's main branch (whose name is always "main") — the sync silently skips on
150
150
  // every default-branch push. When the caller also supplies the repo's
151
151
  // default branch name, an override equal to it must resolve via isMain.
152
152
  const branches = [
@@ -2,23 +2,23 @@
2
2
  * Syncs this site's Puck component registry (_registry/components/* and the
3
3
  * registry index) headlessly, without opening the editor in a browser.
4
4
  * Intended to run from CI on push to main or a branch whose name matches a
5
- * CSS branch, whenever puck.config.tsx or components/puck/** change.
5
+ * branch on the site, whenever puck.config.tsx or components/puck/** change.
6
6
  *
7
7
  * Usage: tsx scripts/sync-puck-registry.ts [--dry-run]
8
8
  *
9
9
  * Required env vars (see validateEnv below for the full fallback contract):
10
10
  * CSS_BASE_URL, CSS_SITE_ID, CSS_REGISTRY_API_KEY
11
11
  * Optional:
12
- * CSS_BRANCH_ID — CSS branch to target (in CI: the pushed git ref's name)
12
+ * CSS_BRANCH_ID — branch to target (in CI: the pushed git ref's name)
13
13
  * CSS_DEFAULT_BRANCH — the repo's default branch name (defaults to "main");
14
14
  * when CSS_BRANCH_ID equals it, the site's isMain branch is targeted
15
15
  * regardless of naming (see resolveBranchId for the resolution contract)
16
16
  *
17
17
  * CSS_REGISTRY_API_KEY must be a sat_ site token scoped to write:registry
18
18
  * only — do not reuse a read-scoped token (P1_CSS_API_KEY). Because that
19
- * token has no read access at all, every run rewrites every component
20
- * descriptor + the registry index unconditionally (no skip-if-unchanged)
21
- * see syncComponentRegistryWriteOnly.
19
+ * token has no read access at all, every run posts every component
20
+ * descriptor + the registry index; the backend compares each against stored
21
+ * content and writes only what changed — see syncComponentRegistryWriteOnly.
22
22
  */
23
23
 
24
24
  import { register } from "node:module";
@@ -43,7 +43,7 @@ export function validateEnv(env: Record<string, string | undefined>): ValidatedE
43
43
  const siteId = env.CSS_SITE_ID ?? env.NEXT_PUBLIC_CSS_SITE_ID;
44
44
  const apiKey = env.CSS_REGISTRY_API_KEY;
45
45
  const branchOverride = env.CSS_BRANCH_ID ?? env.NEXT_PUBLIC_CSS_BRANCH_ID;
46
- // Defaults to "main": the CSS main content branch is always literally
46
+ // Defaults to "main": the site's main content branch is always literally
47
47
  // named "main", so for repos whose default git branch is also "main" this
48
48
  // resolves to the same branch it would have matched by name. Repos with a
49
49
  // differently-named default branch (master, trunk) must set it explicitly.
@@ -88,10 +88,10 @@ export function resolveConfigModule(mod: unknown): unknown {
88
88
  }
89
89
 
90
90
  /**
91
- * Thrown by resolveBranchId when no CSS branch matches. Distinguished from
92
- * other errors so callers (main(), a CI trigger firing on every git branch)
93
- * can treat "this branch has no CSS counterpart" as a benign no-op rather
94
- * than a real sync failure.
91
+ * Thrown by resolveBranchId when no matching branch is found. Distinguished
92
+ * from other errors so callers (main(), a CI trigger firing on every git
93
+ * branch) can treat "this branch has no counterpart on the site" as a benign
94
+ * no-op rather than a real sync failure.
95
95
  */
96
96
  export class NoBranchMatchError extends Error {}
97
97
 
@@ -133,12 +133,12 @@ export function filterAssetStubbedDescriptors(descriptors: Descriptor[]): {
133
133
 
134
134
  /**
135
135
  * Resolution contract: an override (in CI, always the pushed git ref's name)
136
- * matches a CSS branch by id or name — EXCEPT when it equals the repo's
137
- * default branch name, which always resolves the site's isMain branch. CSS
138
- * main is always literally named "main", so without that rule a repo whose
139
- * default branch is "master"/"trunk" would silently skip on every push. The
140
- * default branch means the main registry, even over a coincidental CSS
141
- * branch named e.g. "master".
136
+ * matches a branch on the site by id or name — EXCEPT when it equals the
137
+ * repo's default branch name, which always resolves the site's isMain
138
+ * branch. The site's main branch is always literally named "main", so
139
+ * without that rule a repo whose default branch is "master"/"trunk" would
140
+ * silently skip on every push. The default branch means the main registry,
141
+ * even over a coincidentally-named branch on the site, e.g. "master".
142
142
  */
143
143
  export function resolveBranchId(
144
144
  branches: Branch[],
@@ -211,8 +211,8 @@ const isMainModule = import.meta.url === pathToFileURL(process.argv[1] ?? "").hr
211
211
  if (isMainModule) {
212
212
  main().catch((err: unknown) => {
213
213
  // A CI trigger firing on every git branch push has no way to know ahead
214
- // of time which branches have a matching CSS branch — that has to be
215
- // discovered at runtime. Treat "no match" as a benign no-op, not a
214
+ // of time which branches have a matching branch on the site — that has
215
+ // to be discovered at runtime. Treat "no match" as a benign no-op, not a
216
216
  // failure, so unrelated feature-branch pushes don't turn CI red.
217
217
  if (err instanceof NoBranchMatchError) {
218
218
  console.log(`[sync-puck-registry] Skipping: ${err.message}`);
@@ -1,30 +1,27 @@
1
- import { resolve } from "path";
2
1
  import { defineConfig } from "vitest/config";
3
2
  import react from "@vitejs/plugin-react";
4
3
 
5
4
  export default defineConfig({
6
5
  plugins: [react()],
7
- resolve: {
8
- alias: {
9
- "@pantheon-systems/puck-css/fields": resolve(
10
- __dirname,
11
- "../..",
12
- "packages/puck-css/src/data/fields.tsx",
13
- ),
14
- "@pantheon-systems/pds-toolkit-react": resolve(
15
- __dirname,
16
- "../..",
17
- "packages/puck-css/src/__mocks__/@pantheon-systems/pds-toolkit-react.ts",
18
- ),
19
- "@puckeditor/core": resolve(
20
- __dirname,
21
- "../..",
22
- "packages/puck-css/src/__mocks__/@puckeditor/core.ts",
23
- ),
24
- },
25
- },
26
6
  test: {
27
7
  environment: "node",
8
+ // Inlining below means the first test to import puck-css pays for Vite
9
+ // transforming that whole graph — seconds on a cold machine, and the default
10
+ // 5s timeout fails it on slower CI runners while every later test in the file
11
+ // runs in milliseconds.
12
+ testTimeout: 30_000,
13
+ server: {
14
+ deps: {
15
+ // pds-toolkit-react's entry point imports its own dist/index.css, and
16
+ // puck-css imports pds-toolkit-react. Left external, vitest hands that
17
+ // chain to Node's ESM loader, which has no loader for .css; inlining
18
+ // routes it through Vite instead. Both must be listed — inlining only the
19
+ // leaf leaves puck-css external, and Node then loads the whole subtree
20
+ // without consulting this list. The patterns match a resolved path, so
21
+ // they allow pnpm's `@pantheon-systems+puck-css` directory form too.
22
+ inline: [/@pantheon-systems[/+]puck-css/, /@pantheon-systems[/+]pds-toolkit-react/],
23
+ },
24
+ },
28
25
  typecheck: {
29
26
  tsconfig: "./tsconfig.test.json",
30
27
  },
@@ -1,76 +0,0 @@
1
- # @pantheon-systems/p1-starter
2
-
3
- ## 1.0.7
4
-
5
- ### Patch Changes
6
-
7
- - Updated dependencies
8
- - Updated dependencies
9
- - Updated dependencies
10
- - Updated dependencies [3ed945e]
11
- - Updated dependencies
12
- - Updated dependencies
13
- - Updated dependencies
14
- - Updated dependencies
15
- - Updated dependencies
16
- - Updated dependencies
17
- - Updated dependencies
18
- - Updated dependencies
19
- - @pantheon-systems/puck-css@0.8.0
20
- - @pantheon-systems/p1-next-sdk@0.8.0
21
- - @pantheon-systems/css-client@0.8.0
22
-
23
- ## 1.0.6
24
-
25
- ### Patch Changes
26
-
27
- - Updated dependencies [b0254ff]
28
- - Updated dependencies
29
- - Updated dependencies [e937842]
30
- - Updated dependencies [e937842]
31
- - @pantheon-systems/puck-css@0.7.0
32
- - @pantheon-systems/css-client@0.7.0
33
- - @pantheon-systems/p1-next-sdk@0.7.0
34
-
35
- ## 1.0.5
36
-
37
- ### Patch Changes
38
-
39
- - @pantheon-systems/puck-css@0.6.0
40
- - @pantheon-systems/p1-next-sdk@0.6.0
41
-
42
- ## 1.0.4
43
-
44
- ### Patch Changes
45
-
46
- - Updated dependencies [0bc7982]
47
- - @pantheon-systems/puck-css@0.5.0
48
- - @pantheon-systems/p1-next-sdk@0.5.0
49
-
50
- ## 1.0.3
51
-
52
- ### Patch Changes
53
-
54
- - Updated dependencies
55
- - @pantheon-systems/puck-css@0.4.4
56
- - @pantheon-systems/p1-next-sdk@0.4.4
57
- - @pantheon-systems/css-client@0.4.4
58
-
59
- ## 1.0.2
60
-
61
- ### Patch Changes
62
-
63
- - Updated dependencies
64
- - @pantheon-systems/puck-css@0.4.3
65
- - @pantheon-systems/p1-next-sdk@0.4.3
66
- - @pantheon-systems/css-client@0.4.3
67
-
68
- ## 1.0.1
69
-
70
- ### Patch Changes
71
-
72
- - Updated dependencies [6650602]
73
- - Updated dependencies [dc7cfd7]
74
- - @pantheon-systems/puck-css@0.4.2
75
- - @pantheon-systems/css-client@0.4.2
76
- - @pantheon-systems/p1-next-sdk@0.4.2
@@ -1,65 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
-
3
- const { loadPublishedPage, notFound } = vi.hoisted(() => ({
4
- loadPublishedPage: vi.fn(),
5
- notFound: vi.fn(() => {
6
- throw new Error("NEXT_NOT_FOUND");
7
- }),
8
- }));
9
-
10
- vi.mock("@pantheon-systems/p1-next-sdk/server", () => ({
11
- loadPublishedPage,
12
- loadRouteTemplateKeys: vi.fn().mockResolvedValue([]),
13
- createCssQueryFetchers: vi.fn().mockReturnValue([]),
14
- }));
15
-
16
- vi.mock("next/navigation", () => ({ notFound }));
17
-
18
- vi.mock("@pantheon-systems/puck-css/server", () => ({
19
- pagePathFromCatchAllSegments: (segments: string[]) => `/${segments.join("/")}`,
20
- loadRemoteDatasourceContext: vi.fn().mockResolvedValue({}),
21
- extractReferencedDatasourceIds: vi.fn().mockReturnValue([]),
22
- resolveDataTemplates: vi.fn(async (d: unknown) => d),
23
- }));
24
-
25
- vi.mock("../lib/remote-datasource-fetchers", () => ({
26
- REMOTE_DATASOURCE_FETCHERS: [],
27
- }));
28
-
29
- vi.mock("../app/[...puckPath]/client", () => ({ Client: () => null }));
30
- vi.mock("../components/content-unavailable", () => ({
31
- ContentUnavailable: () => null,
32
- }));
33
-
34
- import Page from "../app/[...puckPath]/page";
35
-
36
- const render = (...segments: string[]) =>
37
- Page({ params: Promise.resolve({ puckPath: segments }) });
38
-
39
- describe("catch-all route — missing vs unavailable", () => {
40
- beforeEach(() => vi.clearAllMocks());
41
-
42
- // The route is statically renderable, so a 200 here would write every junk URL
43
- // a crawler probes into the response cache as a successful page.
44
- it("404s a path with no published page", async () => {
45
- loadPublishedPage.mockResolvedValue({ status: "missing" });
46
- await expect(render("nope")).rejects.toThrow("NEXT_NOT_FOUND");
47
- expect(notFound).toHaveBeenCalled();
48
- });
49
-
50
- // 404ing here would deindex a live page over a transient backend blip.
51
- it("does not 404 when the backend is unreachable", async () => {
52
- loadPublishedPage.mockResolvedValue({ status: "unavailable" });
53
- await render("real-page");
54
- expect(notFound).not.toHaveBeenCalled();
55
- });
56
-
57
- it("renders published content", async () => {
58
- loadPublishedPage.mockResolvedValue({
59
- status: "ok",
60
- data: { root: { props: { title: "Hi" } }, content: [] },
61
- });
62
- await render("blog");
63
- expect(notFound).not.toHaveBeenCalled();
64
- });
65
- });