@nitrogenbuilder/connector-payload 0.1.26 → 0.1.28

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.
@@ -3,5 +3,8 @@
3
3
  *
4
4
  * The plugin registers collections at init time via `registerCollection()`.
5
5
  */
6
- export declare function registerCollection(alias: string, collectionSlug: string): void;
6
+ export declare function registerCollection(alias: string, collectionSlug: string, routePattern?: string): void;
7
7
  export declare function resolveCollection(postType: string): string;
8
+ export declare function resolveCollectionRoutePattern(postType: string): string | undefined;
9
+ export declare function buildRelativePermalink(postType: string, slug: string): string;
10
+ export declare function buildPermalink(postType: string, slug: string, frontendUrl?: string): string;
@@ -4,9 +4,40 @@
4
4
  * The plugin registers collections at init time via `registerCollection()`.
5
5
  */
6
6
  const registeredCollections = new Map();
7
- export function registerCollection(alias, collectionSlug) {
8
- registeredCollections.set(alias, collectionSlug);
7
+ function normalizeRoutePattern(routePattern) {
8
+ if (!routePattern)
9
+ return undefined;
10
+ return routePattern.startsWith('/') ? routePattern : `/${routePattern}`;
11
+ }
12
+ function buildRelativePath(routePattern, slug) {
13
+ if (routePattern) {
14
+ if (routePattern.includes('[...slug]')) {
15
+ return routePattern.replace('[...slug]', slug);
16
+ }
17
+ if (routePattern.includes('[slug]')) {
18
+ return routePattern.replace('[slug]', slug);
19
+ }
20
+ return routePattern.endsWith('/') ? `${routePattern}${slug}` : routePattern;
21
+ }
22
+ return `/${slug}`;
23
+ }
24
+ export function registerCollection(alias, collectionSlug, routePattern) {
25
+ registeredCollections.set(alias, {
26
+ collectionSlug,
27
+ routePattern: normalizeRoutePattern(routePattern),
28
+ });
9
29
  }
10
30
  export function resolveCollection(postType) {
11
- return registeredCollections.get(postType) || postType;
31
+ return registeredCollections.get(postType)?.collectionSlug || postType;
32
+ }
33
+ export function resolveCollectionRoutePattern(postType) {
34
+ return registeredCollections.get(postType)?.routePattern;
35
+ }
36
+ export function buildRelativePermalink(postType, slug) {
37
+ return buildRelativePath(resolveCollectionRoutePattern(postType), slug);
38
+ }
39
+ export function buildPermalink(postType, slug, frontendUrl) {
40
+ const relativePermalink = buildRelativePermalink(postType, slug);
41
+ const baseUrl = (frontendUrl || '').replace(/\/$/, '');
42
+ return baseUrl ? `${baseUrl}${relativePermalink}` : relativePermalink;
12
43
  }
@@ -68,10 +68,10 @@ export const NitrogenEditButtonRuntime = ({ collection }) => {
68
68
  }, [collection]);
69
69
  if (!id || !token || !authorId)
70
70
  return null;
71
- const param = collection === 'nitrogen-templates' ? 'id' : 'pageId';
72
71
  const editorBase = instanceUrl ?? '';
73
72
  const isDevelopmentMode = isLocalAdminHost();
74
- const editHref = `${editorBase}/nitrogen-editor?token=${encodeURIComponent(token)}&collection=${encodeURIComponent(collection)}&${param}=${id}&authorId=${encodeURIComponent(authorId)}${isDevelopmentMode ? '&development=true' : ''}`;
73
+ const encodedAuthorId = encodeURIComponent(authorId);
74
+ const editHref = `${editorBase}/nitrogen-editor?token=${encodeURIComponent(token)}&collection=${encodeURIComponent(collection)}&pageId=${id}&authorId=${encodedAuthorId}&author=${encodedAuthorId}${isDevelopmentMode ? '&development=true' : ''}`;
75
75
  const viewHref = collection === 'nitrogen-templates'
