canopycms-next 0.0.61 → 0.0.63

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/client.d.ts CHANGED
@@ -1,8 +1,16 @@
1
- import type { CanopyClientConfig } from 'canopycms/client';
1
+ import type { CanopyClientConfig, CustomFieldRenderers } from 'canopycms/client';
2
2
  /**
3
3
  * Next.js-specific wrapper for CanopyEditorPage that automatically reads
4
4
  * URL search params (branch, entry) using Next.js's useSearchParams hook.
5
5
  *
6
+ * @param customRenderers Optional per-field-type render overrides, forwarded
7
+ * to `CanopyEditorPage`. Forwarded rather than dropped for a specific reason:
8
+ * Next is the primary target, so this wrapper is the entrypoint adopters
9
+ * actually import (it is what the README's Quick Start scaffolds). Accepting
10
+ * the argument only on the core `CanopyEditorPage` made the extension point
11
+ * unreachable from the path every adopter uses, which is an extension point
12
+ * in name only.
13
+ *
6
14
  * @example
7
15
  * ```tsx
8
16
  * // app/edit/page.tsx
@@ -17,5 +25,5 @@ import type { CanopyClientConfig } from 'canopycms/client';
17
25
  * }
18
26
  * ```
19
27
  */
20
- export declare const NextCanopyEditorPage: (config: CanopyClientConfig) => () => import("react/jsx-runtime").JSX.Element;
28
+ export declare const NextCanopyEditorPage: (config: CanopyClientConfig, customRenderers?: CustomFieldRenderers) => () => import("react/jsx-runtime").JSX.Element;
21
29
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,kBAAkB,kDAuB9D,CAAA"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,kBAAkB,EAC1B,kBAAkB,oBAAoB,kDAwBvC,CAAA"}
package/dist/client.js CHANGED
@@ -7,6 +7,14 @@ import { CanopyEditorPage } from 'canopycms/client';
7
7
  * Next.js-specific wrapper for CanopyEditorPage that automatically reads
8
8
  * URL search params (branch, entry) using Next.js's useSearchParams hook.
9
9
  *
