@payloadcms/plugin-seo 4.0.0-internal.b8e7c89 → 4.0.0-internal.bf4bcce

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAKV,eAAe,EAChB,MAAM,YAAY,CAAA;AASnB,eAAO,MAAM,SAAS,wDAyRpB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAKV,eAAe,EAChB,MAAM,YAAY,CAAA;AASnB,eAAO,MAAM,SAAS,wDAmZpB,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { definePlugin } from 'payload';
1
+ import { canAccessAdmin, definePlugin, executeAccess, Forbidden, traverseFields, UnauthorizedError } from 'payload';
2
2
  import { deepMergeSimple } from 'payload/shared';
3
3
  import { MetaDescriptionField } from './fields/MetaDescription/index.js';
4
4
  import { MetaImageField } from './fields/MetaImage/index.js';
@@ -41,13 +41,107 @@ export const seoPlugin = definePlugin({
41
41
  }
42
42
  ];
43
43
  const collectionConfigBySlug = new Map();
44
+ const collectionGenerationTargetSlugs = new Set(pluginConfig.collections ?? []);
44
45
  for (const c of config.collections ?? []){
45
46
  collectionConfigBySlug.set(c.slug, c);
47
+ if (hasSEOGenerationField({
48
+ config,
49
+ fields: c.fields
50
+ })) {
51
+ collectionGenerationTargetSlugs.add(c.slug);
52
+ }
46
53
  }
47
54
  const globalConfigBySlug = new Map();
48
55
  for (const g of config.globals ?? []){
49
56
  globalConfigBySlug.set(g.slug, g);
50
57
  }