76
76
  ? `${frontendUrl}/nitrogen-templates/${slug}`
77
77
  : `${frontendUrl}/${slug}`;
@@ -1,8 +1,6 @@
1
1
  import type { SanitizedConfig } from "payload";
2
2
  interface NitrogenEditorSearchParams {
3
- id?: string;
4
3
  pageId?: string;
5
- templateId?: string;
6
4
  collection?: string;
7
5
  development?: string;
8
6
  }
@@ -15,7 +13,7 @@ interface NitrogenEditorSearchParams {
15
13
  * import configPromise from '@payload-config'
16
14
  * export default createNitrogenEditorPage(configPromise)
17
15
  *
18
- * Accessible at `/nitrogen-editor?pageId=xxx` or `/nitrogen-editor?id=xxx&collection=nitrogen-templates`.
16
+ * Accessible at `/nitrogen-editor?pageId=xxx`.
19
17
  */
20
18
  export declare function createNitrogenEditorPage(config: Promise<SanitizedConfig>): ({ searchParams, }: {
21
19
  searchParams: Promise<NitrogenEditorSearchParams>;
@@ -57,7 +57,7 @@ function getSiteUrl(settings, isDevelopment) {
57
57
  * import configPromise from '@payload-config'
58
58
  * export default createNitrogenEditorPage(configPromise)
59
59
  *
60
- * Accessible at `/nitrogen-editor?pageId=xxx` or `/nitrogen-editor?id=xxx&collection=nitrogen-templates`.
60
+ * Accessible at `/nitrogen-editor?pageId=xxx`.
61
61
  */
62
62
  export function createNitrogenEditorPage(config) {
63
63
  return async function NitrogenEditorPage({ searchParams, }) {
@@ -76,15 +76,7 @@ export function createNitrogenEditorPage(config) {
76
76
  const isDevelopment = params.development === "true";
77
77
  const siteUrl = getSiteUrl(settings, isDevelopment);
78
78
  const nitrogenConfig = settings.nitrogenConfig || {};
79
- // Determine the postType for the editor's API calls
80
- let postType;
81
- if (params.collection) {
82
- postType = params.collection;
83
- }
84
- else if (params.id || params.templateId) {
85
- postType = "nitrogen-templates";
86
- }
87
- else {
79
+ if (!params.pageId || !params.collection) {
88
80
  return redirect("/admin");
89
81
  }
90
82
  // Build the config object the builder reads from window.nitrogenConfig
@@ -93,14 +85,14 @@ export function createNitrogenEditorPage(config) {
93
85
  provider: {
94
86
  type: "payload",
95
87
  apiUrl: getNitrogenApiUrl(isDevelopment),
96
- collection: postType,
88
+ collection: params.collection,
97
89
  },
98
90
  siteUrl: siteUrl || "",
99
91
  urlMaps: nitrogenConfig.urlMaps || [],
100
92
  wysiwygColors: nitrogenConfig.wysiwygColors || {},
101
93
  cssInjection: nitrogenConfig.cssInjection || "",
102
94
  };
103
- const editId = params.id || params.templateId || params.pageId || "";
95
+ const editId = params.pageId;
104
96
  const isEditorDev = isDevelopment && !!settings.instanceUrl;
105
97
  const editorOrigin = settings.instanceUrl?.replace(/\/$/, "") || "";
106
98
  const editorAssetsBase = isEditorDev
@@ -111,8 +103,8 @@ export function createNitrogenEditorPage(config) {
111
103
  __html: [
112
104
  `window.nitrogenConfig = ${JSON.stringify(builderConfig)};`,
113
105
  `window.nitrogenEditId = "${editId}";`,
114
- // Inject authorId into the URL so the editor can read it from window.location.search
115
- `(function(){var u=new URL(window.location.href);if(!u.searchParams.has("authorId")){u.searchParams.set("authorId",${JSON.stringify(String(user.id))});window.history.replaceState(null,"",u.toString())}})();`,
106
+ // Keep both legacy and current author params present for editor builds.
107
+ `(function(){var u=new URL(window.location.href),a=${JSON.stringify(String(user.id))},changed=false;if(!u.searchParams.has("authorId")){u.searchParams.set("authorId",a);changed=true}if(!u.searchParams.has("author")){u.searchParams.set("author",a);changed=true}if(changed){window.history.replaceState(null,"",u.toString())}})();`,
116
108
  ].join(""),
117
109
  } }), _jsxs("div", { id: "root", children: [_jsx("div", { style: {
118
110
  position: "fixed",
@@ -1,5 +1,5 @@
1
1
  import { getNitrogenSettings } from './helpers';
2
- import { resolveCollection } from '../collection-registry';
2
+ import { buildPermalink, buildRelativePermalink, resolveCollection, } from '../collection-registry';
3
3
  export const allEndpoints = [
4
4
  // GET /api/nitrogen/v1/all — List all items with filtering
5
5
  {
@@ -34,8 +34,8 @@ export const allEndpoints = [
34
34
  id: doc.id,
35
35
  title: String(doc.title || ''),
36
36
  slug: String(doc.slug || ''),
37
- permalink: `${settings.frontendUrl || ''}/${String(doc.slug || '')}`,
38
- relative_permalink: `/${String(doc.slug || '')}`,
37
+ permalink: buildPermalink(postType, String(doc.slug || ''), settings.frontendUrl),
38
+ relative_permalink: buildRelativePermalink(postType, String(doc.slug || '')),
39
39
  type: collection,
40
40
  }));
41
41
  return Response.json(items);
@@ -1,4 +1,4 @@
1
- import { resolveCollection } from "../collection-registry";
1
+ import { buildPermalink, buildRelativePermalink, resolveCollection, } from "../collection-registry";
2
2
  import { getNitrogenSettings, buildDynamicData, buildPageResponse, } from "./helpers";
3
3
  function toArray(value) {
4
4
  if (Array.isArray(value)) {
@@ -189,18 +189,19 @@ export const batchEndpoints = [
189
189
  else if (params.embed) {
190
190
  data = result.docs.map((doc) => {
191
191
  const dynamicData = buildDynamicData(doc, settings);
192
- return buildPageResponse(doc, settings, dynamicData);
192
+ return buildPageResponse(doc, settings, dynamicData, collectionSlug);
193
193
  });
194
194
  }
195
195
  else {
196
196
  data = result.docs.map((doc) => {
197
197
  const d = doc;
198
+ const slug = String(d.slug || "");
198
199
  return {
199
200
  id: d.id,
200
201
  title: String(d.title || ""),
201
- slug: String(d.slug || ""),
202
- permalink: `${settings.frontendUrl || ""}/${String(d.slug || "")}`,
203
- relative_permalink: `/${String(d.slug || "")}`,
202
+ slug,
203
+ permalink: buildPermalink(endpoint, slug, settings.frontendUrl),
204
+ relative_permalink: buildRelativePermalink(endpoint, slug),
204
205
  };
205
206
  });
206
207
  }
@@ -28,7 +28,7 @@ export function createCollectionEndpoints(collectionSlug, endpointPrefix) {
28
28
  limit: 0,
29
29
  depth: 1,
30
30
  });
31
- const items = result.docs.map((doc) => buildListItemResponse(doc, settings));
31
+ const items = result.docs.map((doc) => buildListItemResponse(doc, settings, collectionSlug));
32
32
  return Response.json(items);
33
33
  },
34
34
  },
@@ -76,7 +76,7 @@ export function createCollectionEndpoints(collectionSlug, endpointPrefix) {
76
76
  ]);
77
77
  const dynamicData = buildDynamicData(doc, settings);
78
78
  return Response.json({
79
- ...buildPageResponse(doc, settings, dynamicData),
79
+ ...buildPageResponse(doc, settings, dynamicData, collectionSlug),
80
80
  template: pageTemplate,
81
81
  headerTemplate,
82
82
  footerTemplate,
@@ -146,7 +146,7 @@ export function createCollectionEndpoints(collectionSlug, endpointPrefix) {
146
146
  const doc = result.docs[0];
147
147
  const dynamicData = buildDynamicData(doc, settings);
148
148
  return Response.json({
149
- ...buildPageResponse(doc, settings, dynamicData),
149
+ ...buildPageResponse(doc, settings, dynamicData, collectionSlug),
150
150
  template: pageTemplate,
151
151
  headerTemplate,
152
152
  footerTemplate,
@@ -173,7 +173,7 @@ export function createCollectionEndpoints(collectionSlug, endpointPrefix) {
173
173
  const doc = result.docs[0];
174
174
  const dynamicData = buildDynamicData(doc, settings);
175
175
  return Response.json({
176
- ...buildPageResponse(doc, settings, dynamicData),
176
+ ...buildPageResponse(doc, settings, dynamicData, collectionSlug),
177
177
  template: pageTemplate,
178
178
  headerTemplate,
179
179
  footerTemplate,
@@ -6,7 +6,7 @@ export interface TemplateRef {
6
6
  }
7
7
  export declare function formatDate(date: string | Date): string;
8
8
  export declare function buildDynamicData(doc: NitrogenPageDoc | NitrogenTemplateDoc, globalSettings?: NitrogenSettingsGlobal): JsonObject;
9
- export declare function buildPageResponse(doc: NitrogenPageDoc | NitrogenTemplateDoc, settings: NitrogenSettingsGlobal, dynamicData: JsonObject): {
9
+ export declare function buildPageResponse(doc: NitrogenPageDoc | NitrogenTemplateDoc, settings: NitrogenSettingsGlobal, dynamicData: JsonObject, collectionSlug?: string): {
10
10
  id: string | number;
11
11
  token: string;
12
12
  title: string;
@@ -29,7 +29,7 @@ export declare function buildPageResponse(doc: NitrogenPageDoc | NitrogenTemplat
29
29
  wysiwygColors: {};
30
30
  };
31
31
  };
32
- export declare function buildListItemResponse(doc: NitrogenPageDoc | NitrogenTemplateDoc, settings: NitrogenSettingsGlobal): {
32
+ export declare function buildListItemResponse(doc: NitrogenPageDoc | NitrogenTemplateDoc, settings: NitrogenSettingsGlobal, collectionSlug?: string): {
33
33
  id: string | number;
34
34
  title: string;
35
35
  slug: string;
@@ -1,3 +1,4 @@
1
+ import { buildPermalink, buildRelativePermalink } from '../collection-registry';
1
2
  export function formatDate(date) {
2
3
  const d = new Date(date);
3
4
  const pad = (n) => String(n).padStart(2, '0');
@@ -49,17 +50,18 @@ export function buildDynamicData(doc, globalSettings) {
49
50
  }
50
51
  return dynamicData;
51
52
  }
52
- export function buildPageResponse(doc, settings, dynamicData) {
53
+ export function buildPageResponse(doc, settings, dynamicData, collectionSlug = 'pages') {
53
54
  const pageSettings = 'pageSettings' in doc ? doc.pageSettings : undefined;
54
55
  const templateSettings = 'templateSettings' in doc ? doc.templateSettings : undefined;
56
+ const slug = String(doc.slug || '');
55
57
  return {
56
58
  id: doc.id,
57
59
  token: settings.licenseKey || '',
58
60
  title: doc.title,
59
61
  author: doc.author && typeof doc.author === 'object' ? doc.author.id : (doc.author || ''),
60
- slug: doc.slug,
61
- permalink: `${settings.frontendUrl || ''}/${doc.slug}`,
62
- relative_permalink: `/${doc.slug}`,
62
+ slug,
63
+ permalink: buildPermalink(collectionSlug, slug, settings.frontendUrl),
64
+ relative_permalink: buildRelativePermalink(collectionSlug, slug),
63
65
  content: doc.nitrogenData ? JSON.stringify(doc.nitrogenData) : '[]',
64
66
  dynamic_data: dynamicData,
65
67
  settings: pageSettings || templateSettings || {
@@ -72,15 +74,16 @@ export function buildPageResponse(doc, settings, dynamicData) {
72
74
  },
73
75
  };
74
76
  }
75
- export function buildListItemResponse(doc, settings) {
77
+ export function buildListItemResponse(doc, settings, collectionSlug = 'pages') {
76
78
  const pageSettings = 'pageSettings' in doc ? doc.pageSettings : undefined;
77
79
  const templateSettings = 'templateSettings' in doc ? doc.templateSettings : undefined;
80
+ const slug = String(doc.slug || '');
78
81
  return {
79
82
  id: doc.id,
80
83
  title: doc.title,
81
- slug: doc.slug,
82
- permalink: `${settings.frontendUrl || ''}/${doc.slug}`,
83
- relative_permalink: `/${doc.slug}`,
84
+ slug,
85
+ permalink: buildPermalink(collectionSlug, slug, settings.frontendUrl),
86
+ relative_permalink: buildRelativePermalink(collectionSlug, slug),
84
87
  content: doc.nitrogenData ? JSON.stringify(doc.nitrogenData) : '[]',
85
88
  settings: pageSettings || templateSettings || {},
86
89
  nitrogen_settings: {
@@ -1,4 +1,4 @@
1
- import { getNitrogenSettings, buildDynamicData, buildPageResponse, buildListItemResponse, requireAuth, } from './helpers';
1
+ import { getNitrogenSettings, buildDynamicData, buildPageResponse, buildListItemResponse, getTemplateForType, requireAuth, } from './helpers';
2
2
  export const templatesEndpoints = [
3
3
  // GET /api/nitrogen/v1/nitrogen-templates/slug/:slug — Get a single template by slug
4
4
  {
@@ -8,12 +8,16 @@ export const templatesEndpoints = [
8
8
  const { payload, routeParams } = req;
9
9
  const slug = routeParams?.slug;
10
10
  try {
11
- const result = await payload.find({
12
- collection: 'nitrogen-templates',
13
- where: { slug: { equals: slug } },
14
- limit: 1,
15
- depth: 1,
16
- });
11
+ const [result, headerTemplate, footerTemplate] = await Promise.all([
12
+ payload.find({
13
+ collection: 'nitrogen-templates',
14
+ where: { slug: { equals: slug } },
15
+ limit: 1,
16
+ depth: 1,
17
+ }),
18
+ getTemplateForType(payload, 'header'),
19
+ getTemplateForType(payload, 'footer'),
20
+ ]);
17
21
  const doc = result.docs[0];
18
22
  if (!doc) {
19
23
  return Response.json({ error: 'Not found' }, { status: 404 });
@@ -46,6 +50,12 @@ export const templatesEndpoints = [
46
50
  permalink: frontendBase ? `${frontendBase}${relativePermalink}` : relativePermalink,
47
51
  relative_permalink: relativePermalink,
48
52
  postType: associatedCollection || '',
53
+ headerTemplate: associatedCollection !== 'header' && associatedCollection !== 'footer'
54
+ ? headerTemplate
55
+ : null,
56
+ footerTemplate: associatedCollection !== 'header' && associatedCollection !== 'footer'
57
+ ? footerTemplate
58
+ : null,
49
59
  });
50
60
  }
51
61
  catch {
@@ -91,11 +101,15 @@ export const templatesEndpoints = [
91
101
  const { payload, routeParams } = req;
92
102
  const id = routeParams?.id;
93
103
  try {
94
- const doc = await payload.findByID({
95
- collection: 'nitrogen-templates',
96
- id,
97
- depth: 1,
98
- });
104
+ const [doc, headerTemplate, footerTemplate] = await Promise.all([
105
+ payload.findByID({
106
+ collection: 'nitrogen-templates',
107
+ id,
108
+ depth: 1,
109
+ }),
110
+ getTemplateForType(payload, 'header'),
111
+ getTemplateForType(payload, 'footer'),
112
+ ]);
99
113
  const settings = await getNitrogenSettings(payload);
100
114
  // Build dynamic data from the first document of the associated collection
101
115
  // so the template preview has real data to bind to
@@ -126,6 +140,12 @@ export const templatesEndpoints = [
126
140
  permalink: frontendBase ? `${frontendBase}${relativePermalink}` : relativePermalink,
127
141
  relative_permalink: relativePermalink,
128
142
  postType: associatedCollection || '',
143
+ headerTemplate: associatedCollection !== 'header' && associatedCollection !== 'footer'
144
+ ? headerTemplate
145
+ : null,
146
+ footerTemplate: associatedCollection !== 'header' && associatedCollection !== 'footer'
147
+ ? footerTemplate
148
+ : null,
129
149
  });
130
150
  }
131
151
  catch {
package/dist/index.d.ts CHANGED
@@ -10,6 +10,14 @@ export interface NitrogenConnectorPluginOptions {
10
10
  * Example: `collections: ['pages', 'blog-posts']`
11
11
  */
12
12
  collections?: string[];
13
+ /**
14
+ * Optional frontend route patterns for collections whose public URLs do not
15
+ * match the raw collection slug.
16
+ *
17
+ * Example:
18
+ * `collectionRoutes: { posts: '/blog/[slug]', patent: '/patents/[slug]' }`
19
+ */
20
+ collectionRoutes?: Record<string, string>;
13
21
  }
14
22
  export declare const nitrogenConnectorPlugin: (options?: NitrogenConnectorPluginOptions) => Plugin;
15
23
  export { NitrogenTemplates } from "./collections/NitrogenTemplates";
package/dist/index.js CHANGED
@@ -53,11 +53,12 @@ export const nitrogenConnectorPlugin = (options = {}) => (incomingConfig) => {
53
53
  ...batchEndpoints,
54
54
  ];
55
55
  // Register templates collection
56
- registerCollection("nitrogen-templates", "nitrogen-templates");
57
- registerCollection("nitrogen_template", "nitrogen-templates");
56
+ registerCollection("nitrogen-templates", "nitrogen-templates", "/nitrogen-templates/[slug]");
57
+ registerCollection("nitrogen_template", "nitrogen-templates", "/nitrogen-templates/[slug]");
58
58
  // Process collections
59
59
  const additionalCollections = options.collections || [];
60
60
  for (const slug of additionalCollections) {
61
+ const routePattern = options.collectionRoutes?.[slug];
61
62
  // Find the existing collection in the config
62
63
  const existingIndex = (config.collections || []).findIndex((col) => col.slug === slug);
63
64
  if (existingIndex === -1) {
@@ -125,7 +126,7 @@ export const nitrogenConnectorPlugin = (options = {}) => (incomingConfig) => {
125
126
  const collectionEndpoints = createCollectionEndpoints(slug, slug);
126
127
  config.endpoints = [...(config.endpoints || []), ...collectionEndpoints];
127
128
  // Register in the collection registry for the `all` endpoint
128
- registerCollection(slug, slug);
129
+ registerCollection(slug, slug, routePattern);
129
130
  }
130
131
  return config;
131
132
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitrogenbuilder/connector-payload",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "Nitrogen page builder connector plugin for Payload CMS 3.x",
5
5
  "author": "Leonardo Dentzien <leo@torchmedia.ca>",
6
6
  "type": "module",