@nitrogenbuilder/connector-payload 0.1.52 → 1.0.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.
@@ -77,15 +77,15 @@ function buildRelativePath(slug, routePattern, templateSlug) {
77
77
  export const NitrogenEditButtonRuntime = ({ collection, routePattern }) => {
78
78
  const [id, setId] = useState(undefined);
79
79
  const [token, setToken] = useState(undefined);
80
+ const [connectorToken, setConnectorToken] = useState(undefined);
80
81
  const [slug, setSlug] = useState(undefined);
81
82
  const [documentRelativePath, setDocumentRelativePath] = useState(undefined);
82
83
  const [persistedStatus, setPersistedStatus] = useState(undefined);
83
84
  const [frontendUrl, setFrontendUrl] = useState(undefined);
84
85
  const [instanceUrl, setInstanceUrl] = useState(undefined);
85
- const [authorId, setAuthorId] = useState(undefined);
86
86
  const [templateSlug, setTemplateSlug] = useState(undefined);
87
87
  const formStatus = useFormFields(([fields]) => fields?._status?.value);
88
- const { isPreviewEnabled, previewURL } = useLivePreviewContext();
88
+ const { previewURL } = useLivePreviewContext();
89
89
  useEffect(() => {
90
90
  const segments = window.location.pathname.split('/').filter(Boolean);
91
91
  const docId = segments.length >= 4 ? segments[3] : undefined;
@@ -128,21 +128,16 @@ export const NitrogenEditButtonRuntime = ({ collection, routePattern }) => {
128
128
  setTemplateSlug(null);
129
129
  });
130
130
  }
131
- fetch('/api/users/me')
132
- .then((res) => res.json())
133
- .then((data) => {
134
- if (data.user?.id) {
135
- setAuthorId(String(data.user.id));
136
- }
137
- })
138
- .catch((err) => {
139
- console.error('Failed to fetch current user:', err);
140
- });
141
131
  fetch('/api/globals/nitrogen-settings')
142
132
  .then((res) => res.json())
143
133
  .then((data) => {
134
+ // `token` authenticates the editor itself (license key); `connectorToken`
135
+ // is forwarded to the preview iframe to unlock draft content.
136
+ if (data.licenseKey) {
137
+ setToken(data.licenseKey);
138
+ }
144
139
  if (data.connectorToken) {
145
- setToken(data.connectorToken);
140
+ setConnectorToken(data.connectorToken);
146
141
  }
147
142
  const editorUrl = getPreferredEditorUrl(data);
148
143
  if (editorUrl) {
@@ -157,13 +152,14 @@ export const NitrogenEditButtonRuntime = ({ collection, routePattern }) => {
157
152
  console.error('Failed to fetch nitrogen settings:', err);
158
153
  });
159
154
  }, [collection, routePattern]);
160
- if (!id || !token || !authorId)
155
+ if (!id || !token)
161
156
  return null;
162
157
  const editorBase = instanceUrl ?? '';
163
158
  const isDevelopmentMode = isLocalAdminHost();
164
- const encodedAuthorId = encodeURIComponent(authorId);
165
159
  const developmentFlags = isDevelopmentMode ? '&development=true' : '';
166
- const editHref = `${editorBase}/nitrogen-editor?token=${encodeURIComponent(token)}&collection=${encodeURIComponent(collection)}&pageId=${id}&authorId=${encodedAuthorId}&author=${encodedAuthorId}${developmentFlags}`;
160
+ // No authorId here on purpose — the editor page injects identity as
161
+ // window.nitrogenUser, so a copied edit URL won't carry it.
162
+ const editHref = `${editorBase}/nitrogen-editor?token=${encodeURIComponent(token)}&connectorToken=${encodeURIComponent(connectorToken ?? '')}&collection=${encodeURIComponent(collection)}&pageId=${id}${developmentFlags}`;
167
163
  const viewRelativePath = collection === 'nitrogen-templates'
168
164
  ? `/nitrogen-templates/${trimSlashes(slug || '')}`
169
165
  : documentRelativePath ||
@@ -178,7 +174,6 @@ export const NitrogenEditButtonRuntime = ({ collection, routePattern }) => {
178
174
  : undefined;
179
175
  const viewAction = resolveNitrogenViewAction({
180
176
  documentStatus: formStatus ?? persistedStatus,
181
- isPreviewEnabled,
182
177
  previewURL,
183
178
  publicHref,
184
179
  });
@@ -2,9 +2,8 @@ export type NitrogenViewAction = {
2
2
  href: string;
3
3
  label: 'Preview Draft' | 'View Page';
4
4
  };
5
- export declare function resolveNitrogenViewAction({ documentStatus, isPreviewEnabled, previewURL, publicHref, }: {
5
+ export declare function resolveNitrogenViewAction({ documentStatus, previewURL, publicHref, }: {
6
6
  documentStatus?: unknown;
7
- isPreviewEnabled: boolean;
8
7
  previewURL?: string;
9
8
  publicHref?: string;
10
9
  }): NitrogenViewAction | null;
@@ -1,6 +1,6 @@
1
- export function resolveNitrogenViewAction({ documentStatus, isPreviewEnabled, previewURL, publicHref, }) {
1
+ export function resolveNitrogenViewAction({ documentStatus, previewURL, publicHref, }) {
2
2
  if (documentStatus === 'draft') {
3
- const href = isPreviewEnabled ? previewURL?.trim() : '';
3
+ const href = previewURL?.trim();
4
4
  return href ? { href, label: 'Preview Draft' } : null;
5
5
  }
6
6
  const href = publicHref?.trim();
@@ -1,2 +1,2 @@
1
- export declare const DEFAULT_EDITOR_CDN_VERSION = "0.5.30";
1
+ export declare const DEFAULT_EDITOR_CDN_VERSION = "1.3";
2
2
  export declare const NITROGEN_PACKAGE_NAMES: readonly ["@nitrogenbuilder/client", "@nitrogenbuilder/client-core", "@nitrogenbuilder/client-preact", "@nitrogenbuilder/client-react", "@nitrogenbuilder/connector-payload", "@nitrogenbuilder/editor", "@nitrogenbuilder/types"];
package/dist/constants.js CHANGED
@@ -1,4 +1,4 @@
1
- export const DEFAULT_EDITOR_CDN_VERSION = '0.5.30';
1
+ export const DEFAULT_EDITOR_CDN_VERSION = '1.3';
2
2
  export const NITROGEN_PACKAGE_NAMES = [
3
3
  '@nitrogenbuilder/client',
4
4
  '@nitrogenbuilder/client-core',
@@ -68,6 +68,9 @@ export function createNitrogenEditorPage(config) {
68
68
  type: "payload",
69
69
  apiUrl: getNitrogenApiUrl(isPreviewDevelopment),
70
70
  collection: params.collection,
71
+ // Shown as a "Sign in" button in the editor when the CMS session has
72
+ // expired (e.g. a save fails with 401/403).
73
+ loginUrl: "/admin/login",
71
74
  },
72
75
  siteUrl: siteUrl || "",
73
76
  urlMaps: nitrogenConfig.urlMaps || [],
@@ -87,10 +90,8 @@ export function createNitrogenEditorPage(config) {
87
90
  `window.nitrogenEditId = "${editId}";`,
88
91
  // Identity injected as a global (not via URL) so a copied edit URL
89
92
  // doesn't carry the original author's id/email. The editor reads
90
- // window.nitrogenUser, falling back to the authorId/author params below.
93
+ // window.nitrogenUser, falling back to the authorId/authorEmail params.
91
94
  `window.nitrogenUser = ${JSON.stringify({ id: String(user.id), email: user.email })};`,
92
- // Keep both legacy and current author params present for editor builds.
93
- `(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())}})();`,
94
95
  ].join(""),
95
96
  } }), _jsxs("div", { id: "root", children: [_jsx("div", { style: {
96
97
  position: "fixed",
@@ -203,7 +203,7 @@ export function createComponentInventoryEndpoints(args) {
203
203
  const authError = requireAuth(req);
204
204
  if (authError)
205
205
  return authError;
206
- const result = await reindexAllComponentInventory(req.payload, args.collections, args.componentManifest);
206
+ const result = await reindexAllComponentInventory(req.payload, args.collections, args.componentManifest, req);
207
207
  return Response.json({
208
208
  success: true,
209
209
  ...result,
package/dist/index.js CHANGED
@@ -57,7 +57,8 @@ export const nitrogenConnectorPlugin = (options = {}) => (incomingConfig) => {
57
57
  const createAfterChangeHook = (collectionSlug) => {
58
58
  return async ({ doc, req }) => {
59
59
  if (doc) {
60
- await reindexDocumentUsage(req.payload, collectionSlug, doc, collectionSlug === 'nitrogen-templates' ? 'template' : 'document');
60
+ // Pass `req` so inventory writes join the caller's transaction.
61
+ await reindexDocumentUsage(req.payload, collectionSlug, doc, collectionSlug === 'nitrogen-templates' ? 'template' : 'document', req);
61
62
  }
62
63
  return doc;
63
64
  };
@@ -66,7 +67,7 @@ export const nitrogenConnectorPlugin = (options = {}) => (incomingConfig) => {
66
67
  return async ({ doc, id, req, }) => {
67
68
  const sourceId = doc?.id ?? id;
68
69
  if (sourceId !== undefined) {
69
- await deleteDocumentUsage(req.payload, collectionSlug, sourceId);
70
+ await deleteDocumentUsage(req.payload, collectionSlug, sourceId, req);
70
71
  }
71
72
  return doc;
72
73
  };
@@ -1,5 +1,5 @@
1
1
  import type { ComponentManifestEntry } from '@nitrogenbuilder/types';
2
- import type { Payload, Where } from 'payload';
2
+ import type { Payload, PayloadRequest, Where } from 'payload';
3
3
  import type { NitrogenInventorySourceDoc } from '../types.js';
4
4
  import { type NitrogenComponentManifestInput } from './manifest.js';
5
5
  export declare const NITROGEN_COMPONENT_CATALOG_COLLECTION = "nitrogen-component-catalog";
@@ -23,9 +23,9 @@ export declare function findAllDocs<T extends object>(payload: Payload, collecti
23
23
  limit?: number;
24
24
  select?: Record<string, true>;
25
25
  where?: Where;
26
- }): Promise<T[]>;
27
- export declare function syncComponentCatalog(payload: Payload, manifestInput?: NitrogenComponentManifestInput): Promise<ComponentManifestEntry[]>;
28
- export declare function reindexDocumentUsage(payload: Payload, sourceCollection: string, doc: NitrogenInventorySourceDoc, sourceType?: 'document' | 'template'): Promise<number>;
29
- export declare function deleteDocumentUsage(payload: Payload, sourceCollection: string, sourceDocumentId: string | number): Promise<void>;
30
- export declare function reindexAllComponentInventory(payload: Payload, collections: string[], manifestInput?: NitrogenComponentManifestInput): Promise<ReindexResult>;
26
+ }, req?: PayloadRequest): Promise<T[]>;
27
+ export declare function syncComponentCatalog(payload: Payload, manifestInput?: NitrogenComponentManifestInput, req?: PayloadRequest): Promise<ComponentManifestEntry[]>;
28
+ export declare function reindexDocumentUsage(payload: Payload, sourceCollection: string, doc: NitrogenInventorySourceDoc, sourceType?: 'document' | 'template', req?: PayloadRequest): Promise<number>;
29
+ export declare function deleteDocumentUsage(payload: Payload, sourceCollection: string, sourceDocumentId: string | number, req?: PayloadRequest): Promise<void>;
30
+ export declare function reindexAllComponentInventory(payload: Payload, collections: string[], manifestInput?: NitrogenComponentManifestInput, req?: PayloadRequest): Promise<ReindexResult>;
31
31
  export {};
@@ -62,7 +62,7 @@ export function extractComponentUsageRecords(modules) {
62
62
  collectUsageFromTree(modules, 'modules', results);
63
63
  return results;
64
64
  }
65
- export async function findAllDocs(payload, collection, options) {
65
+ export async function findAllDocs(payload, collection, options, req) {
66
66
  const docs = [];
67
67
  let page = 1;
68
68
  let hasNextPage = true;
@@ -74,6 +74,7 @@ export async function findAllDocs(payload, collection, options) {
74
74
  page,
75
75
  overrideAccess: true,
76
76
  pagination: true,
77
+ req,
77
78
  select: options?.select,
78
79
  where: options?.where,
79
80
  });
@@ -83,16 +84,17 @@ export async function findAllDocs(payload, collection, options) {
83
84
  }
84
85
  return docs;
85
86
  }
86
- async function deleteUsageDocs(payload, docs) {
87
+ async function deleteUsageDocs(payload, docs, req) {
87
88
  for (const doc of docs) {
88
89
  await payload.delete({
89
90
  collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
90
91
  id: doc.id,
91
92
  overrideAccess: true,
93
+ req,
92
94
  });
93
95
  }
94
96
  }
95
- async function findUsageDocsForSource(payload, sourceCollection, sourceDocumentId) {
97
+ async function findUsageDocsForSource(payload, sourceCollection, sourceDocumentId, req) {
96
98
  return findAllDocs(payload, NITROGEN_COMPONENT_USAGE_COLLECTION, {
97
99
  limit: 100,
98
100
  select: {
@@ -112,15 +114,16 @@ async function findUsageDocsForSource(payload, sourceCollection, sourceDocumentI
112
114
  },
113
115
  ],
114
116
  },
115
- });
117
+ }, req);
116
118
  }
117
- async function createUsageDocs(payload, sourceCollection, sourceType, doc) {
119
+ async function createUsageDocs(payload, sourceCollection, sourceType, doc, req) {
118
120
  const sourceDocumentId = String(doc.id);
119
121
  const usageRecords = extractComponentUsageRecords(doc.nitrogenData);
120
122
  for (const record of usageRecords) {
121
123
  await payload.create({
122
124
  collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
123
125
  overrideAccess: true,
126
+ req,
124
127
  data: {
125
128
  usageKey: `${sourceCollection}:${sourceDocumentId}:${record.moduleId}:${record.modulePath}:${record.componentName}`,
126
129
  componentName: record.componentName,
@@ -141,10 +144,10 @@ async function createUsageDocs(payload, sourceCollection, sourceType, doc) {
141
144
  }
142
145
  return usageRecords.length;
143
146
  }
144
- export async function syncComponentCatalog(payload, manifestInput) {
147
+ export async function syncComponentCatalog(payload, manifestInput, req) {
145
148
  const manifest = await resolveComponentManifest(manifestInput);
146
149
  const entries = manifest.components || [];
147
- const existingDocs = await findAllDocs(payload, NITROGEN_COMPONENT_CATALOG_COLLECTION);
150
+ const existingDocs = await findAllDocs(payload, NITROGEN_COMPONENT_CATALOG_COLLECTION, undefined, req);
148
151
  const existingByName = new Map(existingDocs.map((doc) => [doc.componentName, doc]));
149
152
  const nextNames = new Set(entries.map((entry) => entry.name));
150
153
  for (const entry of entries) {
@@ -163,6 +166,7 @@ export async function syncComponentCatalog(payload, manifestInput) {
163
166
  id: existing.id,
164
167
  data,
165
168
  overrideAccess: true,
169
+ req,
166
170
  });
167
171
  }
168
172
  else {
@@ -170,6 +174,7 @@ export async function syncComponentCatalog(payload, manifestInput) {
170
174
  collection: NITROGEN_COMPONENT_CATALOG_COLLECTION,
171
175
  data,
172
176
  overrideAccess: true,
177
+ req,
173
178
  });
174
179
  }
175
180
  }
@@ -179,30 +184,31 @@ export async function syncComponentCatalog(payload, manifestInput) {
179
184
  collection: NITROGEN_COMPONENT_CATALOG_COLLECTION,
180
185
  id: existing.id,
181
186
  overrideAccess: true,
187
+ req,
182
188
  });
183
189
  }
184
190
  }
185
191
  return entries;
186
192
  }
187
- export async function reindexDocumentUsage(payload, sourceCollection, doc, sourceType = 'document') {
193
+ export async function reindexDocumentUsage(payload, sourceCollection, doc, sourceType = 'document', req) {
188
194
  const sourceDocumentId = String(doc.id);
189
- const docsForSource = await findUsageDocsForSource(payload, sourceCollection, sourceDocumentId);
190
- await deleteUsageDocs(payload, docsForSource);
191
- return createUsageDocs(payload, sourceCollection, sourceType, doc);
195
+ const docsForSource = await findUsageDocsForSource(payload, sourceCollection, sourceDocumentId, req);
196
+ await deleteUsageDocs(payload, docsForSource, req);
197
+ return createUsageDocs(payload, sourceCollection, sourceType, doc, req);
192
198
  }
193
- export async function deleteDocumentUsage(payload, sourceCollection, sourceDocumentId) {
194
- const docsForSource = await findUsageDocsForSource(payload, sourceCollection, String(sourceDocumentId));
195
- await deleteUsageDocs(payload, docsForSource);
199
+ export async function deleteDocumentUsage(payload, sourceCollection, sourceDocumentId, req) {
200
+ const docsForSource = await findUsageDocsForSource(payload, sourceCollection, String(sourceDocumentId), req);
201
+ await deleteUsageDocs(payload, docsForSource, req);
196
202
  }
197
- export async function reindexAllComponentInventory(payload, collections, manifestInput) {
198
- const entries = await syncComponentCatalog(payload, manifestInput);
203
+ export async function reindexAllComponentInventory(payload, collections, manifestInput, req) {
204
+ const entries = await syncComponentCatalog(payload, manifestInput, req);
199
205
  const usageDocs = await findAllDocs(payload, NITROGEN_COMPONENT_USAGE_COLLECTION, {
200
206
  limit: 200,
201
207
  select: {
202
208
  id: true,
203
209
  },
204
- });
205
- await deleteUsageDocs(payload, usageDocs);
210
+ }, req);
211
+ await deleteUsageDocs(payload, usageDocs, req);
206
212
  let documentCount = 0;
207
213
  let usageCount = 0;
208
214
  for (const collection of collections) {
@@ -216,10 +222,10 @@ export async function reindexAllComponentInventory(payload, collections, manifes
216
222
  _status: true,
217
223
  nitrogenData: true,
218
224
  },
219
- });
225
+ }, req);
220
226
  for (const doc of docs) {
221
227
  documentCount += 1;
222
- usageCount += await createUsageDocs(payload, collection, collection === 'nitrogen-templates' ? 'template' : 'document', doc);
228
+ usageCount += await createUsageDocs(payload, collection, collection === 'nitrogen-templates' ? 'template' : 'document', doc, req);
223
229
  }
224
230
  }
225
231
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitrogenbuilder/connector-payload",
3
- "version": "0.1.52",
3
+ "version": "1.0.0",
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",