10
+ * @param customRenderers Optional per-field-type render overrides, forwarded
11
+ * to `CanopyEditorPage`. Forwarded rather than dropped for a specific reason:
12
+ * Next is the primary target, so this wrapper is the entrypoint adopters
13
+ * actually import (it is what the README's Quick Start scaffolds). Accepting
14
+ * the argument only on the core `CanopyEditorPage` made the extension point
15
+ * unreachable from the path every adopter uses, which is an extension point
16
+ * in name only.
17
+ *
10
18
  * @example
11
19
  * ```tsx
12
20
  * // app/edit/page.tsx
@@ -21,8 +29,8 @@ import { CanopyEditorPage } from 'canopycms/client';
21
29
  * }
22
30
  * ```
23
31
  */
24
- export const NextCanopyEditorPage = (config) => {
25
- const CorePage = CanopyEditorPage(config);
32
+ export const NextCanopyEditorPage = (config, customRenderers) => {
33
+ const CorePage = CanopyEditorPage(config, customRenderers);
26
34
  // Reads URL search params. Next.js 15 requires useSearchParams() consumers to
27
35
  // sit under a <Suspense> boundary, otherwise static rendering errors with
28
36
  // "useSearchParams() should be wrapped in a suspense boundary". We provide the
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGnD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAA0B,EAAE,EAAE;IACjE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAEzC,8EAA8E;IAC9E,0EAA0E;IAC1E,+EAA+E;IAC/E,4EAA4E;IAC5E,SAAS,sBAAsB;QAC7B,MAAM,eAAe,GAAG,eAAe,EAAE,CAAA;QACzC,MAAM,YAAY,GAAG;YACnB,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,SAAS;YAClD,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS;SACjD,CAAA;QACD,OAAO,KAAC,QAAQ,IAAC,YAAY,EAAE,YAAY,GAAI,CAAA;IACjD,CAAC;IAED,OAAO,SAAS,cAAc;QAC5B,OAAO,CACL,KAAC,QAAQ,IAAC,QAAQ,EAAE,IAAI,YACtB,KAAC,sBAAsB,KAAG,GACjB,CACZ,CAAA;IACH,CAAC,CAAA;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGnD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,MAA0B,EAC1B,eAAsC,EACtC,EAAE;IACF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IAE1D,8EAA8E;IAC9E,0EAA0E;IAC1E,+EAA+E;IAC/E,4EAA4E;IAC5E,SAAS,sBAAsB;QAC7B,MAAM,eAAe,GAAG,eAAe,EAAE,CAAA;QACzC,MAAM,YAAY,GAAG;YACnB,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,SAAS;YAClD,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS;SACjD,CAAA;QACD,OAAO,KAAC,QAAQ,IAAC,YAAY,EAAE,YAAY,GAAI,CAAA;IACjD,CAAC;IAED,OAAO,SAAS,cAAc;QAC5B,OAAO,CACL,KAAC,QAAQ,IAAC,QAAQ,EAAE,IAAI,YACtB,KAAC,sBAAsB,KAAG,GACjB,CACZ,CAAA;IACH,CAAC,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../src/client.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ // Mocked so this stays a node-environment test: the factory under test calls
3
+ // CanopyEditorPage at CALL time (not render time), so asserting what it was
4
+ // handed needs no DOM, no jsdom and no testing-library.
5
+ const canopyEditorPage = vi.fn(() => () => null);
6
+ vi.mock('canopycms/client', () => ({
7
+ CanopyEditorPage: (...args) => canopyEditorPage(...args),
8
+ }));
9
+ vi.mock('next/navigation', () => ({ useSearchParams: () => new URLSearchParams() }));
10
+ const { NextCanopyEditorPage } = await import('./client');
11
+ const config = { apiBase: '/api/canopycms' };
12
+ describe('NextCanopyEditorPage', () => {
13
+ it('forwards customRenderers to CanopyEditorPage', () => {
14
+ // Next is the primary target, so this wrapper is the entrypoint adopters
15
+ // import. Accepting `customRenderers` only on the core CanopyEditorPage
16
+ // left the extension point unreachable from the path every adopter uses
17
+ // - and silently, since an ignored extra argument is not a type error at
18
+ // the call site.
19
+ const customRenderers = { number: () => null };
20
+ NextCanopyEditorPage(config, customRenderers);
21
+ expect(canopyEditorPage).toHaveBeenCalledWith(config, customRenderers);
22
+ });
23
+ it('still works with no customRenderers (the scaffolded call shape)', () => {
24
+ canopyEditorPage.mockClear();
25
+ NextCanopyEditorPage(config);
26
+ expect(canopyEditorPage).toHaveBeenCalledWith(config, undefined);
27
+ });
28
+ });
29
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../src/client.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAEjD,6EAA6E;AAC7E,4EAA4E;AAC5E,wDAAwD;AACxD,MAAM,gBAAgB,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;AAChD,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,gBAAgB,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAI,IAAW,CAAC;CAC5E,CAAC,CAAC,CAAA;AACH,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,EAAE,EAAE,CAAC,CAAC,CAAA;AAEpF,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAA;AAEzD,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,gBAAgB,EAAW,CAAA;AAErD,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,yEAAyE;QACzE,wEAAwE;QACxE,wEAAwE;QACxE,yEAAyE;QACzE,iBAAiB;QACjB,MAAM,eAAe,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAA;QAE9C,oBAAoB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;QAE7C,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,gBAAgB,CAAC,SAAS,EAAE,CAAA;QAE5B,oBAAoB,CAAC,MAAM,CAAC,CAAA;QAE5B,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAClE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,12 +1,43 @@
1
- import { type CanopyContext, type CanopyBuildContext, type CanopyServices } from 'canopycms/server';
1
+ import { type CanopyContext, type CanopyBuildContext, type CanopyServices, type SeoFieldLocation } from 'canopycms/server';
2
2
  import type { CanopyConfig, AuthPlugin, FieldConfig } from 'canopycms';
3
+ import type { Metadata, MetadataRoute } from 'next';
3
4
  import { createCanopyCatchAllHandler } from './adapter';
4
- import { type GenerateContentStaticParamsOptions } from './static';
5
+ import { type EntryToMetadataOptions, type GenerateContentSitemapOptions, type GenerateContentStaticParamsOptions } from './static';
6
+ /**
7
+ * Merge a context-wide default SEO field location (`createNextCanopyContext({ seo })`) with a
8
+ * per-call override.
9
+ *
10
+ * `generateContentSitemap`'s `noindex` exclusion and `entryToMetadata`'s field extraction/`noindex`
11
+ * read must agree on where the SEO fields live, or the two surfaces drift: an entry can end up
12
+ * `noindex` on the page while the sitemap still advertises its URL (or the reverse), because each
13
+ * call site independently forgot (or mis-set) `group`/`fields`. Both bound helpers below call this
14
+ * SAME function with the SAME context-wide default, which is what makes agreement structural
15
+ * rather than a matter of adopter discipline.
16
+ *
17
+ * Only keys the caller actually supplies override the default — an omitted (or explicitly
18
+ * `undefined`) `fields`/`group` falls through to the context-wide value, so setting a default once
19
+ * and never repeating it per call is the common case. A plain `{ ...contextDefault, ...callOverride
20
+ * }` would NOT have this property: `entryToMetadata`'s options type always has `fields`/`group`
21
+ * keys, so a caller who omits them still produces an object whose `fields`/`group` are present but
22
+ * `undefined`, and spreading that would silently clobber the default. Checking each key explicitly
23
+ * avoids that trap. Exported for direct unit testing.
24
+ */
25
+ export declare function mergeSeoFieldLocation(contextDefault: SeoFieldLocation | undefined, callOverride: SeoFieldLocation | undefined): SeoFieldLocation;
5
26
  export interface NextCanopyOptions {
6
27
  config: CanopyConfig;
7
28
  /** Auth plugin for user authentication. Optional for static deployments (deployedAs: 'static'). */
8
29
  authPlugin?: AuthPlugin;
9
30
  entrySchemaRegistry: Record<string, readonly FieldConfig[]>;
31
+ /**
32
+ * Where the SEO fields live (`fields` name overrides, and/or a nested `group`). Set once here
33
+ * and it is shared by BOTH the returned `generateContentSitemap`'s `noindex` exclusion and the
34
+ * returned `entryToMetadata`'s field extraction, so the two surfaces cannot independently forget
35
+ * or mis-set it and drift apart — see `mergeSeoFieldLocation`. Omit for the flat (inline-group)
36
+ * convention, which is the default on both the schema side (`defineSeoFieldGroup()`) and here.
37
+ * A per-call `seo`/`fields`/`group` option on either helper still overrides this default for
38
+ * that one call.
39
+ */
40
+ seo?: SeoFieldLocation;
10
41
  }
11
42
  /**
12
43
  * Wrap a build context so its operations throw if misused at request time on a production server.
@@ -55,6 +86,25 @@ export interface NextCanopyContextResult {
55
86
  readByUrlPath: CanopyContext['readByUrlPath'];
56
87
  /** Phase-selecting `read` (build context at build, runtime context at request) — counterpart to readByUrlPath. */
57
88
  read: CanopyContext['read'];
89
+ /**
90
+ * Phase-selecting `listEntries` — every entry under `rootPath` in a single filesystem
91
+ * pass, each with its `urlPath`, `slug`, `entryType`, `data` and `schema`. Use it instead
92
+ * of "enumerate paths, then read each one", which is an N+1 over the content tree and
93
+ * invites URL-reconstruction bugs; the returned `urlPath` round-trips through
94
+ * `readByUrlPath` by construction, including for multi-segment paths.
95
+ *
96
+ * ```ts
97
+ * const articles = await listEntries<ArticleContent>({
98
+ * filter: (e) => e.entryType === 'article',
99
+ * })
100
+ * ```
101
+ *
102
+ * At build time this reads filesystem-direct; at request time it uses the branch-aware,
103
+ * **ACL-enforced** runtime context, so entries the current user cannot read are omitted.
104
+ * Note it takes no `branch` option — see `CanopyContext['listEntries']` for the
105
+ * base-branch pinning caveat in prod.
106
+ */
107
+ listEntries: CanopyContext['listEntries'];
58
108
  /**
59
109
  * Build the array Next's `generateStaticParams` expects from CanopyCMS content. Enumeration-only
60
110
  * (reads the set of routable paths, never entry content) and closes over the build context, so your
@@ -62,6 +112,28 @@ export interface NextCanopyContextResult {
62
112
  * `[slug]` route, or the default catch-all for `[...slug]`.
63
113
  */
64
114
  generateContentStaticParams: (options?: GenerateContentStaticParamsOptions) => Promise<Array<Record<string, string | string[]>>>;
115
+ /**
116
+ * Build `app/sitemap.ts`'s `MetadataRoute.Sitemap` from CanopyCMS content. Includes EVERY
117
+ * routable entry type by default and excludes `noindex` entries through the same predicate
118
+ * `entryToMetadata` uses for `robots`. Bound to the build context, so your `sitemap.ts` never
119
+ * imports the admin `getCanopyForBuild`.
120
+ *
121
+ * Reads the SEO field location from `createNextCanopyContext({ seo })` by default (shared with
122
+ * `entryToMetadata` below via `mergeSeoFieldLocation` — see that function's doc). Pass `seo` on a
123
+ * given call to override just that call.
124
+ */
125
+ generateContentSitemap: (options: GenerateContentSitemapOptions) => Promise<MetadataRoute.Sitemap>;
126
+ /**
127
+ * Map an entry's SEO fields onto a Next `Metadata` for `generateMetadata`. Re-exposed here so a
128
+ * page module has one CanopyCMS import (your `lib/canopy.ts`) rather than two.
129
+ *
130
+ * Reads the SAME SEO field location as `generateContentSitemap` above by default (the
131
+ * `createNextCanopyContext({ seo })` value); the two are bound from one context-wide default so
132
+ * they cannot silently disagree about where `noindex` (or a renamed field) lives. Pass
133
+ * `fields`/`group` on a given call to override just that call. This is a pure
134
+ * mapping and touches no context.
135
+ */
136
+ entryToMetadata: (entryData: unknown, options?: EntryToMetadataOptions) => Metadata;
65
137
  /** API catch-all route handler */
66
138
  handler: ReturnType<typeof createCanopyCatchAllHandler>;
67
139
  /** Underlying services (rarely needed directly) */
@@ -1 +1 @@
1
- {"version":3,"file":"context-wrapper.d.ts","sourceRoot":"","sources":["../src/context-wrapper.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAYpB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAc,WAAW,EAAE,MAAM,WAAW,CAAA;AAKlF,OAAO,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAA;AACvD,OAAO,EAAuB,KAAK,kCAAkC,EAAE,MAAM,UAAU,CAAA;AAkCvF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAA;IACpB,mGAAmG;IACnG,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC,CAAA;CAC5D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,YAAY,GACnB,kBAAkB,CA4CpB;AAED,MAAM,WAAW,uBAAuB;IACtC,8GAA8G;IAC9G,SAAS,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACvC;;;;;;;;;;;;;OAaG;IACH,iBAAiB,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACpD;;;;;;;OAOG;IACH,aAAa,EAAE,aAAa,CAAC,eAAe,CAAC,CAAA;IAC7C,kHAAkH;IAClH,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC3B;;;;;OAKG;IACH,2BAA2B,EAAE,CAC3B,OAAO,CAAC,EAAE,kCAAkC,KACzC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAAA;IACtD,kCAAkC;IAClC,OAAO,EAAE,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAA;IACvD,mDAAmD;IACnD,QAAQ,EAAE,cAAc,CAAA;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CA4LlC"}
1
+ {"version":3,"file":"context-wrapper.d.ts","sourceRoot":"","sources":["../src/context-wrapper.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAMnB,KAAK,gBAAgB,EAMtB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAc,WAAW,EAAE,MAAM,WAAW,CAAA;AAGlF,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AACnD,OAAO,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAA;AACvD,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,KAAK,kCAAkC,EACxC,MAAM,UAAU,CAAA;AAEjB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,gBAAgB,GAAG,SAAS,EAC5C,YAAY,EAAE,gBAAgB,GAAG,SAAS,GACzC,gBAAgB,CAKlB;AAiCD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAA;IACpB,mGAAmG;IACnG,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC,CAAA;IAC3D;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,gBAAgB,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,YAAY,GACnB,kBAAkB,CA4CpB;AAED,MAAM,WAAW,uBAAuB;IACtC,8GAA8G;IAC9G,SAAS,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACvC;;;;;;;;;;;;;OAaG;IACH,iBAAiB,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACpD;;;;;;;OAOG;IACH,aAAa,EAAE,aAAa,CAAC,eAAe,CAAC,CAAA;IAC7C,kHAAkH;IAClH,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC3B;;;;;;;;;;;;;;;;;OAiBG;IACH,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IACzC;;;;;OAKG;IACH,2BAA2B,EAAE,CAC3B,OAAO,CAAC,EAAE,kCAAkC,KACzC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAAA;IACtD;;;;;;;;;OASG;IACH,sBAAsB,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IAClG;;;;;;;;;OASG;IACH,eAAe,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,sBAAsB,KAAK,QAAQ,CAAA;IACnF,kCAAkC;IAClC,OAAO,EAAE,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAA;IACvD,mDAAmD;IACnD,QAAQ,EAAE,cAAc,CAAA;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAqNlC"}
@@ -1,13 +1,38 @@
1
1
  import path from 'node:path';
2
2
  import { cache } from 'react';
3
3
  import { headers } from 'next/headers';
4
- import { createCanopyContext, isBuildMode, startDevContentWatcher, createCanopyServices, createAssetStore, operatingStrategy, loadInternalGroups, loadBranchContext, STATIC_DEPLOY_USER, } from 'canopycms/server';
5
- import { authResultToCanopyUser } from 'canopycms';
4
+ import { createCanopyContext, isBuildMode, startDevContentWatcher, createCanopyServices, createAssetStore, operatingStrategy, resolveCanopyUser, STATIC_DEPLOY_USER, } from 'canopycms/server';
6
5
  import { assertAuthPluginAllowedForMode } from 'canopycms/auth';
7
6
  import { CachingAuthPlugin, FileBasedAuthCache } from 'canopycms/auth/cache';
8
7
  import { createCanopyCatchAllHandler } from './adapter';
9
- import { collectStaticParams } from './static';
10
- let warnedNoAdmins = false;
8
+ import { collectStaticParams, entryToMetadata as entryToMetadataCore, generateContentSitemap, } from './static';
9
+ /**
10
+ * Merge a context-wide default SEO field location (`createNextCanopyContext({ seo })`) with a
11
+ * per-call override.
12
+ *
13
+ * `generateContentSitemap`'s `noindex` exclusion and `entryToMetadata`'s field extraction/`noindex`
14
+ * read must agree on where the SEO fields live, or the two surfaces drift: an entry can end up
15
+ * `noindex` on the page while the sitemap still advertises its URL (or the reverse), because each
16
+ * call site independently forgot (or mis-set) `group`/`fields`. Both bound helpers below call this
17
+ * SAME function with the SAME context-wide default, which is what makes agreement structural
18
+ * rather than a matter of adopter discipline.
19
+ *
20
+ * Only keys the caller actually supplies override the default — an omitted (or explicitly
21
+ * `undefined`) `fields`/`group` falls through to the context-wide value, so setting a default once
22
+ * and never repeating it per call is the common case. A plain `{ ...contextDefault, ...callOverride
23
+ * }` would NOT have this property: `entryToMetadata`'s options type always has `fields`/`group`
24
+ * keys, so a caller who omits them still produces an object whose `fields`/`group` are present but
25
+ * `undefined`, and spreading that would silently clobber the default. Checking each key explicitly
26
+ * avoids that trap. Exported for direct unit testing.
27
+ */
28
+ export function mergeSeoFieldLocation(contextDefault, callOverride) {
29
+ const merged = { ...contextDefault };
30
+ if (callOverride?.fields !== undefined)
31
+ merged.fields = callOverride.fields;
32
+ if (callOverride?.group !== undefined)
33
+ merged.group = callOverride.group;
34
+ return merged;
35
+ }
11
36
  let warnedStaticMode = false;
12
37
  /**
13
38
  * Stub auth plugin for static deployments where no real auth is needed.
@@ -147,31 +172,29 @@ export async function createNextCanopyContext(options) {
147
172
  if (options.config.mode === 'dev' && !isBuildMode()) {
148
173
  startDevContentWatcher(services, { mode: options.config.dev?.contentSync });
149
174
  }
150
- // User extractor: passes Next.js headers to auth plugin, loads internal groups, applies authorization
175
+ // User extractor: passes Next.js headers to auth plugin, resolves internal
176
+ // groups, applies authorization. Delegates to the shared
177
+ // "authenticate -> load internal groups -> merge" pipeline
178
+ // (resolveCanopyUser, in canopycms core) so this stays in lockstep with
179
+ // http/handler.ts's API-layer equivalent rather than re-implementing it —
180
+ // a previous copy here loaded groups from the base branch content clone
181
+ // (via loadBranchContext), which nothing in the product ever writes
182
+ // groups.json into, so group-based privileges never took effect.
183
+ //
184
+ // No base-branch context resolution here (unlike the previous copy):
185
+ // that call existed only to source groups.json from the (wrong) content
186
+ // branch. Actual content reads (buildContentTree/listEntries/read) already
187
+ // provision the base/active branch themselves via loadOrCreateBranchContext
188
+ // (see context.ts's resolveSchemaContext), so dropping it here removes a
189
+ // redundant per-request EFS round-trip rather than losing provisioning.
151
190
  const extractUser = async () => {
152
191
  const headersList = await headers();
153
192
  const authResult = await authPlugin.authenticate(headersList);
154
- // Load internal groups from main branch
155
- const baseBranch = services.config.defaultBaseBranch ?? 'main';
156
- const operatingMode = services.config.mode ?? 'dev';
157
- const mainBranchContext = await loadBranchContext({
158
- branchName: baseBranch,
159
- mode: operatingMode,
193
+ return resolveCanopyUser(authResult, {
194
+ getSettingsBranchRoot: services.getSettingsBranchRoot,
195
+ mode: services.config.mode ?? 'dev',
196
+ bootstrapAdminIds: services.bootstrapAdminIds,
160
197
  });
161
- const internalGroups = mainBranchContext
162
- ? await loadInternalGroups(mainBranchContext.branchRoot, operatingMode, services.bootstrapAdminIds).catch((err) => {
163
- console.warn('CanopyCMS: Failed to load internal groups from main branch:', err);
164
- return [];
165
- })
166
- : [];
167
- if (!warnedNoAdmins && Array.isArray(internalGroups)) {
168
- const adminsGroup = internalGroups.find((g) => g.id === 'Admins');
169
- if (!adminsGroup || adminsGroup.members.length === 0) {
170
- console.warn('CanopyCMS: No admin users configured. Set CANOPY_BOOTSTRAP_ADMIN_IDS or add members to the Admins group.');
171
- }
172
- warnedNoAdmins = true;
173
- }
174
- return authResultToCanopyUser(authResult, services.bootstrapAdminIds, internalGroups);
175
198
  };
176
199
  // Create core context with pre-created services (framework-agnostic)
177
200
  const coreContext = createCanopyContext({
@@ -213,11 +236,36 @@ export async function createNextCanopyContext(options) {
213
236
  const ctx = isBuildMode() ? await getCanopyForBuild() : await getCanopy();
214
237
  return ctx.read(input);
215
238
  };
239
+ const listEntries = async (opts) => {
240
+ const ctx = isBuildMode() ? await getCanopyForBuild() : await getCanopy();
241
+ return ctx.listEntries(opts);
242
+ };
216
243
  // Enumeration-only static-params helper, bound to the (guarded) build context so page modules don't
217
244
  // import the admin context just to list paths. generateStaticParams is build-only, so this is safe.
218
245
  const generateContentStaticParams = async (options = {}) => {
219
246
  return collectStaticParams(await getCanopyForBuild(), options);
220
247
  };
248
+ // Sitemap generation reads entry CONTENT (to apply the noindex predicate), so unlike
249
+ // generateContentStaticParams it is not enumeration-only — but sitemap.ts is build-only in a
250
+ // static export, and on a prod `server` deployment guardBuildContext throws if it is reached at
251
+ // request time. Binding it here keeps the admin context out of the route module either way.
252
+ //
253
+ // Both this and boundEntryToMetadata below feed options.seo (the context-wide default set on
254
+ // createNextCanopyContext) through the SAME mergeSeoFieldLocation call, so the noindex exclusion
255
+ // here and entryToMetadata's noindex/field read cannot independently drift out of sync.
256
+ const boundGenerateContentSitemap = async (callOptions) => {
257
+ return generateContentSitemap(await getCanopyForBuild(), {
258
+ ...callOptions,
259
+ seo: mergeSeoFieldLocation(options.seo, callOptions.seo),
260
+ });
261
+ };
262
+ const boundEntryToMetadata = (entryData, callOptions = {}) => {
263
+ const seoLocation = mergeSeoFieldLocation(options.seo, {
264
+ fields: callOptions.fields,
265
+ group: callOptions.group,
266
+ });
267
+ return entryToMetadataCore(entryData, { ...callOptions, ...seoLocation });
268
+ };
221
269
  // Create API handler using same services
222
270
  const handler = createCanopyCatchAllHandler({
223
271
  ...options,
@@ -230,7 +278,10 @@ export async function createNextCanopyContext(options) {
230
278
  getCanopyForBuild,
231
279
  readByUrlPath,
232
280
  read,
281
+ listEntries,
233
282
  generateContentStaticParams,
283
+ generateContentSitemap: boundGenerateContentSitemap,
284
+ entryToMetadata: boundEntryToMetadata,
234
285
  handler,
235
286
  services,
236
287
  };
@@ -1 +1 @@
1
- {"version":3,"file":"context-wrapper.js","sourceRoot":"","sources":["../src/context-wrapper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context-wrapper.js","sourceRoot":"","sources":["../src/context-wrapper.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { createCanopyCatchAllHandler, wrapNextRequest, type CanopyNextOptions } from './adapter';
2
2
  export { createNextCanopyContext, type NextCanopyOptions, type NextCanopyContextResult, } from './context-wrapper';
3
- export { collectStaticParams, type GenerateContentStaticParamsOptions } from './static';
3
+ export { collectStaticParams, generateContentSitemap, entryToMetadata, type GenerateContentStaticParamsOptions, type GenerateContentSitemapOptions, type EntryToMetadataOptions, type SitemapExtraUrl, } from './static';
4
4
  export { createMockAuthPlugin, createRejectingAuthPlugin } from './test-utils';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAEhG,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,mBAAmB,EAAE,KAAK,kCAAkC,EAAE,MAAM,UAAU,CAAA;AAEvF,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAEhG,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,KAAK,kCAAkC,EACvC,KAAK,6BAA6B,EAClC,KAAK,sBAAsB,EAC3B,KAAK,eAAe,GACrB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { createCanopyCatchAllHandler, wrapNextRequest } from './adapter';
2
2
  export { createNextCanopyContext, } from './context-wrapper';
3
- export { collectStaticParams } from './static';
3
+ export { collectStaticParams, generateContentSitemap, entryToMetadata, } from './static';
4
4
  export { createMockAuthPlugin, createRejectingAuthPlugin } from './test-utils';
5
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAA0B,MAAM,WAAW,CAAA;AAEhG,OAAO,EACL,uBAAuB,GAGxB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,mBAAmB,EAA2C,MAAM,UAAU,CAAA;AAEvF,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAA0B,MAAM,WAAW,CAAA;AAEhG,OAAO,EACL,uBAAuB,GAGxB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,GAKhB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA"}
package/dist/static.d.ts CHANGED
@@ -1,10 +1,17 @@
1
- import { type CanopyBuildContext, type CollectStaticPathsOptions } from 'canopycms/server';
1
+ import type { Metadata, MetadataRoute } from 'next';
2
+ import { type CanopyBuildContext, type CollectStaticPathsOptions, type ExtractSeoFieldsOptions, type RoutableEntry, type SeoFieldLocation, type SeoOgType } from 'canopycms/server';
2
3
  /**
3
- * Next.js static-export helpers built on the framework-agnostic core in `canopycms/server`.
4
+ * Next.js static-export helpers built on the framework-agnostic core in `canopycms/server`:
5
+ * static params (`collectStaticParams`), the content sitemap (`generateContentSitemap`), and
6
+ * per-entry metadata (`entryToMetadata`).
4
7
  *
5
- * Today this ships static-params generation. Sitemap and SEO-metadata helpers are tracked as
6
- * follow-up work (see .claude/future-tasks/static-export-sitemap.md and
7
- * .claude/future-tasks/static-export-seo-metadata.md).
8
+ * The last two ship together on purpose. `noindex` has to suppress a page in BOTH surfaces —
9
+ * `robots: { index: false }` on the page and absence from the sitemap — and both read it through
10
+ * the same core `isNoindexEntry` predicate, so they cannot disagree about which pages are
11
+ * advertised.
12
+ *
13
+ * `robots.txt` is out of scope: it is a handful of static lines with no CanopyCMS content behind
14
+ * it. Write `app/robots.ts` yourself, and point its `sitemap` at the route below.
8
15
  */
9
16
  export interface GenerateContentStaticParamsOptions extends CollectStaticPathsOptions {
10
17
  /** Route param name. Default 'slug'. */
@@ -36,4 +43,114 @@ export interface GenerateContentStaticParamsOptions extends CollectStaticPathsOp
36
43
  * `[[...slug]]`, otherwise exclude it via `options.filter` (e.g. `(e) => e.segments.length > 0`).
37
44
  */
38
45
  export declare function collectStaticParams(buildCtx: Pick<CanopyBuildContext, 'listEntries'>, options?: GenerateContentStaticParamsOptions): Promise<Array<Record<string, string | string[]>>>;
46
+ type SitemapItem = MetadataRoute.Sitemap[number];
47
+ /** A URL with no CanopyCMS entry behind it (a hand-written app route, a feed). */
48
+ export interface SitemapExtraUrl {
49
+ /** Site-relative path ('/blog') or an absolute URL. Trailing-slash rules apply to the former. */
50
+ path: string;
51
+ lastModified?: Date | string;
52
+ changeFrequency?: SitemapItem['changeFrequency'];
53
+ priority?: number;
54
+ }
55
+ export interface GenerateContentSitemapOptions {
56
+ /**
57
+ * Site origin, e.g. `https://example.com`. Required: a sitemap must carry absolute URLs, or
58
+ * search engines reject the whole file. Enforced — `generateContentSitemap` throws if this
59
+ * isn't an absolute URL (no scheme, or empty).
60
+ */
61
+ siteUrl: string;
62
+ /**
63
+ * Emit site-relative URLs with a trailing slash (`/contact/` rather than `/contact`).
64
+ *
65
+ * **Explicit on purpose.** CanopyCMS cannot see your `next.config.ts`, so it cannot know
66
+ * whether your site serves `trailingSlash: true`. Set this to match, or the sitemap advertises
67
+ * URLs that redirect — a real adopter shipped exactly that mismatch.
68
+ */
69
+ trailingSlash?: boolean;
70
+ /** Scope to a collection logical path (e.g. 'content/posts'). Defaults to the whole content root. */
71
+ rootPath?: string;
72
+ /** Where the SEO fields live, when they aren't the flat defaults. Drives the `noindex` read. */
73
+ seo?: SeoFieldLocation;
74
+ /**
75
+ * Drop entries from the sitemap. Applied ON TOP of the `noindex` exclusion, which is not
76
+ * optional. Use for structural URLs that shouldn't be advertised (e.g. a bare collection index).
77
+ */
78
+ exclude?: (entry: RoutableEntry) => boolean;
79
+ /**
80
+ * `<lastmod>` per entry. Defaults to the entry's `updatedAt`.
81
+ *
82
+ * **`updatedAt` is filesystem mtime, not an editorial timestamp.** A fresh CI clone resets every
83
+ * file's mtime to checkout time, so on a clean build agent the default dates every URL to the
84
+ * moment the tree was cloned. Treat the default as "changed since the last build" at best; if
85
+ * you need a truthful `<lastmod>`, supply one here (a content date field, or git commit time)
86
+ * or return `undefined` to omit the element entirely, which is better than asserting a date you
87
+ * cannot stand behind.
88
+ */
89
+ lastModified?: (entry: RoutableEntry) => Date | string | undefined;
90
+ /** `<priority>` per entry. Omitted from the URL when this returns undefined (the default). */
91
+ priority?: (entry: RoutableEntry) => number | undefined;
92
+ /** URLs with no entry behind them — hand-written app routes, feeds — appended to the result. */
93
+ extraUrls?: SitemapExtraUrl[];
94
+ }
95
+ /**
96
+ * Build Next's `MetadataRoute.Sitemap` from CanopyCMS content.
97
+ *
98
+ * **Every routable entry type is included by default.** There is no list of "sitemap-able" entry
99
+ * types to keep in sync, and that is the whole design: a hand-rolled sitemap that enumerates a
100
+ * remembered list of entry types omits whichever type nobody added, ships green, and takes the
101
+ * missing pages out of search results silently. Omitting a URL here requires an explicit
102
+ * `exclude` predicate or a `noindex` flag on the entry.
103
+ *
104
+ * `noindex` entries are excluded, via the same core `isNoindexEntry` predicate that drives
105
+ * `robots: { index: false }` in `entryToMetadata`. They are still BUILT — enumeration
106
+ * (`generateContentStaticParams`) does not filter them, so the page exists for anyone holding
107
+ * the link; it just isn't advertised.
108
+ *
109
+ * `changeFrequency` is not emitted for entries: a blanket value asserted for every URL carries no
110
+ * information, and search engines say they ignore it. Set it per-URL via `extraUrls` if you want it.
111
+ *
112
+ * Output is stably ordered ('/' first, then alphabetical) so a rebuild doesn't reshuffle the file.
113
+ *
114
+ * @example
115
+ * // app/sitemap.ts
116
+ * export const dynamic = 'force-static' // required for output: 'export'
117
+ * export default () => contentSitemap({ siteUrl: 'https://example.com', trailingSlash: true })
118
+ */
119
+ export declare function generateContentSitemap(buildCtx: Pick<CanopyBuildContext, 'listEntries'>, options: GenerateContentSitemapOptions): Promise<MetadataRoute.Sitemap>;
120
+ export interface EntryToMetadataOptions extends ExtractSeoFieldsOptions {
121
+ /** Route path for this entry — the canonical URL when the entry sets none. */
122
+ path?: string;
123
+ /**
124
+ * Site origin for resolving relative canonical / OG image URLs. Omit to leave them relative and
125
+ * let Next's `metadataBase` resolve them.
126
+ */
127
+ siteUrl?: string;
128
+ /** Emit site-relative URLs with a trailing slash. Match your sitemap and your routing config. */
129
+ trailingSlash?: boolean;
130
+ /** Site name (openGraph.siteName, and the social-card title fallback). */
131
+ siteName?: string;
132
+ /** Root-layout mode: emit `title: { template, default }` (e.g. `'%s | Example'`). */
133
+ titleTemplate?: string;
134
+ /** og:type when the entry sets none. Defaults to 'website'. */
135
+ defaultOgType?: SeoOgType;
136
+ }
137
+ /**
138
+ * Map an entry's SEO fields onto a Next `Metadata` object.
139
+ *
140
+ * Title and description follow ONE convention everywhere: the entry's meta field, else the
141
+ * fallback you pass, else unset (so the root layout's default applies). An empty CMS field counts
142
+ * as unset — see `extractSeoFields`.
143
+ *
144
+ * `noindex` goes through the same core predicate the sitemap uses, so a page marked noindex is
145
+ * suppressed in both surfaces or neither.
146
+ *
147
+ * @example
148
+ * export async function generateMetadata({ params }): Promise<Metadata> {
149
+ * const { slug } = await params
150
+ * const result = await readByUrlPath(`/posts/${slug}`)
151
+ * return entryToMetadata(result?.data, { path: `/posts/${slug}`, fallbackTitle: result?.data.title })
152
+ * }
153
+ */
154
+ export declare function entryToMetadata(entryData: unknown, opts?: EntryToMetadataOptions): Metadata;
155
+ export {};
39
156
  //# sourceMappingURL=static.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC/B,MAAM,kBAAkB,CAAA;AAEzB;;;;;;GAMG;AAEH,MAAM,WAAW,kCAAmC,SAAQ,yBAAyB;IACnF,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAA;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,EACjD,OAAO,GAAE,kCAAuC,GAC/C,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAmBnD"}
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AACnD,OAAO,EAOL,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,kCAAmC,SAAQ,yBAAyB;IACnF,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAA;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,EACjD,OAAO,GAAE,kCAAuC,GAC/C,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,CAyBnD;AAMD,KAAK,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;AAEhD,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,iGAAiG;IACjG,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;IAC5B,eAAe,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,6BAA6B;IAC5C;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,qGAAqG;IACrG,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gGAAgG;IAChG,GAAG,CAAC,EAAE,gBAAgB,CAAA;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAA;IAC3C;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,MAAM,GAAG,SAAS,CAAA;IAClE,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAA;IACvD,gGAAgG;IAChG,SAAS,CAAC,EAAE,eAAe,EAAE,CAAA;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,EACjD,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CA4ChC;AAiCD,MAAM,WAAW,sBAAuB,SAAQ,uBAAuB;IACrE,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iGAAiG;IACjG,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,SAAS,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,GAAE,sBAA2B,GAAG,QAAQ,CAkD/F"}
package/dist/static.js CHANGED
@@ -1,4 +1,4 @@
1
- import { collectStaticPaths, } from 'canopycms/server';
1
+ import { collectRoutableEntries, collectStaticPaths, extractSeoFields, isAbsoluteUrl, isNoindexEntry, resolveSeoUrl, } from 'canopycms/server';
2
2
  /**
3
3
  * Shape CanopyCMS content paths into the array Next's `generateStaticParams` expects.
4
4
  *
@@ -14,7 +14,13 @@ import { collectStaticPaths, } from 'canopycms/server';
14
14
  export async function collectStaticParams(buildCtx, options = {}) {
15
15
  const { paramName = 'slug', shape = 'catch-all', basePath, ...collectOptions } = options;
16
16
  let entries = await collectStaticPaths(buildCtx, collectOptions);
17
- if (basePath) {
17
+ // basePath only means something for the catch-all shape: it rewrites `segments` relative to the
18
+ // route's URL prefix, and 'single' shape never reads `segments` (it emits `entry.slug`). Applying
19
+ // the prefix FILTER unconditionally — as this once did — silently dropped every entry outside the
20
+ // prefix for 'single' too, contradicting this option's own doc above ("no effect with shape:
21
+ // 'single'") and meaning unbuilt pages for anyone who set basePath alongside 'single'. Scope with
22
+ // `rootPath` for 'single' instead.
23
+ if (basePath && shape !== 'single') {
18
24
  // Make segments relative to a nested route's base prefix (e.g. '/docs' for app/docs/[[...slug]]).
19
25
  // urlPath is always lowercased (see content-listing), so lowercase the prefix to match.
20
26
  const prefix = (basePath.endsWith('/') ? basePath.slice(0, -1) : basePath).toLowerCase();
@@ -27,4 +33,155 @@ export async function collectStaticParams(buildCtx, options = {}) {
27
33
  }
28
34
  return entries.map((entry) => shape === 'single' ? { [paramName]: entry.slug } : { [paramName]: entry.segments });
29
35
  }
36
+ /**
37
+ * Build Next's `MetadataRoute.Sitemap` from CanopyCMS content.
38
+ *
39
+ * **Every routable entry type is included by default.** There is no list of "sitemap-able" entry
40
+ * types to keep in sync, and that is the whole design: a hand-rolled sitemap that enumerates a
41
+ * remembered list of entry types omits whichever type nobody added, ships green, and takes the
42
+ * missing pages out of search results silently. Omitting a URL here requires an explicit
43
+ * `exclude` predicate or a `noindex` flag on the entry.
44
+ *
45
+ * `noindex` entries are excluded, via the same core `isNoindexEntry` predicate that drives
46
+ * `robots: { index: false }` in `entryToMetadata`. They are still BUILT — enumeration
47
+ * (`generateContentStaticParams`) does not filter them, so the page exists for anyone holding
48
+ * the link; it just isn't advertised.
49
+ *
50
+ * `changeFrequency` is not emitted for entries: a blanket value asserted for every URL carries no
51
+ * information, and search engines say they ignore it. Set it per-URL via `extraUrls` if you want it.
52
+ *
53
+ * Output is stably ordered ('/' first, then alphabetical) so a rebuild doesn't reshuffle the file.
54
+ *
55
+ * @example
56
+ * // app/sitemap.ts
57
+ * export const dynamic = 'force-static' // required for output: 'export'
58
+ * export default () => contentSitemap({ siteUrl: 'https://example.com', trailingSlash: true })
59
+ */
60
+ export async function generateContentSitemap(buildCtx, options) {
61
+ const { siteUrl, trailingSlash, rootPath, seo, exclude, lastModified, priority } = options;
62
+ // A sitemap with a non-absolute <loc> is invalid — search engines reject the WHOLE file, not
63
+ // just the bad entry, and the build stays green because nothing here threw. 'example.com' (no
64
+ // scheme) and '' both pass through resolveSeoUrl unmodified today; catch them here instead.
65
+ if (!isAbsoluteUrl(siteUrl)) {
66
+ throw new Error(`CanopyCMS: generateContentSitemap requires an absolute siteUrl (e.g. "https://example.com"), ` +
67
+ `got ${JSON.stringify(siteUrl)}. A sitemap whose <loc> values aren't absolute URLs is invalid ` +
68
+ 'and search engines silently reject the entire file.');
69
+ }
70
+ const urlOpts = { siteUrl, trailingSlash };
71
+ const entries = await collectRoutableEntries(buildCtx, { rootPath });
72
+ const items = [];
73
+ for (const entry of entries) {
74
+ if (isNoindexEntry(entry.data, seo))
75
+ continue;
76
+ if (exclude?.(entry))
77
+ continue;
78
+ const modified = lastModified ? lastModified(entry) : entry.updatedAt;
79
+ const entryPriority = priority?.(entry);
80
+ items.push({
81
+ url: resolveSeoUrl(entry.urlPath, urlOpts),
82
+ ...(modified ? { lastModified: modified } : {}),
83
+ ...(entryPriority === undefined ? {} : { priority: entryPriority }),
84
+ });
85
+ }
86
+ for (const extra of options.extraUrls ?? []) {
87
+ items.push({
88
+ url: resolveSeoUrl(extra.path, urlOpts),
89
+ ...(extra.lastModified ? { lastModified: extra.lastModified } : {}),
90
+ ...(extra.changeFrequency ? { changeFrequency: extra.changeFrequency } : {}),
91
+ ...(extra.priority === undefined ? {} : { priority: extra.priority }),
92
+ });
93
+ }
94
+ const root = resolveSeoUrl('/', urlOpts);
95
+ return dedupeSitemapItems(items).sort((a, b) => a.url === root ? -1 : b.url === root ? 1 : a.url.localeCompare(b.url));
96
+ }
97
+ /**
98
+ * Drop duplicate `<loc>` entries, keeping the first occurrence and warning about each collision.
99
+ *
100
+ * A duplicate URL isn't fatal to a crawler, but it usually means two entries (or an entry and an
101
+ * `extraUrls` path) are unintentionally sharing one URL — an index entry collapsing onto a
102
+ * sibling's path, or two `urlPath`s that only differ by case (`urlPath` is lowercased — see
103
+ * `content-listing.ts`). Warning rather than silently deduping turns that into a build-time signal
104
+ * an adopter can act on instead of a sitemap that just quietly has fewer URLs than expected.
105
+ */
106
+ function dedupeSitemapItems(items) {
107
+ const seen = new Set();
108
+ const result = [];
109
+ for (const item of items) {
110
+ if (seen.has(item.url)) {
111
+ console.warn(`CanopyCMS: generateContentSitemap found more than one entry resolving to the same sitemap ` +
112
+ `URL ${JSON.stringify(item.url)}. Keeping the first and dropping the rest — this usually means ` +
113
+ 'two entries (or an entry and an extraUrls path) are unintentionally sharing one URL.');
114
+ continue;
115
+ }
116
+ seen.add(item.url);
117
+ result.push(item);
118
+ }
119
+ return result;
120
+ }
121
+ /**
122
+ * Map an entry's SEO fields onto a Next `Metadata` object.
123
+ *
124
+ * Title and description follow ONE convention everywhere: the entry's meta field, else the
125
+ * fallback you pass, else unset (so the root layout's default applies). An empty CMS field counts
126
+ * as unset — see `extractSeoFields`.
127
+ *
128
+ * `noindex` goes through the same core predicate the sitemap uses, so a page marked noindex is
129
+ * suppressed in both surfaces or neither.
130
+ *
131
+ * @example
132
+ * export async function generateMetadata({ params }): Promise<Metadata> {
133
+ * const { slug } = await params
134
+ * const result = await readByUrlPath(`/posts/${slug}`)
135
+ * return entryToMetadata(result?.data, { path: `/posts/${slug}`, fallbackTitle: result?.data.title })
136
+ * }
137
+ */
138
+ export function entryToMetadata(entryData, opts = {}) {
139
+ const seo = extractSeoFields(entryData, opts);
140
+ const urlOpts = { siteUrl: opts.siteUrl, trailingSlash: opts.trailingSlash };
141
+ // The entry's own canonical wins over the route path; an absolute one passes through verbatim
142
+ // (see resolveSeoUrl — the absolute check runs before any normalization, which is a fixed bug).
143
+ const canonicalSource = seo.canonical ?? opts.path;
144
+ const canonical = canonicalSource ? resolveSeoUrl(canonicalSource, urlOpts) : undefined;
145
+ // Images are files, never directory-style URLs: never append a trailing slash to one.
146
+ const ogImage = seo.ogImage ? resolveSeoUrl(seo.ogImage, { siteUrl: opts.siteUrl }) : undefined;
147
+ // og:title falls back to the site name so a page that inherits the layout title still emits a
148
+ // usable card — Next REPLACES `openGraph` wholesale rather than deep-merging it.
149
+ const socialTitle = seo.title ?? opts.siteName;
150
+ const ogType = seo.ogType ?? opts.defaultOgType ?? 'website';
151
+ const openGraphBase = {
152
+ ...(socialTitle ? { title: socialTitle } : {}),
153
+ ...(seo.description ? { description: seo.description } : {}),
154
+ ...(canonical ? { url: canonical } : {}),
155
+ ...(opts.siteName ? { siteName: opts.siteName } : {}),
156
+ ...(ogImage ? { images: [{ url: ogImage }] } : {}),
157
+ };
158
+ const metadata = {
159
+ ...(canonical ? { alternates: { canonical } } : {}),
160
+ // Spelled out per branch rather than cast: Next's OpenGraph metadata is a discriminated
161
+ // union on `type`.
162
+ openGraph: ogType === 'article'
163
+ ? { ...openGraphBase, type: 'article' }
164
+ : ogType === 'profile'
165
+ ? { ...openGraphBase, type: 'profile' }
166
+ : { ...openGraphBase, type: 'website' },
167
+ twitter: {
168
+ card: seo.twitterCard ?? 'summary_large_image',
169
+ ...(socialTitle ? { title: socialTitle } : {}),
170
+ ...(seo.description ? { description: seo.description } : {}),
171
+ ...(ogImage ? { images: [ogImage] } : {}),
172
+ },
173
+ };
174
+ if (opts.titleTemplate) {
175
+ metadata.title = { template: opts.titleTemplate, default: seo.title ?? opts.siteName ?? '' };
176
+ }
177
+ else if (seo.title) {
178
+ metadata.title = seo.title;
179
+ }
180
+ if (seo.description)
181
+ metadata.description = seo.description;
182
+ // Same predicate as the sitemap's exclusion — these two must never be derived separately.
183
+ if (isNoindexEntry(entryData, opts))
184
+ metadata.robots = { index: false, follow: false };
185
+ return metadata;
186
+ }
30
187
  //# sourceMappingURL=static.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"static.js","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAGnB,MAAM,kBAAkB,CAAA;AA4BzB;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAiD,EACjD,UAA8C,EAAE;IAEhD,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE,KAAK,GAAG,WAAW,EAAE,QAAQ,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,CAAA;IACxF,IAAI,OAAO,GAAG,MAAM,kBAAkB,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAA;IAEhE,IAAI,QAAQ,EAAE,CAAC;QACb,kGAAkG;QAClG,wFAAwF;QACxF,MAAM,MAAM,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;QACxF,OAAO,GAAG,OAAO;aACd,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;aACrF,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;YAClF,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;QAC1D,CAAC,CAAC,CAAA;IACN,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAC3B,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,QAAQ,EAAE,CACnF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"static.js","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canopycms-next",
3
- "version": "0.0.61",
3
+ "version": "0.0.63",
4
4
  "description": "Next.js adapter for CanopyCMS",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,19 +34,19 @@
34
34
  "node": ">=18"
35
35
  },
36
36
  "peerDependencies": {
37
- "next": "^13.5.7 || ^14.2.25 || ^15.2.3 || >=16.0.0 <16.2.0 || >=16.3.0 <17.0.0",
37
+ "next": "^13.5.7 || ^14.2.25 || ^15.5.21 || >=16.0.0 <16.2.0 || >=16.3.0 <17.0.0",
38
38
  "react": "^18.0.0 || ^19.0.0",
39
- "canopycms": "0.0.61"
39
+ "canopycms": "0.0.63"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^22.9.0",
43
43
  "esbuild": "^0.25.0",
44
44
  "@types/react": "^18.3.12",
45
- "next": "^15.5.19",
45
+ "next": "^15.5.21",
46
46
  "react": "^18.3.1",
47
47
  "typescript": "^5.6.3",
48
48
  "vitest": "^4.1.0",
49
- "canopycms": "0.0.61"
49
+ "canopycms": "0.0.63"
50
50
  },
51
51
  "scripts": {
52
52
  "build": "tsc -p tsconfig.build.json && esbuild src/config.ts --bundle --platform=node --packages=external --external:next --format=cjs --outfile=dist/config.cjs && esbuild src/config.ts --bundle --platform=node --packages=external --external:next --format=esm --outfile=dist/config.mjs",