58
+ const authorizeGenerateTarget = async ({ data, req })=>{
59
+ if (!data || typeof data !== 'object') {
60
+ throw new Forbidden(req.t);
61
+ }
62
+ const collectionConfig = data.collectionSlug && collectionGenerationTargetSlugs.has(data.collectionSlug) ? collectionConfigBySlug.get(data.collectionSlug) : undefined;
63
+ const globalConfig = data.globalSlug && pluginConfig.globals?.includes(data.globalSlug) ? globalConfigBySlug.get(data.globalSlug) : undefined;
64
+ if (collectionConfig && !data.globalSlug) {
65
+ const dataDocumentID = data.doc && typeof data.doc === 'object' && 'id' in data.doc ? data.doc.id : undefined;
66
+ const documentIDs = [
67
+ data.id,
68
+ dataDocumentID
69
+ ].filter((id)=>id !== null && id !== undefined);
70
+ if (documentIDs.some((id)=>typeof id !== 'string' && typeof id !== 'number')) {
71
+ throw new Forbidden(req.t);
72
+ }
73
+ if (documentIDs.length === 2 && String(documentIDs[0]) !== String(documentIDs[1])) {
74
+ throw new Forbidden(req.t);
75
+ }
76
+ const documentID = documentIDs[0];
77
+ if (documentID !== undefined) {
78
+ const accessibleDoc = await req.payload.findByID({
79
+ id: documentID,
80
+ collection: collectionConfig.slug,
81
+ depth: 0,
82
+ disableErrors: true,
83
+ draft: true,
84
+ overrideAccess: false,
85
+ req,
86
+ trash: true,
87
+ user: req.user
88
+ });
89
+ if (!accessibleDoc) {
90
+ const { totalDocs } = await req.payload.count({
91
+ collection: collectionConfig.slug,
92
+ disableErrors: true,
93
+ overrideAccess: true,
94
+ req,
95
+ trash: true,
96
+ where: {
97
+ id: {
98
+ equals: documentID
99
+ }
100
+ }
101
+ });
102
+ if (totalDocs > 0) {
103
+ throw new Forbidden(req.t);
104
+ }
105
+ if (collectionConfig.access?.create) {
106
+ await executeAccess({
107
+ slug: collectionConfig.slug,
108
+ data: data.doc,
109
+ req
110
+ }, collectionConfig.access.create);
111
+ }
112
+ }
113
+ } else if (collectionConfig.access?.create) {
114
+ await executeAccess({
115
+ slug: collectionConfig.slug,
116
+ data: data.doc,
117
+ req
118
+ }, collectionConfig.access.create);
119
+ }
120
+ return {
121
+ collectionConfig,
122
+ globalConfig: undefined
123
+ };
124
+ }
125
+ if (globalConfig && !data.collectionSlug) {
126
+ const doc = await req.payload.findGlobal({
127
+ slug: globalConfig.slug,
128
+ depth: 0,
129
+ disableErrors: true,
130
+ draft: true,
131
+ overrideAccess: false,
132
+ req,
133
+ user: req.user
134
+ });
135
+ if (!doc) {
136
+ throw new Forbidden(req.t);
137
+ }
138
+ return {
139
+ collectionConfig: undefined,
140
+ globalConfig
141
+ };
142
+ }
143
+ throw new Forbidden(req.t);
144
+ };
51
145
  return {
52
146
  ...config,
53
147
  collections: config.collections?.map((collection)=>{
@@ -114,12 +208,19 @@ export const seoPlugin = definePlugin({
114
208
  ...config.endpoints ?? [],
115
209
  {
116
210
  handler: async (req)=>{
211
+ await authorizeGenerate({
212
+ req
213
+ });
117
214
  const data = await req.json?.();
118
215
  const reqData = data ?? req.data;
216
+ const { collectionConfig, globalConfig } = await authorizeGenerateTarget({
217
+ data: reqData,
218
+ req
219
+ });
119
220
  const result = pluginConfig.generateTitle ? await pluginConfig.generateTitle({
120
221
  ...data,
121
- collectionConfig: reqData.collectionSlug ? collectionConfigBySlug.get(reqData.collectionSlug) : undefined,
122
- globalConfig: reqData.globalSlug ? globalConfigBySlug.get(reqData.globalSlug) : undefined,
222
+ collectionConfig,
223
+ globalConfig,
123
224
  req
124
225
  }) : '';
125
226
  return new Response(JSON.stringify({
@@ -133,12 +234,19 @@ export const seoPlugin = definePlugin({
133
234
  },
134
235
  {
135
236
  handler: async (req)=>{
237
+ await authorizeGenerate({
238
+ req
239
+ });
136
240
  const data = await req.json?.();
137
241
  const reqData = data ?? req.data;
242
+ const { collectionConfig, globalConfig } = await authorizeGenerateTarget({
243
+ data: reqData,
244
+ req
245
+ });
138
246
  const result = pluginConfig.generateDescription ? await pluginConfig.generateDescription({
139
247
  ...data,
140
- collectionConfig: reqData.collectionSlug ? collectionConfigBySlug.get(reqData.collectionSlug) : undefined,
141
- globalConfig: reqData.globalSlug ? globalConfigBySlug.get(reqData.globalSlug) : undefined,
248
+ collectionConfig,
249
+ globalConfig,
142
250
  req
143
251
  }) : '';
144
252
  return new Response(JSON.stringify({
@@ -152,12 +260,19 @@ export const seoPlugin = definePlugin({
152
260
  },
153
261
  {
154
262
  handler: async (req)=>{
263
+ await authorizeGenerate({
264
+ req
265
+ });
155
266
  const data = await req.json?.();
156
267
  const reqData = data ?? req.data;
268
+ const { collectionConfig, globalConfig } = await authorizeGenerateTarget({
269
+ data: reqData,
270
+ req
271
+ });
157
272
  const result = pluginConfig.generateURL ? await pluginConfig.generateURL({
158
273
  ...data,
159
- collectionConfig: reqData.collectionSlug ? collectionConfigBySlug.get(reqData.collectionSlug) : undefined,
160
- globalConfig: reqData.globalSlug ? globalConfigBySlug.get(reqData.globalSlug) : undefined,
274
+ collectionConfig,
275
+ globalConfig,
161
276
  req
162
277
  }) : '';
163
278
  return new Response(JSON.stringify({
@@ -171,12 +286,19 @@ export const seoPlugin = definePlugin({
171
286
  },
172
287
  {
173
288
  handler: async (req)=>{
289
+ await authorizeGenerate({
290
+ req
291
+ });
174
292
  const data = await req.json?.();
175
293
  const reqData = data ?? req.data;
294
+ const { collectionConfig, globalConfig } = await authorizeGenerateTarget({
295
+ data: reqData,
296
+ req
297
+ });
176
298
  const result = pluginConfig.generateImage ? await pluginConfig.generateImage({
177
299
  ...data,
178
- collectionConfig: reqData.collectionSlug ? collectionConfigBySlug.get(reqData.collectionSlug) : undefined,
179
- globalConfig: reqData.globalSlug ? globalConfigBySlug.get(reqData.globalSlug) : undefined,
300
+ collectionConfig,
301
+ globalConfig,
180
302
  req
181
303
  }) : '';
182
304
  return new Response(JSON.stringify({
@@ -240,5 +362,38 @@ export const seoPlugin = definePlugin({
240
362
  };
241
363
  }
242
364
  });
365
+ const hasSEOGenerationField = ({ config, fields })=>{
366
+ let hasGenerationField = false;
367
+ traverseFields({
368
+ callback: ({ field })=>{
369
+ if (!('admin' in field)) {
370
+ return;
371
+ }
372
+ const fieldComponent = field.admin?.components?.Field;
373
+ const generationProp = fieldComponent && typeof fieldComponent === 'object' ? seoGenerationComponentProps[fieldComponent.path] : undefined;
374
+ if (generationProp && fieldComponent.clientProps?.[generationProp] === true) {
375
+ hasGenerationField = true;
376
+ return true;
377
+ }
378
+ },
379
+ config,
380
+ fields
381
+ });
382
+ return hasGenerationField;
383
+ };
384
+ const seoGenerationComponentProps = {
385
+ '@payloadcms/plugin-seo/client#MetaDescriptionComponent': 'hasGenerateDescriptionFn',
386
+ '@payloadcms/plugin-seo/client#MetaImageComponent': 'hasGenerateImageFn',
387
+ '@payloadcms/plugin-seo/client#MetaTitleComponent': 'hasGenerateTitleFn',
388
+ '@payloadcms/plugin-seo/client#PreviewComponent': 'hasGenerateURLFn'
389
+ };
390
+ const authorizeGenerate = async ({ req })=>{
391
+ if (!req.user) {
392
+ throw new UnauthorizedError(req.t);
393
+ }
394
+ await canAccessAdmin({
395
+ req
396
+ });
397
+ };
243
398
 
244
399
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Config, Field, GroupField, TabsField } from 'payload'\n\nimport { definePlugin } from 'payload'\nimport { deepMergeSimple } from 'payload/shared'\n\nimport type {\n GenerateDescription,\n GenerateImage,\n GenerateTitle,\n GenerateURL,\n SEOPluginConfig,\n} from './types.js'\n\nimport { MetaDescriptionField } from './fields/MetaDescription/index.js'\nimport { MetaImageField } from './fields/MetaImage/index.js'\nimport { MetaTitleField } from './fields/MetaTitle/index.js'\nimport { OverviewField } from './fields/Overview/index.js'\nimport { PreviewField } from './fields/Preview/index.js'\nimport { translations } from './translations/index.js'\n\nexport const seoPlugin = definePlugin<SEOPluginConfig>({\n slug: '@payloadcms/plugin-seo',\n plugin: ({ config, options: pluginConfig }) => {\n const defaultFields: Field[] = [\n OverviewField({}),\n MetaTitleField({\n hasGenerateFn: typeof pluginConfig?.generateTitle === 'function',\n }),\n MetaDescriptionField({\n hasGenerateFn: typeof pluginConfig?.generateDescription === 'function',\n }),\n ...(pluginConfig?.uploadsCollection\n ? [\n MetaImageField({\n hasGenerateFn: typeof pluginConfig?.generateImage === 'function',\n relationTo: pluginConfig.uploadsCollection as string,\n }),\n ]\n : []),\n PreviewField({\n hasGenerateFn: typeof pluginConfig?.generateURL === 'function',\n }),\n ]\n\n const seoFields: GroupField[] = [\n {\n name: 'meta',\n type: 'group',\n fields: [\n ...(pluginConfig?.fields && typeof pluginConfig.fields === 'function'\n ? pluginConfig.fields({ defaultFields })\n : defaultFields),\n ],\n interfaceName: pluginConfig.interfaceName,\n label: 'SEO',\n },\n ]\n\n const collectionConfigBySlug = new Map<string, NonNullable<Config['collections']>[number]>()\n for (const c of config.collections ?? []) {\n collectionConfigBySlug.set(c.slug, c)\n }\n const globalConfigBySlug = new Map<string, NonNullable<Config['globals']>[number]>()\n for (const g of config.globals ?? []) {\n globalConfigBySlug.set(g.slug, g)\n }\n\n return {\n ...config,\n collections:\n config.collections?.map((collection) => {\n const { slug } = collection\n const isEnabled = pluginConfig?.collections?.includes(slug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n // prevent issues with auth enabled collections having an email field that shouldn't be moved to the SEO tab\n const emailField =\n collection.auth &&\n !(typeof collection.auth === 'object' && collection.auth.disableLocalStrategy) &&\n collection.fields?.find((field) => 'name' in field && field.name === 'email')\n const hasOnlyEmailField = collection.fields?.length === 1 && emailField\n\n const seoTabs: TabsField[] = hasOnlyEmailField\n ? [\n {\n type: 'tabs',\n tabs: [\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n : [\n {\n type: 'tabs',\n tabs: [\n // append a new tab onto the end of the tabs array, if there is one at the first index\n // if needed, create a new `Content` tab in the first index for this collection's base fields\n ...(collection?.fields?.[0]?.type === 'tabs' &&\n collection?.fields?.[0]?.tabs\n ? collection.fields[0].tabs\n : [\n {\n fields: [\n ...(emailField\n ? collection.fields.filter(\n (field) => 'name' in field && field.name !== 'email',\n )\n : collection.fields),\n ],\n label: collection?.labels?.singular || 'Content',\n },\n ]),\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n\n return {\n ...collection,\n fields: [\n ...(emailField ? [emailField] : []),\n ...seoTabs,\n ...(collection?.fields?.[0]?.type === 'tabs' ? collection.fields.slice(1) : []),\n ],\n }\n }\n\n return {\n ...collection,\n fields: [...(collection?.fields || []), ...seoFields],\n }\n }\n\n return collection\n }) || [],\n endpoints: [\n ...(config.endpoints ?? []),\n {\n handler: async (req) => {\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n const reqData = data ?? req.data\n\n const result = pluginConfig.generateTitle\n ? await pluginConfig.generateTitle({\n ...data,\n collectionConfig: reqData.collectionSlug\n ? collectionConfigBySlug.get(reqData.collectionSlug)\n : undefined,\n globalConfig: reqData.globalSlug\n ? globalConfigBySlug.get(reqData.globalSlug)\n : undefined,\n req,\n } satisfies Parameters<GenerateTitle>[0])\n : ''\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-title',\n },\n {\n handler: async (req) => {\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n const reqData = data ?? req.data\n\n const result = pluginConfig.generateDescription\n ? await pluginConfig.generateDescription({\n ...data,\n collectionConfig: reqData.collectionSlug\n ? collectionConfigBySlug.get(reqData.collectionSlug)\n : undefined,\n globalConfig: reqData.globalSlug\n ? globalConfigBySlug.get(reqData.globalSlug)\n : undefined,\n req,\n } satisfies Parameters<GenerateDescription>[0])\n : ''\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-description',\n },\n {\n handler: async (req) => {\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n const reqData = data ?? req.data\n\n const result = pluginConfig.generateURL\n ? await pluginConfig.generateURL({\n ...data,\n collectionConfig: reqData.collectionSlug\n ? collectionConfigBySlug.get(reqData.collectionSlug)\n : undefined,\n globalConfig: reqData.globalSlug\n ? globalConfigBySlug.get(reqData.globalSlug)\n : undefined,\n req,\n } satisfies Parameters<GenerateURL>[0])\n : ''\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-url',\n },\n {\n handler: async (req) => {\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n const reqData = data ?? req.data\n\n const result = pluginConfig.generateImage\n ? await pluginConfig.generateImage({\n ...data,\n collectionConfig: reqData.collectionSlug\n ? collectionConfigBySlug.get(reqData.collectionSlug)\n : undefined,\n globalConfig: reqData.globalSlug\n ? globalConfigBySlug.get(reqData.globalSlug)\n : undefined,\n req,\n } satisfies Parameters<GenerateImage>[0])\n : ''\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-image',\n },\n ],\n globals:\n config.globals?.map((global) => {\n const { slug } = global\n const isEnabled = pluginConfig?.globals?.includes(slug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n const seoTabs: TabsField[] = [\n {\n type: 'tabs',\n tabs: [\n // append a new tab onto the end of the tabs array, if there is one at the first index\n // if needed, create a new `Content` tab in the first index for this global's base fields\n ...(global?.fields?.[0]?.type === 'tabs' && global?.fields?.[0].tabs\n ? global.fields[0].tabs\n : [\n {\n fields: [...(global?.fields || [])],\n label: global?.label || 'Content',\n },\n ]),\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n\n return {\n ...global,\n fields: [\n ...seoTabs,\n ...(global?.fields?.[0]?.type === 'tabs' ? global.fields.slice(1) : []),\n ],\n }\n }\n\n return {\n ...global,\n fields: [...(global?.fields || []), ...seoFields],\n }\n }\n\n return global\n }) || [],\n i18n: {\n ...config.i18n,\n translations: deepMergeSimple(translations, config.i18n?.translations ?? {}),\n },\n }\n },\n})\n"],"names":["definePlugin","deepMergeSimple","MetaDescriptionField","MetaImageField","MetaTitleField","OverviewField","PreviewField","translations","seoPlugin","slug","plugin","config","options","pluginConfig","defaultFields","hasGenerateFn","generateTitle","generateDescription","uploadsCollection","generateImage","relationTo","generateURL","seoFields","name","type","fields","interfaceName","label","collectionConfigBySlug","Map","c","collections","set","globalConfigBySlug","g","globals","map","collection","isEnabled","includes","tabbedUI","emailField","auth","disableLocalStrategy","find","field","hasOnlyEmailField","length","seoTabs","tabs","filter","labels","singular","slice","endpoints","handler","req","data","json","reqData","result","collectionConfig","collectionSlug","get","undefined","globalConfig","globalSlug","Response","JSON","stringify","status","method","path","global","i18n"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Config, Field, GroupField, PayloadRequest, TabsField } from 'payload'\n\nimport {\n canAccessAdmin,\n definePlugin,\n executeAccess,\n Forbidden,\n traverseFields,\n UnauthorizedError,\n} from 'payload'\nimport { deepMergeSimple } from 'payload/shared'\n\nimport type {\n GenerateDescription,\n GenerateImage,\n GenerateTitle,\n GenerateURL,\n SEOPluginConfig,\n} from './types.js'\n\nimport { MetaDescriptionField } from './fields/MetaDescription/index.js'\nimport { MetaImageField } from './fields/MetaImage/index.js'\nimport { MetaTitleField } from './fields/MetaTitle/index.js'\nimport { OverviewField } from './fields/Overview/index.js'\nimport { PreviewField } from './fields/Preview/index.js'\nimport { translations } from './translations/index.js'\n\nexport const seoPlugin = definePlugin<SEOPluginConfig>({\n slug: '@payloadcms/plugin-seo',\n plugin: ({ config, options: pluginConfig }) => {\n const defaultFields: Field[] = [\n OverviewField({}),\n MetaTitleField({\n hasGenerateFn: typeof pluginConfig?.generateTitle === 'function',\n }),\n MetaDescriptionField({\n hasGenerateFn: typeof pluginConfig?.generateDescription === 'function',\n }),\n ...(pluginConfig?.uploadsCollection\n ? [\n MetaImageField({\n hasGenerateFn: typeof pluginConfig?.generateImage === 'function',\n relationTo: pluginConfig.uploadsCollection as string,\n }),\n ]\n : []),\n PreviewField({\n hasGenerateFn: typeof pluginConfig?.generateURL === 'function',\n }),\n ]\n\n const seoFields: GroupField[] = [\n {\n name: 'meta',\n type: 'group',\n fields: [\n ...(pluginConfig?.fields && typeof pluginConfig.fields === 'function'\n ? pluginConfig.fields({ defaultFields })\n : defaultFields),\n ],\n interfaceName: pluginConfig.interfaceName,\n label: 'SEO',\n },\n ]\n\n const collectionConfigBySlug = new Map<string, NonNullable<Config['collections']>[number]>()\n const collectionGenerationTargetSlugs = new Set(pluginConfig.collections ?? [])\n for (const c of config.collections ?? []) {\n collectionConfigBySlug.set(c.slug, c)\n\n if (hasSEOGenerationField({ config, fields: c.fields })) {\n collectionGenerationTargetSlugs.add(c.slug)\n }\n }\n const globalConfigBySlug = new Map<string, NonNullable<Config['globals']>[number]>()\n for (const g of config.globals ?? []) {\n globalConfigBySlug.set(g.slug, g)\n }\n\n const authorizeGenerateTarget = async ({\n data,\n req,\n }: {\n data:\n | null\n | Omit<Parameters<GenerateTitle>[0], 'collectionConfig' | 'globalConfig' | 'req'>\n | undefined\n req: PayloadRequest\n }) => {\n if (!data || typeof data !== 'object') {\n throw new Forbidden(req.t)\n }\n\n const collectionConfig =\n data.collectionSlug && collectionGenerationTargetSlugs.has(data.collectionSlug)\n ? collectionConfigBySlug.get(data.collectionSlug)\n : undefined\n const globalConfig =\n data.globalSlug && pluginConfig.globals?.includes(data.globalSlug)\n ? globalConfigBySlug.get(data.globalSlug)\n : undefined\n\n if (collectionConfig && !data.globalSlug) {\n const dataDocumentID =\n data.doc && typeof data.doc === 'object' && 'id' in data.doc ? data.doc.id : undefined\n const documentIDs = [data.id, dataDocumentID].filter(\n (id) => id !== null && id !== undefined,\n )\n\n if (documentIDs.some((id) => typeof id !== 'string' && typeof id !== 'number')) {\n throw new Forbidden(req.t)\n }\n\n if (documentIDs.length === 2 && String(documentIDs[0]) !== String(documentIDs[1])) {\n throw new Forbidden(req.t)\n }\n\n const documentID = documentIDs[0] as number | string | undefined\n\n if (documentID !== undefined) {\n const accessibleDoc = await req.payload.findByID({\n id: documentID,\n collection: collectionConfig.slug,\n depth: 0,\n disableErrors: true,\n draft: true,\n overrideAccess: false,\n req,\n trash: true,\n user: req.user,\n })\n\n if (!accessibleDoc) {\n const { totalDocs } = await req.payload.count({\n collection: collectionConfig.slug,\n disableErrors: true,\n overrideAccess: true,\n req,\n trash: true,\n where: {\n id: {\n equals: documentID,\n },\n },\n })\n\n if (totalDocs > 0) {\n throw new Forbidden(req.t)\n }\n\n if (collectionConfig.access?.create) {\n await executeAccess(\n { slug: collectionConfig.slug, data: data.doc, req },\n collectionConfig.access.create,\n )\n }\n }\n } else if (collectionConfig.access?.create) {\n await executeAccess(\n { slug: collectionConfig.slug, data: data.doc, req },\n collectionConfig.access.create,\n )\n }\n\n return { collectionConfig, globalConfig: undefined }\n }\n\n if (globalConfig && !data.collectionSlug) {\n const doc = await req.payload.findGlobal({\n slug: globalConfig.slug,\n depth: 0,\n disableErrors: true,\n draft: true,\n overrideAccess: false,\n req,\n user: req.user,\n })\n\n if (!doc) {\n throw new Forbidden(req.t)\n }\n\n return { collectionConfig: undefined, globalConfig }\n }\n\n throw new Forbidden(req.t)\n }\n\n return {\n ...config,\n collections:\n config.collections?.map((collection) => {\n const { slug } = collection\n const isEnabled = pluginConfig?.collections?.includes(slug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n // prevent issues with auth enabled collections having an email field that shouldn't be moved to the SEO tab\n const emailField =\n collection.auth &&\n !(typeof collection.auth === 'object' && collection.auth.disableLocalStrategy) &&\n collection.fields?.find((field) => 'name' in field && field.name === 'email')\n const hasOnlyEmailField = collection.fields?.length === 1 && emailField\n\n const seoTabs: TabsField[] = hasOnlyEmailField\n ? [\n {\n type: 'tabs',\n tabs: [\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n : [\n {\n type: 'tabs',\n tabs: [\n // append a new tab onto the end of the tabs array, if there is one at the first index\n // if needed, create a new `Content` tab in the first index for this collection's base fields\n ...(collection?.fields?.[0]?.type === 'tabs' &&\n collection?.fields?.[0]?.tabs\n ? collection.fields[0].tabs\n : [\n {\n fields: [\n ...(emailField\n ? collection.fields.filter(\n (field) => 'name' in field && field.name !== 'email',\n )\n : collection.fields),\n ],\n label: collection?.labels?.singular || 'Content',\n },\n ]),\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n\n return {\n ...collection,\n fields: [\n ...(emailField ? [emailField] : []),\n ...seoTabs,\n ...(collection?.fields?.[0]?.type === 'tabs' ? collection.fields.slice(1) : []),\n ],\n }\n }\n\n return {\n ...collection,\n fields: [...(collection?.fields || []), ...seoFields],\n }\n }\n\n return collection\n }) || [],\n endpoints: [\n ...(config.endpoints ?? []),\n {\n handler: async (req) => {\n await authorizeGenerate({ req })\n\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n const reqData = data ?? req.data\n const { collectionConfig, globalConfig } = await authorizeGenerateTarget({\n data: reqData,\n req,\n })\n\n const result = pluginConfig.generateTitle\n ? await pluginConfig.generateTitle({\n ...data,\n collectionConfig,\n globalConfig,\n req,\n } satisfies Parameters<GenerateTitle>[0])\n : ''\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-title',\n },\n {\n handler: async (req) => {\n await authorizeGenerate({ req })\n\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n const reqData = data ?? req.data\n const { collectionConfig, globalConfig } = await authorizeGenerateTarget({\n data: reqData,\n req,\n })\n\n const result = pluginConfig.generateDescription\n ? await pluginConfig.generateDescription({\n ...data,\n collectionConfig,\n globalConfig,\n req,\n } satisfies Parameters<GenerateDescription>[0])\n : ''\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-description',\n },\n {\n handler: async (req) => {\n await authorizeGenerate({ req })\n\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n const reqData = data ?? req.data\n const { collectionConfig, globalConfig } = await authorizeGenerateTarget({\n data: reqData,\n req,\n })\n\n const result = pluginConfig.generateURL\n ? await pluginConfig.generateURL({\n ...data,\n collectionConfig,\n globalConfig,\n req,\n } satisfies Parameters<GenerateURL>[0])\n : ''\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-url',\n },\n {\n handler: async (req) => {\n await authorizeGenerate({ req })\n\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n const reqData = data ?? req.data\n const { collectionConfig, globalConfig } = await authorizeGenerateTarget({\n data: reqData,\n req,\n })\n\n const result = pluginConfig.generateImage\n ? await pluginConfig.generateImage({\n ...data,\n collectionConfig,\n globalConfig,\n req,\n } satisfies Parameters<GenerateImage>[0])\n : ''\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-image',\n },\n ],\n globals:\n config.globals?.map((global) => {\n const { slug } = global\n const isEnabled = pluginConfig?.globals?.includes(slug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n const seoTabs: TabsField[] = [\n {\n type: 'tabs',\n tabs: [\n // append a new tab onto the end of the tabs array, if there is one at the first index\n // if needed, create a new `Content` tab in the first index for this global's base fields\n ...(global?.fields?.[0]?.type === 'tabs' && global?.fields?.[0].tabs\n ? global.fields[0].tabs\n : [\n {\n fields: [...(global?.fields || [])],\n label: global?.label || 'Content',\n },\n ]),\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n\n return {\n ...global,\n fields: [\n ...seoTabs,\n ...(global?.fields?.[0]?.type === 'tabs' ? global.fields.slice(1) : []),\n ],\n }\n }\n\n return {\n ...global,\n fields: [...(global?.fields || []), ...seoFields],\n }\n }\n\n return global\n }) || [],\n i18n: {\n ...config.i18n,\n translations: deepMergeSimple(translations, config.i18n?.translations ?? {}),\n },\n }\n },\n})\n\nconst hasSEOGenerationField = ({\n config,\n fields,\n}: {\n config: Config\n fields: Field[]\n}): boolean => {\n let hasGenerationField = false\n\n traverseFields({\n callback: ({ field }) => {\n if (!('admin' in field)) {\n return\n }\n\n const fieldComponent = field.admin?.components?.Field\n const generationProp =\n fieldComponent && typeof fieldComponent === 'object'\n ? seoGenerationComponentProps[\n fieldComponent.path as keyof typeof seoGenerationComponentProps\n ]\n : undefined\n\n if (\n generationProp &&\n (fieldComponent as { clientProps?: Record<string, unknown> }).clientProps?.[\n generationProp\n ] === true\n ) {\n hasGenerationField = true\n\n return true\n }\n },\n config,\n fields,\n })\n\n return hasGenerationField\n}\n\nconst seoGenerationComponentProps = {\n '@payloadcms/plugin-seo/client#MetaDescriptionComponent': 'hasGenerateDescriptionFn',\n '@payloadcms/plugin-seo/client#MetaImageComponent': 'hasGenerateImageFn',\n '@payloadcms/plugin-seo/client#MetaTitleComponent': 'hasGenerateTitleFn',\n '@payloadcms/plugin-seo/client#PreviewComponent': 'hasGenerateURLFn',\n} as const\n\nconst authorizeGenerate = async ({ req }: { req: PayloadRequest }): Promise<void> => {\n if (!req.user) {\n throw new UnauthorizedError(req.t)\n }\n\n await canAccessAdmin({ req })\n}\n"],"names":["canAccessAdmin","definePlugin","executeAccess","Forbidden","traverseFields","UnauthorizedError","deepMergeSimple","MetaDescriptionField","MetaImageField","MetaTitleField","OverviewField","PreviewField","translations","seoPlugin","slug","plugin","config","options","pluginConfig","defaultFields","hasGenerateFn","generateTitle","generateDescription","uploadsCollection","generateImage","relationTo","generateURL","seoFields","name","type","fields","interfaceName","label","collectionConfigBySlug","Map","collectionGenerationTargetSlugs","Set","collections","c","set","hasSEOGenerationField","add","globalConfigBySlug","g","globals","authorizeGenerateTarget","data","req","t","collectionConfig","collectionSlug","has","get","undefined","globalConfig","globalSlug","includes","dataDocumentID","doc","id","documentIDs","filter","some","length","String","documentID","accessibleDoc","payload","findByID","collection","depth","disableErrors","draft","overrideAccess","trash","user","totalDocs","count","where","equals","access","create","findGlobal","map","isEnabled","tabbedUI","emailField","auth","disableLocalStrategy","find","field","hasOnlyEmailField","seoTabs","tabs","labels","singular","slice","endpoints","handler","authorizeGenerate","json","reqData","result","Response","JSON","stringify","status","method","path","global","i18n","hasGenerationField","callback","fieldComponent","admin","components","Field","generationProp","seoGenerationComponentProps","clientProps"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-seo",
3
- "version": "4.0.0-internal.b8e7c89",
3
+ "version": "4.0.0-internal.bf4bcce",
4
4
  "description": "SEO plugin for Payload",
5
5
  "keywords": [
6
6
  "payload",
@@ -57,20 +57,20 @@
57
57
  "dist"
58
58
  ],
59
59
  "dependencies": {
60
- "@payloadcms/translations": "4.0.0-internal.b8e7c89",
61
- "@payloadcms/ui": "4.0.0-internal.b8e7c89"
60
+ "@payloadcms/translations": "4.0.0-internal.bf4bcce",
61
+ "@payloadcms/ui": "4.0.0-internal.bf4bcce"
62
62
  },
63
63
  "devDependencies": {
64
- "@types/react": "19.2.14",
65
- "@types/react-dom": "19.2.3",
64
+ "@types/react": "19.3.0",
65
+ "@types/react-dom": "19.3.0",
66
66
  "@payloadcms/eslint-config": "3.28.0",
67
- "payload": "4.0.0-internal.b8e7c89",
68
- "@payloadcms/next": "4.0.0-internal.b8e7c89"
67
+ "payload": "4.0.0-internal.bf4bcce",
68
+ "@payloadcms/next": "4.0.0-internal.bf4bcce"
69
69
  },
70
70
  "peerDependencies": {
71
71
  "react": "^19.0.1 || ^19.1.2 || ^19.2.1",
72
72
  "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1",
73
- "payload": "4.0.0-internal.b8e7c89"
73
+ "payload": "4.0.0-internal.bf4bcce"
74
74
  },
75
75
  "publishConfig": {
76
76
  "registry": "https://registry.npmjs.org/"
@@ -82,7 +82,7 @@
82
82
  "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
83
83
  "build:types": "tsc --emitDeclarationOnly --outDir dist",
84
84
  "clean": "rimraf -g {dist,*.tsbuildinfo}",
85
- "copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
85
+ "copyfiles": "copyfiles -u 1 -e \"**/*.spec.*\" \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
86
86
  "lint": "eslint .",
87
87
  "lint:fix": "eslint . --fix"
88
88
  }