@ai-stack/payloadcms 3.2.13-beta → 3.2.15-beta

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/README.md CHANGED
@@ -154,6 +154,11 @@ export default buildConfig({
154
154
  [Posts.slug]: true,
155
155
  },
156
156
 
157
+ // Optional
158
+ globals: {
159
+ [Home.slug]: true,
160
+ },
161
+
157
162
  // Optional: Show debug logs to list AI-enabled fields
158
163
  debugging: false,
159
164
 
@@ -166,8 +171,12 @@ export default buildConfig({
166
171
  // Optional: Specify the media collection used by the gpt-image-1 model to reference images (defaults to media)
167
172
  uploadCollectionSlug: "media",
168
173
 
169
- // Optional: Restrict plugin settings to admin users only
174
+ // Optional: Access control for AI features
170
175
  access: {
176
+ // Control who can generate AI content
177
+ generate: ({ req }) => req.user?.role === 'admin',
178
+
179
+ // Control who can modify AI settings and prompts
171
180
  settings: ({ req }) => req.user?.role === 'admin',
172
181
  },
173
182
 
@@ -7,8 +7,7 @@ export function filterEditorSchemaByNodes(schema, allowedNodes) {
7
7
  if (isObjectSchema(def)) {
8
8
  const typeEnum = def.properties?.type?.enum;
9
9
  if (typeEnum && typeEnum.some((t)=>allowedTypes.has(t))) {
10
- filteredDefinitions[key] = JSON.parse(JSON.stringify(def)) // Deep copy to safely mutate
11
- ;
10
+ filteredDefinitions[key] = JSON.parse(JSON.stringify(def)); // Deep copy to safely mutate
12
11
  }
13
12
  }
14
13
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ai/utils/filterEditorSchemaByNodes.ts"],"sourcesContent":["import type { LexicalNodeSchema } from '../schemas/lexicalJsonSchema.js'\n\nimport { isObjectSchema } from './isObjectSchema.js'\n\nexport function filterEditorSchemaByNodes(schema: LexicalNodeSchema, allowedNodes) {\n const allowedTypes = new Set(allowedNodes)\n\n const filteredDefinitions = {}\n\n // First pass: collect definitions whose \"type.enum\" includes an allowed type\n for (const [key, def] of Object.entries(schema.definitions)) {\n if(isObjectSchema(def)) {\n const typeEnum = def.properties?.type?.enum\n if (typeEnum && typeEnum.some((t) => allowedTypes.has(t))) {\n filteredDefinitions[key] = JSON.parse(JSON.stringify(def)) // Deep copy to safely mutate\n }\n }\n }\n\n // Helper to check if a $ref points to an allowed definition\n const isAllowedRef = (ref) => {\n if (typeof ref !== 'string') return false\n const defName = ref.replace('#/definitions/', '')\n return defName in filteredDefinitions\n }\n\n // Second pass: update \"children\" in each definition to only include allowed refs\n for (const def of Object.values(filteredDefinitions)) {\n if (isObjectSchema(def) && def.properties?.children?.items) {\n const items = def.properties.children.items\n\n if (Array.isArray(items.anyOf)) {\n // Filter anyOf to only allowed $refs\n items.anyOf = items.anyOf.filter((entry) => isAllowedRef(entry.$ref))\n if (items.anyOf.length === 0) {\n delete def.properties.children\n }\n } else if (items.$ref && !isAllowedRef(items.$ref)) {\n delete def.properties.children\n }\n }\n }\n\n // Return the new schema with pruned definitions\n return {\n ...schema,\n definitions: filteredDefinitions,\n }\n}\n"],"names":["isObjectSchema","filterEditorSchemaByNodes","schema","allowedNodes","allowedTypes","Set","filteredDefinitions","key","def","Object","entries","definitions","typeEnum","properties","type","enum","some","t","has","JSON","parse","stringify","isAllowedRef","ref","defName","replace","values","children","items","Array","isArray","anyOf","filter","entry","$ref","length"],"mappings":"AAEA,SAASA,cAAc,QAAQ,sBAAqB;AAEpD,OAAO,SAASC,0BAA0BC,MAAyB,EAAEC,YAAY;IAC/E,MAAMC,eAAe,IAAIC,IAAIF;IAE7B,MAAMG,sBAAsB,CAAC;IAE7B,6EAA6E;IAC7E,KAAK,MAAM,CAACC,KAAKC,IAAI,IAAIC,OAAOC,OAAO,CAACR,OAAOS,WAAW,EAAG;QAC3D,IAAGX,eAAeQ,MAAM;YACtB,MAAMI,WAAWJ,IAAIK,UAAU,EAAEC,MAAMC;YACvC,IAAIH,YAAYA,SAASI,IAAI,CAAC,CAACC,IAAMb,aAAac,GAAG,CAACD,KAAK;gBACzDX,mBAAmB,CAACC,IAAI,GAAGY,KAAKC,KAAK,CAACD,KAAKE,SAAS,CAACb,MAAM,6BAA6B;;YAC1F;QACF;IACF;IAEA,4DAA4D;IAC5D,MAAMc,eAAe,CAACC;QACpB,IAAI,OAAOA,QAAQ,UAAU,OAAO;QACpC,MAAMC,UAAUD,IAAIE,OAAO,CAAC,kBAAkB;QAC9C,OAAOD,WAAWlB;IACpB;IAEA,iFAAiF;IACjF,KAAK,MAAME,OAAOC,OAAOiB,MAAM,CAACpB,qBAAsB;QACpD,IAAIN,eAAeQ,QAAQA,IAAIK,UAAU,EAAEc,UAAUC,OAAO;YAC1D,MAAMA,QAAQpB,IAAIK,UAAU,CAACc,QAAQ,CAACC,KAAK;YAE3C,IAAIC,MAAMC,OAAO,CAACF,MAAMG,KAAK,GAAG;gBAC9B,qCAAqC;gBACrCH,MAAMG,KAAK,GAAGH,MAAMG,KAAK,CAACC,MAAM,CAAC,CAACC,QAAUX,aAAaW,MAAMC,IAAI;gBACnE,IAAIN,MAAMG,KAAK,CAACI,MAAM,KAAK,GAAG;oBAC5B,OAAO3B,IAAIK,UAAU,CAACc,QAAQ;gBAChC;YACF,OAAO,IAAIC,MAAMM,IAAI,IAAI,CAACZ,aAAaM,MAAMM,IAAI,GAAG;gBAClD,OAAO1B,IAAIK,UAAU,CAACc,QAAQ;YAChC;QACF;IACF;IAEA,gDAAgD;IAChD,OAAO;QACL,GAAGzB,MAAM;QACTS,aAAaL;IACf;AACF"}
1
+ {"version":3,"sources":["../../../src/ai/utils/filterEditorSchemaByNodes.ts"],"sourcesContent":["import type { LexicalNodeSchema } from '../schemas/lexicalJsonSchema.js'\n\nimport { isObjectSchema } from './isObjectSchema.js'\n\nexport function filterEditorSchemaByNodes(schema: LexicalNodeSchema, allowedNodes) {\n const allowedTypes = new Set(allowedNodes)\n\n const filteredDefinitions = {}\n\n // First pass: collect definitions whose \"type.enum\" includes an allowed type\n for (const [key, def] of Object.entries(schema.definitions)) {\n if(isObjectSchema(def)) {\n const typeEnum = def.properties?.type?.enum\n if (typeEnum && typeEnum.some((t) => allowedTypes.has(t))) {\n filteredDefinitions[key] = JSON.parse(JSON.stringify(def)) // Deep copy to safely mutate\n }\n }\n }\n\n // Helper to check if a $ref points to an allowed definition\n const isAllowedRef = (ref) => {\n if (typeof ref !== 'string') return false\n const defName = ref.replace('#/definitions/', '')\n return defName in filteredDefinitions\n }\n\n // Second pass: update \"children\" in each definition to only include allowed refs\n for (const def of Object.values(filteredDefinitions)) {\n if (isObjectSchema(def) && def.properties?.children?.items) {\n const items = def.properties.children.items\n\n if (Array.isArray(items.anyOf)) {\n // Filter anyOf to only allowed $refs\n items.anyOf = items.anyOf.filter((entry) => isAllowedRef(entry.$ref))\n if (items.anyOf.length === 0) {\n delete def.properties.children\n }\n } else if (items.$ref && !isAllowedRef(items.$ref)) {\n delete def.properties.children\n }\n }\n }\n\n // Return the new schema with pruned definitions\n return {\n ...schema,\n definitions: filteredDefinitions,\n }\n}\n"],"names":["isObjectSchema","filterEditorSchemaByNodes","schema","allowedNodes","allowedTypes","Set","filteredDefinitions","key","def","Object","entries","definitions","typeEnum","properties","type","enum","some","t","has","JSON","parse","stringify","isAllowedRef","ref","defName","replace","values","children","items","Array","isArray","anyOf","filter","entry","$ref","length"],"mappings":"AAEA,SAASA,cAAc,QAAQ,sBAAqB;AAEpD,OAAO,SAASC,0BAA0BC,MAAyB,EAAEC,YAAY;IAC/E,MAAMC,eAAe,IAAIC,IAAIF;IAE7B,MAAMG,sBAAsB,CAAC;IAE7B,6EAA6E;IAC7E,KAAK,MAAM,CAACC,KAAKC,IAAI,IAAIC,OAAOC,OAAO,CAACR,OAAOS,WAAW,EAAG;QAC3D,IAAGX,eAAeQ,MAAM;YACtB,MAAMI,WAAWJ,IAAIK,UAAU,EAAEC,MAAMC;YACvC,IAAIH,YAAYA,SAASI,IAAI,CAAC,CAACC,IAAMb,aAAac,GAAG,CAACD,KAAK;gBACzDX,mBAAmB,CAACC,IAAI,GAAGY,KAAKC,KAAK,CAACD,KAAKE,SAAS,CAACb,OAAM,6BAA6B;YAC1F;QACF;IACF;IAEA,4DAA4D;IAC5D,MAAMc,eAAe,CAACC;QACpB,IAAI,OAAOA,QAAQ,UAAU,OAAO;QACpC,MAAMC,UAAUD,IAAIE,OAAO,CAAC,kBAAkB;QAC9C,OAAOD,WAAWlB;IACpB;IAEA,iFAAiF;IACjF,KAAK,MAAME,OAAOC,OAAOiB,MAAM,CAACpB,qBAAsB;QACpD,IAAIN,eAAeQ,QAAQA,IAAIK,UAAU,EAAEc,UAAUC,OAAO;YAC1D,MAAMA,QAAQpB,IAAIK,UAAU,CAACc,QAAQ,CAACC,KAAK;YAE3C,IAAIC,MAAMC,OAAO,CAACF,MAAMG,KAAK,GAAG;gBAC9B,qCAAqC;gBACrCH,MAAMG,KAAK,GAAGH,MAAMG,KAAK,CAACC,MAAM,CAAC,CAACC,QAAUX,aAAaW,MAAMC,IAAI;gBACnE,IAAIN,MAAMG,KAAK,CAACI,MAAM,KAAK,GAAG;oBAC5B,OAAO3B,IAAIK,UAAU,CAACc,QAAQ;gBAChC;YACF,OAAO,IAAIC,MAAMM,IAAI,IAAI,CAACZ,aAAaM,MAAMM,IAAI,GAAG;gBAClD,OAAO1B,IAAIK,UAAU,CAACc,QAAQ;YAChC;QACF;IACF;IAEA,gDAAgD;IAChD,OAAO;QACL,GAAGzB,MAAM;QACTS,aAAaL;IACf;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"Instructions.d.ts","sourceRoot":"","sources":["../../src/collections/Instructions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,SAAS,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAiChD,eAAO,MAAM,sBAAsB,GACjC,cAAc,YAAY,EAC1B,UAAU,OAAO,CAAC,gBAAgB,CAAC,KAElC,gBAgMA,CAAA"}
1
+ {"version":3,"file":"Instructions.d.ts","sourceRoot":"","sources":["../../src/collections/Instructions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,SAAS,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAsDhD,eAAO,MAAM,sBAAsB,GACjC,cAAc,YAAY,EAC1B,UAAU,OAAO,CAAC,gBAAgB,CAAC,KAElC,gBAgMA,CAAA"}
@@ -14,9 +14,30 @@ const modelOptions = (pluginConfig)=>getGenerationModels(pluginConfig).map((mode
14
14
  };
15
15
  });
16
16
  const defaultAccessConfig = {
17
- create: ()=>true,
18
- read: ()=>true,
19
- update: ()=>true
17
+ create: ({ req })=>{
18
+ if (!req.user) {
19
+ return false;
20
+ }
21
+ return true;
22
+ },
23
+ delete: ({ req })=>{
24
+ if (!req.user) {
25
+ return false;
26
+ }
27
+ return true;
28
+ },
29
+ read: ({ req })=>{
30
+ if (!req.user) {
31
+ return false;
32
+ }
33
+ return true;
34
+ },
35
+ update: ({ req })=>{
36
+ if (!req.user) {
37
+ return false;
38
+ }
39
+ return true;
40
+ }
20
41
  };
21
42
  const defaultAdminConfig = {
22
43
  group: 'Plugins',
@@ -38,7 +59,7 @@ export const instructionsCollection = (pluginConfig, options)=>({
38
59
  name: 'schema-path',
39
60
  type: 'text',
40
61
  admin: {
41
- description: "Please dont change this unless you're sure of what you're doing"
62
+ description: "Please don't change this unless you're sure of what you're doing"
42
63
  },
43
64
  unique: true
44
65
  },
@@ -46,7 +67,7 @@ export const instructionsCollection = (pluginConfig, options)=>({
46
67
  name: 'field-type',
47
68
  type: 'select',
48
69
  admin: {
49
- description: "Please dont change this unless you're sure of what you're doing"
70
+ description: "Please don't change this unless you're sure of what you're doing"
50
71
  },
51
72
  defaultValue: 'text',
52
73
  label: 'Field type',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/collections/Instructions.ts"],"sourcesContent":["import type { CollectionConfig, GroupField } from 'payload'\nimport type { PluginConfig } from 'src/types.js'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\nimport { getGenerationModels } from '../utilities/getGenerationModels.js'\n\nconst groupSettings = (pluginConfig: PluginConfig) =>\n getGenerationModels(pluginConfig).reduce((fields, model) => {\n if (model.settings) {\n fields.push(model.settings)\n }\n return fields\n }, [] as GroupField[])\n\nconst modelOptions = (pluginConfig: PluginConfig) =>\n getGenerationModels(pluginConfig).map((model) => {\n return {\n fields: model.fields,\n label: model.name,\n value: model.id,\n }\n })\n\nconst defaultAccessConfig = {\n create: () => true,\n read: () => true,\n update: () => true,\n}\n\nconst defaultAdminConfig = {\n group: 'Plugins',\n hidden: true,\n}\n\nexport const instructionsCollection = (\n pluginConfig: PluginConfig,\n options?: Partial<CollectionConfig>,\n) =>\n <CollectionConfig>{\n slug: PLUGIN_INSTRUCTIONS_TABLE,\n access: {\n ...defaultAccessConfig,\n ...options?.access,\n },\n admin: {\n ...defaultAdminConfig,\n ...options?.admin,\n group: 'Plugins',\n },\n fields: [\n {\n name: 'schema-path',\n type: 'text',\n admin: {\n description: \"Please don’t change this unless you're sure of what you're doing\",\n },\n unique: true,\n },\n {\n name: 'field-type',\n type: 'select',\n admin: {\n description: \"Please don’t change this unless you're sure of what you're doing\",\n },\n defaultValue: 'text',\n label: 'Field type',\n options: [\n {\n label: 'text',\n value: 'text',\n },\n {\n label: 'textarea',\n value: 'textarea',\n },\n {\n label: 'upload',\n value: 'upload',\n },\n {\n label: 'richText',\n value: 'richText',\n },\n ],\n },\n {\n name: 'relation-to',\n type: 'text',\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'upload'\n },\n },\n label: 'Relation to',\n },\n {\n name: 'model-id',\n type: 'select',\n admin: {\n components: {\n Field: {\n clientProps: {\n filterByField: 'field-type',\n options: modelOptions(pluginConfig),\n },\n path: '@ai-stack/payloadcms/fields#SelectField',\n },\n },\n },\n label: 'Model',\n options: modelOptions(pluginConfig).map((option) => {\n return {\n label: option.label,\n value: option.value,\n }\n }),\n },\n {\n id: 'ai-prompts-tabs',\n type: 'tabs',\n tabs: [\n {\n description:\n 'Define dynamic templates using {{ fieldName }}. Type { to see available field suggestions.',\n fields: [\n {\n name: 'prompt',\n type: 'textarea',\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/fields#PromptEditorField',\n },\n description: \"Click 'Compose' to run this custom prompt and generate content\",\n },\n label: '',\n },\n ],\n label: 'Prompt',\n },\n {\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'upload' && current['model-id'] === 'gpt-image-1'\n },\n },\n description:\n 'These images will be used to generate new visuals in a similar style, layout, or content. You can combine multiple references for more controlled results.',\n fields: [\n {\n name: 'images',\n type: 'array',\n fields: [\n {\n name: 'image',\n type: 'upload',\n admin: {\n description: 'Please make sure the image is publicly accessible.',\n },\n relationTo: pluginConfig.uploadCollectionSlug\n ? pluginConfig.uploadCollectionSlug\n : 'media',\n },\n ],\n },\n ],\n label: 'Sample Images',\n },\n {\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'richText'\n },\n },\n description: '',\n fields: [\n {\n name: 'system',\n type: 'textarea',\n defaultValue: `INSTRUCTIONS:\nYou are a highly skilled and professional blog writer,\nrenowned for crafting engaging and well-organized articles.\nWhen given a title, you meticulously create blogs that are not only\ninformative and accurate but also captivating and beautifully structured.`,\n label: '',\n },\n ],\n label: 'System prompt',\n },\n {\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'richText'\n },\n },\n description: '',\n fields: [\n {\n /** TODO:\n * - Layouts can be saved in as an array\n * - User can add their own layout to collections and use it later for generate specific rich text\n * - User can select previously added layout\n */\n name: 'layout',\n type: 'textarea',\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'richText'\n },\n },\n defaultValue: `[paragraph] - Write a concise introduction (2-3 sentences) that outlines the main topic.\n[horizontalrule] - Insert a horizontal rule to separate the introduction from the main content.\n[list] - Create a list with 3-5 items. Each list item should contain:\n a. [heading] - A brief, descriptive heading (up to 5 words)\n b. [paragraph] - A short explanation or elaboration (1-2 sentences)\n[horizontalrule] - Insert another horizontal rule to separate the main content from the conclusion.\n[paragraph] - Compose a brief conclusion (2-3 sentences) summarizing the key points.\n[quote] - Include a relevant quote from a famous person, directly related to the topic. Format: \"Quote text.\" - Author Name`,\n label: '',\n },\n ],\n label: 'Layout',\n },\n ],\n },\n ...groupSettings(pluginConfig),\n ],\n labels: {\n plural: 'Compose Settings',\n singular: 'Compose Setting',\n },\n }\n"],"names":["PLUGIN_INSTRUCTIONS_TABLE","getGenerationModels","groupSettings","pluginConfig","reduce","fields","model","settings","push","modelOptions","map","label","name","value","id","defaultAccessConfig","create","read","update","defaultAdminConfig","group","hidden","instructionsCollection","options","slug","access","admin","type","description","unique","defaultValue","condition","_","current","components","Field","clientProps","filterByField","path","option","tabs","relationTo","uploadCollectionSlug","labels","plural","singular"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/collections/Instructions.ts"],"sourcesContent":["import type { CollectionConfig, GroupField } from 'payload'\nimport type { PluginConfig } from 'src/types.js'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\nimport { getGenerationModels } from '../utilities/getGenerationModels.js'\n\nconst groupSettings = (pluginConfig: PluginConfig) =>\n getGenerationModels(pluginConfig).reduce((fields, model) => {\n if (model.settings) {\n fields.push(model.settings)\n }\n return fields\n }, [] as GroupField[])\n\nconst modelOptions = (pluginConfig: PluginConfig) =>\n getGenerationModels(pluginConfig).map((model) => {\n return {\n fields: model.fields,\n label: model.name,\n value: model.id,\n }\n })\n\nconst defaultAccessConfig = {\n create: ({ req }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n delete: ({ req }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n read: ({ req }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n update: ({ req }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n}\n\nconst defaultAdminConfig = {\n group: 'Plugins',\n hidden: true,\n}\n\nexport const instructionsCollection = (\n pluginConfig: PluginConfig,\n options?: Partial<CollectionConfig>,\n) =>\n <CollectionConfig>{\n slug: PLUGIN_INSTRUCTIONS_TABLE,\n access: {\n ...defaultAccessConfig,\n ...options?.access,\n },\n admin: {\n ...defaultAdminConfig,\n ...options?.admin,\n group: 'Plugins',\n },\n fields: [\n {\n name: 'schema-path',\n type: 'text',\n admin: {\n description: \"Please don't change this unless you're sure of what you're doing\",\n },\n unique: true,\n },\n {\n name: 'field-type',\n type: 'select',\n admin: {\n description: \"Please don't change this unless you're sure of what you're doing\",\n },\n defaultValue: 'text',\n label: 'Field type',\n options: [\n {\n label: 'text',\n value: 'text',\n },\n {\n label: 'textarea',\n value: 'textarea',\n },\n {\n label: 'upload',\n value: 'upload',\n },\n {\n label: 'richText',\n value: 'richText',\n },\n ],\n },\n {\n name: 'relation-to',\n type: 'text',\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'upload'\n },\n },\n label: 'Relation to',\n },\n {\n name: 'model-id',\n type: 'select',\n admin: {\n components: {\n Field: {\n clientProps: {\n filterByField: 'field-type',\n options: modelOptions(pluginConfig),\n },\n path: '@ai-stack/payloadcms/fields#SelectField',\n },\n },\n },\n label: 'Model',\n options: modelOptions(pluginConfig).map((option) => {\n return {\n label: option.label,\n value: option.value,\n }\n }),\n },\n {\n id: 'ai-prompts-tabs',\n type: 'tabs',\n tabs: [\n {\n description:\n 'Define dynamic templates using {{ fieldName }}. Type { to see available field suggestions.',\n fields: [\n {\n name: 'prompt',\n type: 'textarea',\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/fields#PromptEditorField',\n },\n description: \"Click 'Compose' to run this custom prompt and generate content\",\n },\n label: '',\n },\n ],\n label: 'Prompt',\n },\n {\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'upload' && current['model-id'] === 'gpt-image-1'\n },\n },\n description:\n 'These images will be used to generate new visuals in a similar style, layout, or content. You can combine multiple references for more controlled results.',\n fields: [\n {\n name: 'images',\n type: 'array',\n fields: [\n {\n name: 'image',\n type: 'upload',\n admin: {\n description: 'Please make sure the image is publicly accessible.',\n },\n relationTo: pluginConfig.uploadCollectionSlug\n ? pluginConfig.uploadCollectionSlug\n : 'media',\n },\n ],\n },\n ],\n label: 'Sample Images',\n },\n {\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'richText'\n },\n },\n description: '',\n fields: [\n {\n name: 'system',\n type: 'textarea',\n defaultValue: `INSTRUCTIONS:\nYou are a highly skilled and professional blog writer,\nrenowned for crafting engaging and well-organized articles.\nWhen given a title, you meticulously create blogs that are not only\ninformative and accurate but also captivating and beautifully structured.`,\n label: '',\n },\n ],\n label: 'System prompt',\n },\n {\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'richText'\n },\n },\n description: '',\n fields: [\n {\n /** TODO:\n * - Layouts can be saved in as an array\n * - User can add their own layout to collections and use it later for generate specific rich text\n * - User can select previously added layout\n */\n name: 'layout',\n type: 'textarea',\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'richText'\n },\n },\n defaultValue: `[paragraph] - Write a concise introduction (2-3 sentences) that outlines the main topic.\n[horizontalrule] - Insert a horizontal rule to separate the introduction from the main content.\n[list] - Create a list with 3-5 items. Each list item should contain:\n a. [heading] - A brief, descriptive heading (up to 5 words)\n b. [paragraph] - A short explanation or elaboration (1-2 sentences)\n[horizontalrule] - Insert another horizontal rule to separate the main content from the conclusion.\n[paragraph] - Compose a brief conclusion (2-3 sentences) summarizing the key points.\n[quote] - Include a relevant quote from a famous person, directly related to the topic. Format: \"Quote text.\" - Author Name`,\n label: '',\n },\n ],\n label: 'Layout',\n },\n ],\n },\n ...groupSettings(pluginConfig),\n ],\n labels: {\n plural: 'Compose Settings',\n singular: 'Compose Setting',\n },\n }\n"],"names":["PLUGIN_INSTRUCTIONS_TABLE","getGenerationModels","groupSettings","pluginConfig","reduce","fields","model","settings","push","modelOptions","map","label","name","value","id","defaultAccessConfig","create","req","user","delete","read","update","defaultAdminConfig","group","hidden","instructionsCollection","options","slug","access","admin","type","description","unique","defaultValue","condition","_","current","components","Field","clientProps","filterByField","path","option","tabs","relationTo","uploadCollectionSlug","labels","plural","singular"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/endpoints/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAmB,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAyE3E,eAAO,MAAM,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,SAwNhC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/endpoints/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAmB,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AA6F3E,eAAO,MAAM,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,SA+OhC,CAAA"}
@@ -7,6 +7,24 @@ import { handlebarsHelpersMap } from '../libraries/handlebars/helpersMap.js';
7
7
  import { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js';
8
8
  import { extractImageData } from '../utilities/extractImageData.js';
9
9
  import { getGenerationModels } from '../utilities/getGenerationModels.js';
10
+ const requireAuthentication = (req)=>{
11
+ if (!req.user) {
12
+ throw new Error('Authentication required. Please log in to use AI features.');
13
+ }
14
+ return true;
15
+ };
16
+ const checkAccess = async (req, pluginConfig)=>{
17
+ requireAuthentication(req);
18
+ if (pluginConfig.access?.generate) {
19
+ const hasAccess = await pluginConfig.access.generate({
20
+ req
21
+ });
22
+ if (!hasAccess) {
23
+ throw new Error('Insufficient permissions to use AI generation features.');
24
+ }
25
+ }
26
+ return true;
27
+ };
10
28
  const assignPrompt = async (action, { type, actionParams, context, field, layout, systemPrompt = '', template })=>{
11
29
  const prompt = await replacePlaceholders(template, context);
12
30
  const toLexicalHTML = type === 'richText' ? handlebarsHelpersMap.toHTML.name : '';
@@ -40,51 +58,55 @@ export const endpoints = (pluginConfig)=>({
40
58
  textarea: {
41
59
  //TODO: This is the main endpoint for generating content - its just needs to be renamed to 'generate' or something.
42
60
  handler: async (req)=>{
43
- const data = await req.json?.();
44
- const { allowedEditorNodes = [], locale = 'en', options } = data;
45
- const { action, actionParams, instructionId } = options;
46
- const contextData = data.doc;
47
- if (!instructionId) {
48
- throw new Error(`Instruction ID is required for "${PLUGIN_NAME}" to work, please check your configuration`);
49
- }
50
- const instructions = await req.payload.findByID({
51
- id: instructionId,
52
- collection: PLUGIN_INSTRUCTIONS_TABLE
53
- });
54
- const { collections } = req.payload.config;
55
- const collection = collections.find((collection)=>collection.slug === PLUGIN_INSTRUCTIONS_TABLE);
56
- const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin;
57
- const { schema: editorSchema = {} } = editorConfig;
58
- const { prompt: promptTemplate = '' } = instructions;
59
- let allowedEditorSchema = editorSchema;
60
- if (allowedEditorNodes.length) {
61
- allowedEditorSchema = filterEditorSchemaByNodes(editorSchema, allowedEditorNodes);
62
- }
63
- const schemaPath = instructions['schema-path'];
64
- const fieldName = schemaPath?.split('.').pop();
65
- registerEditorHelper(req.payload, schemaPath);
66
- const { defaultLocale, locales = [] } = req.payload.config.localization || {};
67
- const localeData = locales.find((l)=>{
68
- return l.code === locale;
69
- });
70
- const localeInfo = localeData?.label[defaultLocale] || locale;
71
- const model = getGenerationModels(pluginConfig).find((model)=>model.id === instructions['model-id']);
72
- // @ts-expect-error
73
- const settingsName = model.settings?.name;
74
- if (!settingsName) {
75
- req.payload.logger.error('— AI Plugin: Error fetching settings name!');
76
- }
77
- const modelOptions = instructions[settingsName] || {};
78
- const prompts = await assignPrompt(action, {
79
- type: instructions['field-type'],
80
- actionParams,
81
- context: contextData,
82
- field: fieldName,
83
- layout: instructions.layout,
84
- systemPrompt: instructions.system,
85
- template: promptTemplate
86
- });
87
61
  try {
62
+ // Check authentication and authorization first
63
+ await checkAccess(req, pluginConfig);
64
+ const data = await req.json?.();
65
+ const { allowedEditorNodes = [], locale = 'en', options } = data;
66
+ const { action, actionParams, instructionId } = options;
67
+ const contextData = data.doc;
68
+ if (!instructionId) {
69
+ throw new Error(`Instruction ID is required for "${PLUGIN_NAME}" to work, please check your configuration`);
70
+ }
71
+ // Verify user has access to the specific instruction
72
+ const instructions = await req.payload.findByID({
73
+ id: instructionId,
74
+ collection: PLUGIN_INSTRUCTIONS_TABLE,
75
+ req
76
+ });
77
+ const { collections } = req.payload.config;
78
+ const collection = collections.find((collection)=>collection.slug === PLUGIN_INSTRUCTIONS_TABLE);
79
+ const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin;
80
+ const { schema: editorSchema = {} } = editorConfig;
81
+ const { prompt: promptTemplate = '' } = instructions;
82
+ let allowedEditorSchema = editorSchema;
83
+ if (allowedEditorNodes.length) {
84
+ allowedEditorSchema = filterEditorSchemaByNodes(editorSchema, allowedEditorNodes);
85
+ }
86
+ const schemaPath = instructions['schema-path'];
87
+ const fieldName = schemaPath?.split('.').pop();
88
+ registerEditorHelper(req.payload, schemaPath);
89
+ const { defaultLocale, locales = [] } = req.payload.config.localization || {};
90
+ const localeData = locales.find((l)=>{
91
+ return l.code === locale;
92
+ });
93
+ const localeInfo = localeData?.label[defaultLocale] || locale;
94
+ const model = getGenerationModels(pluginConfig).find((model)=>model.id === instructions['model-id']);
95
+ // @ts-expect-error
96
+ const settingsName = model.settings?.name;
97
+ if (!settingsName) {
98
+ req.payload.logger.error('— AI Plugin: Error fetching settings name!');
99
+ }
100
+ const modelOptions = instructions[settingsName] || {};
101
+ const prompts = await assignPrompt(action, {
102
+ type: instructions['field-type'],
103
+ actionParams,
104
+ context: contextData,
105
+ field: fieldName,
106
+ layout: instructions.layout,
107
+ systemPrompt: instructions.system,
108
+ template: promptTemplate
109
+ });
88
110
  return model.handler?.(prompts.prompt, {
89
111
  ...modelOptions,
90
112
  editorSchema: allowedEditorSchema,
@@ -94,8 +116,13 @@ export const endpoints = (pluginConfig)=>({
94
116
  });
95
117
  } catch (error) {
96
118
  req.payload.logger.error('Error generating content: ', error);
97
- return new Response(JSON.stringify(error.message), {
98
- status: 500
119
+ return new Response(JSON.stringify({
120
+ error: error.message
121
+ }), {
122
+ headers: {
123
+ 'Content-Type': 'application/json'
124
+ },
125
+ status: error.message.includes('Authentication required') || error.message.includes('Insufficient permissions') ? 401 : 500
99
126
  });
100
127
  }
101
128
  },
@@ -104,107 +131,125 @@ export const endpoints = (pluginConfig)=>({
104
131
  },
105
132
  upload: {
106
133
  handler: async (req)=>{
107
- const data = await req.json?.();
108
- const { collectionSlug, documentId, options } = data;
109
- const { instructionId } = options;
110
- let docData = {};
111
- if (documentId) {
112
- try {
113
- docData = await req.payload.findByID({
114
- id: documentId,
115
- collection: collectionSlug,
116
- draft: true
134
+ try {
135
+ // Check authentication and authorization first
136
+ await checkAccess(req, pluginConfig);
137
+ const data = await req.json?.();
138
+ const { collectionSlug, documentId, options } = data;
139
+ const { instructionId } = options;
140
+ let docData = {};
141
+ if (documentId) {
142
+ try {
143
+ docData = await req.payload.findByID({
144
+ id: documentId,
145
+ collection: collectionSlug,
146
+ draft: true,
147
+ req
148
+ });
149
+ } catch (e) {
150
+ req.payload.logger.error('— AI Plugin: Error fetching document, you should try again after enabling drafts for this collection');
151
+ }
152
+ }
153
+ const contextData = {
154
+ ...data.doc,
155
+ ...docData
156
+ };
157
+ let instructions = {
158
+ images: [],
159
+ 'model-id': '',
160
+ prompt: ''
161
+ };
162
+ if (instructionId) {
163
+ // Verify user has access to the specific instruction
164
+ // @ts-expect-error
165
+ instructions = await req.payload.findByID({
166
+ id: instructionId,
167
+ collection: PLUGIN_INSTRUCTIONS_TABLE,
168
+ req
117
169
  });
118
- } catch (e) {
119
- req.payload.logger.error('— AI Plugin: Error fetching document, you should try again after enabling drafts for this collection');
120
170
  }
121
- }
122
- const contextData = {
123
- ...data.doc,
124
- ...docData
125
- };
126
- let instructions = {
127
- images: [],
128
- 'model-id': '',
129
- prompt: ''
130
- };
131
- if (instructionId) {
171
+ const { images: sampleImages = [], prompt: promptTemplate = '' } = instructions;
172
+ const schemaPath = instructions['schema-path'];
173
+ registerEditorHelper(req.payload, schemaPath);
174
+ const text = await replacePlaceholders(promptTemplate, contextData);
175
+ const modelId = instructions['model-id'];
176
+ const uploadCollectionSlug = instructions['relation-to'];
177
+ const images = [
178
+ ...extractImageData(text),
179
+ ...sampleImages
180
+ ];
181
+ const editImages = [];
182
+ for (const img of images){
183
+ try {
184
+ const serverURL = req.payload.config?.serverURL || process.env.SERVER_URL || process.env.NEXT_PUBLIC_SERVER_URL;
185
+ const response = await fetch(`${serverURL}${img.image.url}`, {
186
+ headers: {
187
+ //TODO: Further testing needed or so find a proper way.
188
+ Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`
189
+ },
190
+ method: 'GET'
191
+ });
192
+ const blob = await response.blob();
193
+ editImages.push({
194
+ name: img.image.name,
195
+ type: img.image.type,
196
+ data: blob,
197
+ size: blob.size,
198
+ url: `${serverURL}${img.image.url}`
199
+ });
200
+ } catch (e) {
201
+ req.payload.logger.error('Error fetching reference images!');
202
+ console.error(e);
203
+ throw Error("We couldn't fetch the images. Please ensure the images are accessible and hosted publicly.");
204
+ }
205
+ }
206
+ const model = getGenerationModels(pluginConfig).find((model)=>model.id === modelId);
132
207
  // @ts-expect-error
133
- instructions = await req.payload.findByID({
134
- id: instructionId,
135
- collection: PLUGIN_INSTRUCTIONS_TABLE
136
- });
137
- }
138
- const { images: sampleImages = [], prompt: promptTemplate = '' } = instructions;
139
- const schemaPath = instructions['schema-path'];
140
- registerEditorHelper(req.payload, schemaPath);
141
- const text = await replacePlaceholders(promptTemplate, contextData);
142
- const modelId = instructions['model-id'];
143
- const uploadCollectionSlug = instructions['relation-to'];
144
- const images = [
145
- ...extractImageData(text),
146
- ...sampleImages
147
- ];
148
- const editImages = [];
149
- for (const img of images){
150
- try {
151
- const serverURL = req.payload.config?.serverURL || process.env.SERVER_URL || process.env.NEXT_PUBLIC_SERVER_URL;
152
- const response = await fetch(`${serverURL}${img.image.url}`, {
153
- headers: {
154
- //TODO: Further testing needed or so find a proper way.
155
- Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`
156
- },
157
- method: 'GET'
208
+ const settingsName = model.settings?.name;
209
+ if (!settingsName) {
210
+ req.payload.logger.error('— AI Plugin: Error fetching settings name!');
211
+ }
212
+ let modelOptions = instructions[settingsName] || {};
213
+ modelOptions = {
214
+ ...modelOptions,
215
+ images: editImages
216
+ };
217
+ const result = await model.handler?.(text, modelOptions);
218
+ let assetData;
219
+ if (typeof pluginConfig.mediaUpload === 'function') {
220
+ assetData = await pluginConfig.mediaUpload(result, {
221
+ collection: uploadCollectionSlug,
222
+ request: req
158
223
  });
159
- const blob = await response.blob();
160
- editImages.push({
161
- name: img.image.name,
162
- type: img.image.type,
163
- data: blob,
164
- size: blob.size,
165
- url: `${serverURL}${img.image.url}`
224
+ } else {
225
+ assetData = await req.payload.create({
226
+ collection: uploadCollectionSlug,
227
+ data: result.data,
228
+ file: result.file,
229
+ req
166
230
  });
167
- } catch (e) {
168
- req.payload.logger.error('Error fetching reference images!');
169
- console.error(e);
170
- throw Error("We couldn't fetch the images. Please ensure the images are accessible and hosted publicly.");
171
231
  }
172
- }
173
- const model = getGenerationModels(pluginConfig).find((model)=>model.id === modelId);
174
- // @ts-expect-error
175
- const settingsName = model.settings?.name;
176
- if (!settingsName) {
177
- req.payload.logger.error('— AI Plugin: Error fetching settings name!');
178
- }
179
- let modelOptions = instructions[settingsName] || {};
180
- modelOptions = {
181
- ...modelOptions,
182
- images: editImages
183
- };
184
- const result = await model.handler?.(text, modelOptions);
185
- let assetData;
186
- if (typeof pluginConfig.mediaUpload === 'function') {
187
- assetData = await pluginConfig.mediaUpload(result, {
188
- collection: uploadCollectionSlug,
189
- request: req
190
- });
191
- } else {
192
- assetData = await req.payload.create({
193
- collection: uploadCollectionSlug,
194
- data: result.data,
195
- file: result.file
232
+ if (!assetData.id) {
233
+ req.payload.logger.error('Error uploading generated media, is your media upload function correct?');
234
+ throw new Error('Error uploading generated media!');
235
+ }
236
+ return new Response(JSON.stringify({
237
+ result: {
238
+ id: assetData.id,
239
+ alt: assetData.alt
240
+ }
241
+ }));
242
+ } catch (error) {
243
+ req.payload.logger.error('Error generating upload: ', error);
244
+ return new Response(JSON.stringify({
245
+ error: error.message
246
+ }), {
247
+ headers: {
248
+ 'Content-Type': 'application/json'
249
+ },
250
+ status: error.message.includes('Authentication required') || error.message.includes('Insufficient permissions') ? 401 : 500
196
251
  });
197
252
  }
198
- if (!assetData.id) {
199
- req.payload.logger.error('Error uploading generated media, is your media upload function correct?');
200
- throw new Error('Error uploading generated media!');
201
- }
202
- return new Response(JSON.stringify({
203
- result: {
204
- id: assetData.id,
205
- alt: assetData.alt
206
- }
207
- }));
208
253
  },
209
254
  method: 'post',
210
255
  path: PLUGIN_API_ENDPOINT_GENERATE_UPLOAD
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoints/index.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport * as process from 'node:process'\n\nimport type { ActionMenuItems, Endpoints, PluginConfig } from '../types.js'\n\nimport { defaultPrompts } from '../ai/prompts.js'\nimport { filterEditorSchemaByNodes } from '../ai/utils/filterEditorSchemaByNodes.js'\nimport {\n PLUGIN_API_ENDPOINT_GENERATE,\n PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_NAME,\n} from '../defaults.js'\nimport { registerEditorHelper } from '../libraries/handlebars/helpers.js'\nimport { handlebarsHelpersMap } from '../libraries/handlebars/helpersMap.js'\nimport { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js'\nimport { extractImageData } from '../utilities/extractImageData.js'\nimport { getGenerationModels } from '../utilities/getGenerationModels.js'\n\nconst assignPrompt = async (\n action: ActionMenuItems,\n {\n type,\n actionParams,\n context,\n field,\n layout,\n systemPrompt = '',\n template,\n }: {\n actionParams: Record<any, any>\n context: object\n field: string\n layout: string\n systemPrompt: string\n template: string\n type: string\n },\n) => {\n const prompt = await replacePlaceholders(template, context)\n const toLexicalHTML = type === 'richText' ? handlebarsHelpersMap.toHTML.name : ''\n\n const assignedPrompts = {\n layout: type === 'richText' ? layout : undefined,\n prompt,\n //TODO: Define only once on a collection level\n system: type === 'richText' ? systemPrompt : undefined,\n }\n\n if (action === 'Compose') {\n return assignedPrompts\n }\n\n const { layout: getLayout, system: getSystemPrompt } = defaultPrompts.find(\n (p) => p.name === action,\n )\n\n let updatedLayout = layout\n if (getLayout) {\n updatedLayout = getLayout()\n }\n\n const system = getSystemPrompt({\n ...(actionParams || {}),\n prompt,\n systemPrompt,\n })\n\n return {\n layout: updatedLayout,\n // TODO: revisit this toLexicalHTML\n prompt: await replacePlaceholders(`{{${toLexicalHTML} ${field}}}`, context),\n system,\n }\n}\n\nexport const endpoints: (pluginConfig: PluginConfig) => Endpoints = (pluginConfig) =>\n ({\n textarea: {\n //TODO: This is the main endpoint for generating content - its just needs to be renamed to 'generate' or something.\n handler: async (req: PayloadRequest) => {\n const data = await req.json?.()\n\n const { allowedEditorNodes = [], locale = 'en', options } = data\n const { action, actionParams, instructionId } = options\n const contextData = data.doc\n\n if (!instructionId) {\n throw new Error(\n `Instruction ID is required for \"${PLUGIN_NAME}\" to work, please check your configuration`,\n )\n }\n\n const instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n })\n\n const { collections } = req.payload.config\n const collection = collections.find(\n (collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE,\n )\n\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin\n const { schema: editorSchema = {} } = editorConfig\n const { prompt: promptTemplate = '' } = instructions\n\n let allowedEditorSchema = editorSchema\n if (allowedEditorNodes.length) {\n allowedEditorSchema = filterEditorSchemaByNodes(editorSchema, allowedEditorNodes)\n }\n\n const schemaPath = instructions['schema-path'] as string\n const fieldName = schemaPath?.split('.').pop()\n\n registerEditorHelper(req.payload, schemaPath)\n\n const { defaultLocale, locales = [] } = req.payload.config.localization || {}\n const localeData = locales.find((l) => {\n return l.code === locale\n })\n\n const localeInfo = localeData?.label[defaultLocale] || locale\n\n const model = getGenerationModels(pluginConfig).find(\n (model) => model.id === instructions['model-id'],\n )\n\n // @ts-expect-error\n const settingsName = model.settings?.name\n if (!settingsName) {\n req.payload.logger.error('— AI Plugin: Error fetching settings name!')\n }\n\n const modelOptions = instructions[settingsName] || {}\n\n const prompts = await assignPrompt(action, {\n type: instructions['field-type'] as string,\n actionParams,\n context: contextData,\n field: fieldName,\n layout: instructions.layout,\n systemPrompt: instructions.system,\n template: promptTemplate as string,\n })\n\n try {\n return model.handler?.(prompts.prompt, {\n ...modelOptions,\n editorSchema: allowedEditorSchema,\n layout: prompts.layout,\n locale: localeInfo,\n system: prompts.system,\n })\n } catch (error) {\n req.payload.logger.error('Error generating content: ', error)\n return new Response(JSON.stringify(error.message), { status: 500 })\n }\n },\n method: 'post',\n path: PLUGIN_API_ENDPOINT_GENERATE,\n },\n upload: {\n handler: async (req: PayloadRequest) => {\n const data = await req.json?.()\n\n const { collectionSlug, documentId, options } = data\n const { instructionId } = options\n let docData = {}\n\n if (documentId) {\n try {\n docData = await req.payload.findByID({\n id: documentId,\n collection: collectionSlug,\n draft: true,\n })\n } catch (e) {\n req.payload.logger.error(\n '— AI Plugin: Error fetching document, you should try again after enabling drafts for this collection',\n )\n }\n }\n\n const contextData = {\n ...data.doc,\n ...docData,\n }\n\n let instructions = { images: [], 'model-id': '', prompt: '' }\n\n if (instructionId) {\n // @ts-expect-error\n instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n })\n }\n\n const { images: sampleImages = [], prompt: promptTemplate = '' } = instructions\n const schemaPath = instructions['schema-path']\n\n registerEditorHelper(req.payload, schemaPath)\n\n const text = await replacePlaceholders(promptTemplate, contextData)\n const modelId = instructions['model-id']\n const uploadCollectionSlug = instructions['relation-to']\n\n const images = [...extractImageData(text), ...sampleImages]\n\n const editImages = []\n for (const img of images) {\n try {\n const serverURL =\n req.payload.config?.serverURL ||\n process.env.SERVER_URL ||\n process.env.NEXT_PUBLIC_SERVER_URL\n\n const response = await fetch(`${serverURL}${img.image.url}`, {\n headers: {\n //TODO: Further testing needed or so find a proper way.\n Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`,\n },\n method: 'GET',\n })\n\n const blob = await response.blob()\n editImages.push({\n name: img.image.name,\n type: img.image.type,\n data: blob,\n size: blob.size,\n url: `${serverURL}${img.image.url}`,\n })\n } catch (e) {\n req.payload.logger.error('Error fetching reference images!')\n console.error(e)\n throw Error(\n \"We couldn't fetch the images. Please ensure the images are accessible and hosted publicly.\",\n )\n }\n }\n\n const model = getGenerationModels(pluginConfig).find((model) => model.id === modelId)\n\n // @ts-expect-error\n const settingsName = model.settings?.name\n if (!settingsName) {\n req.payload.logger.error('— AI Plugin: Error fetching settings name!')\n }\n\n let modelOptions = instructions[settingsName] || {}\n modelOptions = {\n ...modelOptions,\n images: editImages,\n }\n\n const result = await model.handler?.(text, modelOptions)\n let assetData: { alt?: string; id: number | string }\n\n if (typeof pluginConfig.mediaUpload === 'function') {\n assetData = await pluginConfig.mediaUpload(result, {\n collection: uploadCollectionSlug,\n request: req,\n })\n } else {\n assetData = await req.payload.create({\n collection: uploadCollectionSlug,\n data: result.data,\n file: result.file,\n })\n }\n\n if (!assetData.id) {\n req.payload.logger.error(\n 'Error uploading generated media, is your media upload function correct?',\n )\n throw new Error('Error uploading generated media!')\n }\n\n return new Response(\n JSON.stringify({\n result: {\n id: assetData.id,\n alt: assetData.alt,\n },\n }),\n )\n },\n method: 'post',\n path: PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n },\n }) satisfies Endpoints\n"],"names":["process","defaultPrompts","filterEditorSchemaByNodes","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","registerEditorHelper","handlebarsHelpersMap","replacePlaceholders","extractImageData","getGenerationModels","assignPrompt","action","type","actionParams","context","field","layout","systemPrompt","template","prompt","toLexicalHTML","toHTML","name","assignedPrompts","undefined","system","getLayout","getSystemPrompt","find","p","updatedLayout","endpoints","pluginConfig","textarea","handler","req","data","json","allowedEditorNodes","locale","options","instructionId","contextData","doc","Error","instructions","payload","findByID","id","collection","collections","config","slug","custom","editorConfig","admin","schema","editorSchema","promptTemplate","allowedEditorSchema","length","schemaPath","fieldName","split","pop","defaultLocale","locales","localization","localeData","l","code","localeInfo","label","model","settingsName","settings","logger","error","modelOptions","prompts","Response","JSON","stringify","message","status","method","path","upload","collectionSlug","documentId","docData","draft","e","images","sampleImages","text","modelId","uploadCollectionSlug","editImages","img","serverURL","env","SERVER_URL","NEXT_PUBLIC_SERVER_URL","response","fetch","image","url","headers","Authorization","get","blob","push","size","console","result","assetData","mediaUpload","request","create","file","alt"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/endpoints/index.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport * as process from 'node:process'\n\nimport type { ActionMenuItems, Endpoints, PluginConfig } from '../types.js'\n\nimport { defaultPrompts } from '../ai/prompts.js'\nimport { filterEditorSchemaByNodes } from '../ai/utils/filterEditorSchemaByNodes.js'\nimport {\n PLUGIN_API_ENDPOINT_GENERATE,\n PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_NAME,\n} from '../defaults.js'\nimport { registerEditorHelper } from '../libraries/handlebars/helpers.js'\nimport { handlebarsHelpersMap } from '../libraries/handlebars/helpersMap.js'\nimport { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js'\nimport { extractImageData } from '../utilities/extractImageData.js'\nimport { getGenerationModels } from '../utilities/getGenerationModels.js'\n\nconst requireAuthentication = (req: PayloadRequest) => {\n if (!req.user) {\n throw new Error('Authentication required. Please log in to use AI features.')\n }\n return true\n}\n\nconst checkAccess = async (req: PayloadRequest, pluginConfig: PluginConfig) => {\n requireAuthentication(req)\n \n if (pluginConfig.access?.generate) {\n const hasAccess = await pluginConfig.access.generate({ req })\n if (!hasAccess) {\n throw new Error('Insufficient permissions to use AI generation features.')\n }\n }\n \n return true\n}\n\nconst assignPrompt = async (\n action: ActionMenuItems,\n {\n type,\n actionParams,\n context,\n field,\n layout,\n systemPrompt = '',\n template,\n }: {\n actionParams: Record<any, any>\n context: object\n field: string\n layout: string\n systemPrompt: string\n template: string\n type: string\n },\n) => {\n const prompt = await replacePlaceholders(template, context)\n const toLexicalHTML = type === 'richText' ? handlebarsHelpersMap.toHTML.name : ''\n\n const assignedPrompts = {\n layout: type === 'richText' ? layout : undefined,\n prompt,\n //TODO: Define only once on a collection level\n system: type === 'richText' ? systemPrompt : undefined,\n }\n\n if (action === 'Compose') {\n return assignedPrompts\n }\n\n const { layout: getLayout, system: getSystemPrompt } = defaultPrompts.find(\n (p) => p.name === action,\n )\n\n let updatedLayout = layout\n if (getLayout) {\n updatedLayout = getLayout()\n }\n\n const system = getSystemPrompt({\n ...(actionParams || {}),\n prompt,\n systemPrompt,\n })\n\n return {\n layout: updatedLayout,\n // TODO: revisit this toLexicalHTML\n prompt: await replacePlaceholders(`{{${toLexicalHTML} ${field}}}`, context),\n system,\n }\n}\n\nexport const endpoints: (pluginConfig: PluginConfig) => Endpoints = (pluginConfig) =>\n ({\n textarea: {\n //TODO: This is the main endpoint for generating content - its just needs to be renamed to 'generate' or something.\n handler: async (req: PayloadRequest) => {\n try {\n // Check authentication and authorization first\n await checkAccess(req, pluginConfig)\n\n const data = await req.json?.()\n\n const { allowedEditorNodes = [], locale = 'en', options } = data\n const { action, actionParams, instructionId } = options\n const contextData = data.doc\n\n if (!instructionId) {\n throw new Error(\n `Instruction ID is required for \"${PLUGIN_NAME}\" to work, please check your configuration`,\n )\n }\n\n // Verify user has access to the specific instruction\n const instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n req, // Pass req to ensure access control is applied\n })\n\n const { collections } = req.payload.config\n const collection = collections.find(\n (collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE,\n )\n\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin\n const { schema: editorSchema = {} } = editorConfig\n const { prompt: promptTemplate = '' } = instructions\n\n let allowedEditorSchema = editorSchema\n if (allowedEditorNodes.length) {\n allowedEditorSchema = filterEditorSchemaByNodes(editorSchema, allowedEditorNodes)\n }\n\n const schemaPath = instructions['schema-path'] as string\n const fieldName = schemaPath?.split('.').pop()\n\n registerEditorHelper(req.payload, schemaPath)\n\n const { defaultLocale, locales = [] } = req.payload.config.localization || {}\n const localeData = locales.find((l) => {\n return l.code === locale\n })\n\n const localeInfo = localeData?.label[defaultLocale] || locale\n\n const model = getGenerationModels(pluginConfig).find(\n (model) => model.id === instructions['model-id'],\n )\n\n // @ts-expect-error\n const settingsName = model.settings?.name\n if (!settingsName) {\n req.payload.logger.error('— AI Plugin: Error fetching settings name!')\n }\n\n const modelOptions = instructions[settingsName] || {}\n\n const prompts = await assignPrompt(action, {\n type: instructions['field-type'] as string,\n actionParams,\n context: contextData,\n field: fieldName,\n layout: instructions.layout,\n systemPrompt: instructions.system,\n template: promptTemplate as string,\n })\n\n return model.handler?.(prompts.prompt, {\n ...modelOptions,\n editorSchema: allowedEditorSchema,\n layout: prompts.layout,\n locale: localeInfo,\n system: prompts.system,\n })\n } catch (error) {\n req.payload.logger.error('Error generating content: ', error)\n return new Response(JSON.stringify({ error: error.message }), { \n headers: { 'Content-Type': 'application/json' },\n status: error.message.includes('Authentication required') || error.message.includes('Insufficient permissions') ? 401 : 500\n })\n }\n },\n method: 'post',\n path: PLUGIN_API_ENDPOINT_GENERATE,\n },\n upload: {\n handler: async (req: PayloadRequest) => {\n try {\n // Check authentication and authorization first\n await checkAccess(req, pluginConfig)\n\n const data = await req.json?.()\n\n const { collectionSlug, documentId, options } = data\n const { instructionId } = options\n let docData = {}\n\n if (documentId) {\n try {\n docData = await req.payload.findByID({\n id: documentId,\n collection: collectionSlug,\n draft: true,\n req, // Pass req to ensure access control is applied\n })\n } catch (e) {\n req.payload.logger.error(\n '— AI Plugin: Error fetching document, you should try again after enabling drafts for this collection',\n )\n }\n }\n\n const contextData = {\n ...data.doc,\n ...docData,\n }\n\n let instructions = { images: [], 'model-id': '', prompt: '' }\n\n if (instructionId) {\n // Verify user has access to the specific instruction\n // @ts-expect-error\n instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n req, // Pass req to ensure access control is applied\n })\n }\n\n const { images: sampleImages = [], prompt: promptTemplate = '' } = instructions\n const schemaPath = instructions['schema-path']\n\n registerEditorHelper(req.payload, schemaPath)\n\n const text = await replacePlaceholders(promptTemplate, contextData)\n const modelId = instructions['model-id']\n const uploadCollectionSlug = instructions['relation-to']\n\n const images = [...extractImageData(text), ...sampleImages]\n\n const editImages = []\n for (const img of images) {\n try {\n const serverURL =\n req.payload.config?.serverURL ||\n process.env.SERVER_URL ||\n process.env.NEXT_PUBLIC_SERVER_URL\n\n const response = await fetch(`${serverURL}${img.image.url}`, {\n headers: {\n //TODO: Further testing needed or so find a proper way.\n Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`,\n },\n method: 'GET',\n })\n\n const blob = await response.blob()\n editImages.push({\n name: img.image.name,\n type: img.image.type,\n data: blob,\n size: blob.size,\n url: `${serverURL}${img.image.url}`,\n })\n } catch (e) {\n req.payload.logger.error('Error fetching reference images!')\n console.error(e)\n throw Error(\n \"We couldn't fetch the images. Please ensure the images are accessible and hosted publicly.\",\n )\n }\n }\n\n const model = getGenerationModels(pluginConfig).find((model) => model.id === modelId)\n\n // @ts-expect-error\n const settingsName = model.settings?.name\n if (!settingsName) {\n req.payload.logger.error('— AI Plugin: Error fetching settings name!')\n }\n\n let modelOptions = instructions[settingsName] || {}\n modelOptions = {\n ...modelOptions,\n images: editImages,\n }\n\n const result = await model.handler?.(text, modelOptions)\n let assetData: { alt?: string; id: number | string }\n\n if (typeof pluginConfig.mediaUpload === 'function') {\n assetData = await pluginConfig.mediaUpload(result, {\n collection: uploadCollectionSlug,\n request: req,\n })\n } else {\n assetData = await req.payload.create({\n collection: uploadCollectionSlug,\n data: result.data,\n file: result.file,\n req, // Pass req to ensure access control is applied\n })\n }\n\n if (!assetData.id) {\n req.payload.logger.error(\n 'Error uploading generated media, is your media upload function correct?',\n )\n throw new Error('Error uploading generated media!')\n }\n\n return new Response(\n JSON.stringify({\n result: {\n id: assetData.id,\n alt: assetData.alt,\n },\n }),\n )\n } catch (error) {\n req.payload.logger.error('Error generating upload: ', error)\n return new Response(JSON.stringify({ error: error.message }), { \n headers: { 'Content-Type': 'application/json' },\n status: error.message.includes('Authentication required') || error.message.includes('Insufficient permissions') ? 401 : 500\n })\n }\n },\n method: 'post',\n path: PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n },\n }) satisfies Endpoints\n "],"names":["process","defaultPrompts","filterEditorSchemaByNodes","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","registerEditorHelper","handlebarsHelpersMap","replacePlaceholders","extractImageData","getGenerationModels","requireAuthentication","req","user","Error","checkAccess","pluginConfig","access","generate","hasAccess","assignPrompt","action","type","actionParams","context","field","layout","systemPrompt","template","prompt","toLexicalHTML","toHTML","name","assignedPrompts","undefined","system","getLayout","getSystemPrompt","find","p","updatedLayout","endpoints","textarea","handler","data","json","allowedEditorNodes","locale","options","instructionId","contextData","doc","instructions","payload","findByID","id","collection","collections","config","slug","custom","editorConfig","admin","schema","editorSchema","promptTemplate","allowedEditorSchema","length","schemaPath","fieldName","split","pop","defaultLocale","locales","localization","localeData","l","code","localeInfo","label","model","settingsName","settings","logger","error","modelOptions","prompts","Response","JSON","stringify","message","headers","status","includes","method","path","upload","collectionSlug","documentId","docData","draft","e","images","sampleImages","text","modelId","uploadCollectionSlug","editImages","img","serverURL","env","SERVER_URL","NEXT_PUBLIC_SERVER_URL","response","fetch","image","url","Authorization","get","blob","push","size","console","result","assetData","mediaUpload","request","create","file","alt"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAIrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAyC9C,QAAA,MAAM,eAAe,GAClB,cAAc,YAAY,MAC1B,gBAAgB,MAAM,KAAG,MAoGzB,CAAA;AAEH,OAAO,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,MAAM,EAAgB,MAAM,SAAS,CAAA;AAIrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AA4D9C,QAAA,MAAM,eAAe,GAClB,cAAc,YAAY,MACxB,gBAAgB,MAAM,KAAG,MA6HzB,CAAA;AAEL,OAAO,EAAE,eAAe,EAAE,CAAA"}
package/dist/plugin.js CHANGED
@@ -11,6 +11,10 @@ import { getGenerationModels } from './utilities/getGenerationModels.js';
11
11
  import { isPluginActivated } from './utilities/isPluginActivated.js';
12
12
  import { updateFieldsConfig } from './utilities/updateFieldsConfig.js';
13
13
  const defaultPluginConfig = {
14
+ access: {
15
+ generate: ({ req })=>!!req.user,
16
+ settings: ({ req })=>!!req.user
17
+ },
14
18
  collections: {},
15
19
  disableSponsorMessage: false,
16
20
  generatePromptOnInit: true,
@@ -35,10 +39,28 @@ const sponsorMessage = `
35
39
  ║ Thank you again, and happy building! ║
36
40
  ╚═══════════════════════════════════════════════════════════════╝
37
41
  `;
42
+ const securityMessage = `
43
+ ╔═══════════════════════════════════════════════════════════════╗
44
+ ║ SECURITY NOTICE ║
45
+ ║ ║
46
+ ║ The AI Plugin now requires authentication by default. ║
47
+ ║ All AI features are restricted to authenticated users. ║
48
+ ║ ║
49
+ ║ To customize access control, configure the 'access' option ║
50
+ ║ in your plugin settings. See documentation for details. ║
51
+ ║ ║
52
+ ║ If you need different access patterns, please configure ║
53
+ ║ them explicitly in your plugin configuration. ║
54
+ ╚═══════════════════════════════════════════════════════════════╝
55
+ `;
38
56
  const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
39
57
  pluginConfig = {
40
58
  ...defaultPluginConfig,
41
- ...pluginConfig
59
+ ...pluginConfig,
60
+ access: {
61
+ ...defaultPluginConfig.access,
62
+ ...pluginConfig.access
63
+ }
42
64
  };
43
65
  pluginConfig.generationModels = getGenerationModels(pluginConfig);
44
66
  const isActivated = isPluginActivated(pluginConfig);
@@ -66,7 +88,10 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
66
88
  ...incomingConfig.collections ?? [],
67
89
  Instructions
68
90
  ];
69
- const { collections: collectionSlugs = [] } = pluginConfig;
91
+ const globals = [
92
+ ...incomingConfig.globals ?? []
93
+ ];
94
+ const { collections: collectionSlugs = [], globals: globalsSlugs = [] } = pluginConfig;
70
95
  const { components: { providers = [] } = {} } = incomingConfig.admin || {};
71
96
  const updatedProviders = [
72
97
  ...providers ?? [],
@@ -101,6 +126,17 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
101
126
  pluginEndpoints.upload,
102
127
  fetchFields(pluginConfig.access)
103
128
  ],
129
+ globals: globals.map((global)=>{
130
+ if (globalsSlugs[global.slug]) {
131
+ const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(global);
132
+ collectionsFieldPathMap = {
133
+ ...collectionsFieldPathMap,
134
+ ...schemaPathMap
135
+ };
136
+ return updatedCollectionConfig;
137
+ }
138
+ return global;
139
+ }),
104
140
  i18n: {
105
141
  ...incomingConfig.i18n || {},
106
142
  translations: {
@@ -119,6 +155,9 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
119
155
  console.error(error);
120
156
  payload.logger.error(`— AI Plugin: Initialization Error: ${error}`);
121
157
  }).finally(()=>{
158
+ setTimeout(()=>{
159
+ payload.logger.info(securityMessage);
160
+ }, 1000);
122
161
  if (!pluginConfig.disableSponsorMessage) {
123
162
  setTimeout(()=>{
124
163
  payload.logger.info(sponsorMessage);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport { deepMerge } from 'payload/shared'\n\nimport type { PluginConfig } from './types.js'\n\nimport { defaultGenerationModels } from './ai/models/index.js'\nimport { lexicalJsonSchema } from './ai/schemas/lexicalJsonSchema.js'\nimport { instructionsCollection } from './collections/Instructions.js'\nimport { PLUGIN_NAME } from './defaults.js'\nimport { fetchFields } from './endpoints/fetchFields.js'\nimport { endpoints } from './endpoints/index.js'\nimport { init } from './init.js'\nimport { translations } from './translations/index.js'\nimport { getGenerationModels } from './utilities/getGenerationModels.js'\nimport { isPluginActivated } from './utilities/isPluginActivated.js'\nimport { updateFieldsConfig } from './utilities/updateFieldsConfig.js'\n\nconst defaultPluginConfig: PluginConfig = {\n collections: {},\n disableSponsorMessage: false,\n generatePromptOnInit: true,\n generationModels: defaultGenerationModels,\n}\n\nconst sponsorMessage = `\n╔═══════════════════════════════════════════════════════════════╗\n║ THANK YOU FOR USING THE PAYLOAD AI PLUGIN! ║\n║ ║\n║ If this plugin makes your life easier, please ║\n║ consider supporting its development and maintenance: ║\n║ ║\n║ • Buy me a coffee: https://buymeacoffee.com/ashbuilds ║\n║ • Sponsor on GitHub: https://github.com/sponsors/ashbuilds ║\n║ ║\n║ Your support fuels continued improvements, ║\n║ new features, and more caffeinated coding sessions! ☕ ║\n║ ║\n║ Got feedback or need help? Submit an issue here: ║\n║ • https://github.com/ashbuilds/payload-ai/issues/new ║\n║ ║\n║ Thank you again, and happy building! ║\n╚═══════════════════════════════════════════════════════════════╝\n`\n\nconst payloadAiPlugin =\n (pluginConfig: PluginConfig) =>\n (incomingConfig: Config): Config => {\n\n pluginConfig = { ...defaultPluginConfig, ...pluginConfig }\n pluginConfig.generationModels = getGenerationModels(pluginConfig)\n\n const isActivated = isPluginActivated(pluginConfig)\n let updatedConfig: Config = { ...incomingConfig }\n let collectionsFieldPathMap = {}\n\n if (isActivated) {\n const Instructions = instructionsCollection(pluginConfig)\n // Inject editor schema to config, so that it can be accessed when /textarea endpoint will hit\n const lexicalSchema = lexicalJsonSchema(pluginConfig.editorConfig?.nodes)\n\n if (pluginConfig.debugging) {\n Instructions.admin.hidden = false\n }\n\n Instructions.admin.custom = {\n ...(Instructions.admin.custom || {}),\n [PLUGIN_NAME]: {\n editorConfig: {\n // Used in admin client for useObject hook\n schema: lexicalSchema,\n },\n },\n }\n\n const collections = [...(incomingConfig.collections ?? []), Instructions]\n const { collections: collectionSlugs = [] } = pluginConfig\n\n const { components: { providers = [] } = {} } = incomingConfig.admin || {}\n const updatedProviders = [\n ...(providers ?? []),\n {\n path: '@ai-stack/payloadcms/client#InstructionsProvider',\n },\n ]\n\n incomingConfig.admin = {\n ...(incomingConfig.admin || {}),\n components: {\n ...(incomingConfig.admin?.components ?? {}),\n providers: updatedProviders,\n },\n }\n\n const pluginEndpoints = endpoints(pluginConfig)\n updatedConfig = {\n ...incomingConfig,\n collections: collections.map((collection) => {\n if (collectionSlugs[collection.slug]) {\n const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(collection)\n collectionsFieldPathMap = {\n ...collectionsFieldPathMap,\n ...schemaPathMap,\n }\n return updatedCollectionConfig\n }\n\n return collection\n }),\n endpoints: [\n ...(incomingConfig.endpoints ?? []),\n pluginEndpoints.textarea,\n pluginEndpoints.upload,\n fetchFields(pluginConfig.access),\n ],\n i18n: {\n ...(incomingConfig.i18n || {}),\n translations: {\n ...deepMerge(translations, incomingConfig.i18n?.translations ?? {}),\n },\n },\n }\n }\n\n updatedConfig.onInit = async (payload) => {\n if (incomingConfig.onInit) await incomingConfig.onInit(payload)\n\n if (!isActivated) {\n payload.logger.warn(`— AI Plugin: Not activated. Please verify your environment keys.`)\n return\n }\n\n await init(payload, collectionsFieldPathMap, pluginConfig)\n .catch((error) => {\n console.error(error)\n payload.logger.error(`— AI Plugin: Initialization Error: ${error}`)\n })\n .finally(() => {\n if (!pluginConfig.disableSponsorMessage) {\n setTimeout(() => {\n payload.logger.info(sponsorMessage)\n }, 3000)\n }\n })\n }\n\n return updatedConfig\n }\n\nexport { payloadAiPlugin }\n"],"names":["deepMerge","defaultGenerationModels","lexicalJsonSchema","instructionsCollection","PLUGIN_NAME","fetchFields","endpoints","init","translations","getGenerationModels","isPluginActivated","updateFieldsConfig","defaultPluginConfig","collections","disableSponsorMessage","generatePromptOnInit","generationModels","sponsorMessage","payloadAiPlugin","pluginConfig","incomingConfig","isActivated","updatedConfig","collectionsFieldPathMap","Instructions","lexicalSchema","editorConfig","nodes","debugging","admin","hidden","custom","schema","collectionSlugs","components","providers","updatedProviders","path","pluginEndpoints","map","collection","slug","schemaPathMap","updatedCollectionConfig","textarea","upload","access","i18n","onInit","payload","logger","warn","catch","error","console","finally","setTimeout","info"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { CollectionConfig, Config, GlobalConfig } from 'payload'\n\nimport { deepMerge } from 'payload/shared'\n\nimport type { PluginConfig } from './types.js'\n\nimport { defaultGenerationModels } from './ai/models/index.js'\nimport { lexicalJsonSchema } from './ai/schemas/lexicalJsonSchema.js'\nimport { instructionsCollection } from './collections/Instructions.js'\nimport { PLUGIN_NAME } from './defaults.js'\nimport { fetchFields } from './endpoints/fetchFields.js'\nimport { endpoints } from './endpoints/index.js'\nimport { init } from './init.js'\nimport { translations } from './translations/index.js'\nimport { getGenerationModels } from './utilities/getGenerationModels.js'\nimport { isPluginActivated } from './utilities/isPluginActivated.js'\nimport { updateFieldsConfig } from './utilities/updateFieldsConfig.js'\n\nconst defaultPluginConfig: PluginConfig = {\n access: {\n generate: ({ req }) => !!req.user,\n settings: ({ req }) => !!req.user,\n },\n collections: {},\n disableSponsorMessage: false,\n generatePromptOnInit: true,\n generationModels: defaultGenerationModels,\n}\n\nconst sponsorMessage = `\n╔═══════════════════════════════════════════════════════════════╗\n║ THANK YOU FOR USING THE PAYLOAD AI PLUGIN! ║\n║ ║\n║ If this plugin makes your life easier, please ║\n║ consider supporting its development and maintenance: ║\n║ ║\n║ • Buy me a coffee: https://buymeacoffee.com/ashbuilds ║\n║ • Sponsor on GitHub: https://github.com/sponsors/ashbuilds ║\n║ ║\n║ Your support fuels continued improvements, ║\n║ new features, and more caffeinated coding sessions! ☕ ║\n║ ║\n║ Got feedback or need help? Submit an issue here: ║\n║ • https://github.com/ashbuilds/payload-ai/issues/new ║\n║ ║\n║ Thank you again, and happy building! ║\n╚═══════════════════════════════════════════════════════════════╝\n`\n\nconst securityMessage = `\n╔═══════════════════════════════════════════════════════════════╗\n║ SECURITY NOTICE ║\n║ ║\n║ The AI Plugin now requires authentication by default. ║\n║ All AI features are restricted to authenticated users. ║\n║ ║\n║ To customize access control, configure the 'access' option ║\n║ in your plugin settings. See documentation for details. ║\n║ ║\n║ If you need different access patterns, please configure ║\n║ them explicitly in your plugin configuration. ║\n╚═══════════════════════════════════════════════════════════════╝\n`\n\nconst payloadAiPlugin =\n (pluginConfig: PluginConfig) =>\n (incomingConfig: Config): Config => {\n\n pluginConfig = { \n ...defaultPluginConfig, \n ...pluginConfig,\n access: {\n ...defaultPluginConfig.access,\n ...pluginConfig.access,\n }\n }\n \n pluginConfig.generationModels = getGenerationModels(pluginConfig)\n\n const isActivated = isPluginActivated(pluginConfig)\n let updatedConfig: Config = { ...incomingConfig }\n let collectionsFieldPathMap = {}\n\n if (isActivated) {\n const Instructions = instructionsCollection(pluginConfig)\n // Inject editor schema to config, so that it can be accessed when /textarea endpoint will hit\n const lexicalSchema = lexicalJsonSchema(pluginConfig.editorConfig?.nodes)\n\n if (pluginConfig.debugging) {\n Instructions.admin.hidden = false\n }\n\n Instructions.admin.custom = {\n ...(Instructions.admin.custom || {}),\n [PLUGIN_NAME]: {\n editorConfig: {\n // Used in admin client for useObject hook\n schema: lexicalSchema,\n },\n },\n }\n\n const collections = [...(incomingConfig.collections ?? []), Instructions]\n const globals = [...(incomingConfig.globals ?? [])]\n const { collections: collectionSlugs = [], globals: globalsSlugs = [] } = pluginConfig\n\n const { components: { providers = [] } = {} } = incomingConfig.admin || {}\n const updatedProviders = [\n ...(providers ?? []),\n {\n path: '@ai-stack/payloadcms/client#InstructionsProvider',\n },\n ]\n\n incomingConfig.admin = {\n ...(incomingConfig.admin || {}),\n components: {\n ...(incomingConfig.admin?.components ?? {}),\n providers: updatedProviders,\n },\n }\n\n const pluginEndpoints = endpoints(pluginConfig)\n updatedConfig = {\n ...incomingConfig,\n collections: collections.map((collection) => {\n if (collectionSlugs[collection.slug]) {\n const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(collection)\n collectionsFieldPathMap = {\n ...collectionsFieldPathMap,\n ...schemaPathMap,\n }\n return updatedCollectionConfig as CollectionConfig\n }\n\n return collection\n }),\n endpoints: [\n ...(incomingConfig.endpoints ?? []),\n pluginEndpoints.textarea,\n pluginEndpoints.upload,\n fetchFields(pluginConfig.access),\n ],\n globals: globals.map((global) => {\n if (globalsSlugs[global.slug]) {\n const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(global)\n collectionsFieldPathMap = {\n ...collectionsFieldPathMap,\n ...schemaPathMap,\n }\n return updatedCollectionConfig as GlobalConfig;\n }\n\n return global\n }),\n i18n: {\n ...(incomingConfig.i18n || {}),\n translations: {\n ...deepMerge(translations, incomingConfig.i18n?.translations ?? {}),\n },\n },\n }\n }\n\n updatedConfig.onInit = async (payload) => {\n if (incomingConfig.onInit) await incomingConfig.onInit(payload)\n\n if (!isActivated) {\n payload.logger.warn(`— AI Plugin: Not activated. Please verify your environment keys.`)\n return\n }\n\n await init(payload, collectionsFieldPathMap, pluginConfig)\n .catch((error) => {\n console.error(error)\n payload.logger.error(`— AI Plugin: Initialization Error: ${error}`)\n })\n .finally(() => {\n setTimeout(() => {\n payload.logger.info(securityMessage)\n }, 1000)\n \n if (!pluginConfig.disableSponsorMessage) {\n setTimeout(() => {\n payload.logger.info(sponsorMessage)\n }, 3000)\n }\n })\n }\n\n return updatedConfig\n }\n\nexport { payloadAiPlugin }"],"names":["deepMerge","defaultGenerationModels","lexicalJsonSchema","instructionsCollection","PLUGIN_NAME","fetchFields","endpoints","init","translations","getGenerationModels","isPluginActivated","updateFieldsConfig","defaultPluginConfig","access","generate","req","user","settings","collections","disableSponsorMessage","generatePromptOnInit","generationModels","sponsorMessage","securityMessage","payloadAiPlugin","pluginConfig","incomingConfig","isActivated","updatedConfig","collectionsFieldPathMap","Instructions","lexicalSchema","editorConfig","nodes","debugging","admin","hidden","custom","schema","globals","collectionSlugs","globalsSlugs","components","providers","updatedProviders","path","pluginEndpoints","map","collection","slug","schemaPathMap","updatedCollectionConfig","textarea","upload","global","i18n","onInit","payload","logger","warn","catch","error","console","finally","setTimeout","info"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,8 +1,19 @@
1
1
  import type { JSONSchema } from 'openai/lib/jsonschema';
2
2
  import type { ImageGenerateParams } from 'openai/resources/images';
3
- import type { CollectionSlug, DataFromCollectionSlug, Endpoint, Field, File, GroupField, PayloadRequest } from 'payload';
3
+ import type { CollectionSlug, DataFromCollectionSlug, Endpoint, Field, File, GlobalConfig, GroupField, PayloadRequest } from 'payload';
4
4
  import type { CSSProperties, MouseEventHandler } from 'react';
5
5
  export interface PluginConfigAccess {
6
+ /**
7
+ * Control access to AI generation features (generate text, images, audio)
8
+ * @default () => !!req.user (requires authentication)
9
+ */
10
+ generate?: ({ req }: {
11
+ req: PayloadRequest;
12
+ }) => Promise<boolean> | boolean;
13
+ /**
14
+ * Control access to AI settings/configuration
15
+ * @default () => !!req.user (requires authentication)
16
+ */
6
17
  settings?: ({ req }: {
7
18
  req: PayloadRequest;
8
19
  }) => Promise<boolean> | boolean;
@@ -15,6 +26,10 @@ export type PluginConfigMediaUploadFunction = (result: {
15
26
  request: PayloadRequest;
16
27
  }) => Promise<DataFromCollectionSlug<CollectionSlug>>;
17
28
  export interface PluginConfig {
29
+ /**
30
+ * Access control configuration for AI features
31
+ * By default, all AI features require authentication
32
+ */
18
33
  access?: PluginConfigAccess;
19
34
  collections: {
20
35
  [key: CollectionSlug]: boolean;
@@ -27,7 +42,9 @@ export interface PluginConfig {
27
42
  fields?: Field[];
28
43
  generatePromptOnInit?: boolean;
29
44
  generationModels?: ((defaultModels: GenerationModel[]) => GenerationModel[]) | GenerationModel[];
30
- globals?: string[];
45
+ globals?: {
46
+ [key: GlobalConfig['slug']]: boolean;
47
+ };
31
48
  interfaceName?: string;
32
49
  mediaUpload?: PluginConfigMediaUploadFunction;
33
50
  uploadCollectionSlug?: CollectionSlug;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { JSONSchema } from 'openai/lib/jsonschema'\nimport type { ImageGenerateParams } from 'openai/resources/images'\nimport type { CollectionSlug, DataFromCollectionSlug, Endpoint, Field, File, GroupField, PayloadRequest } from 'payload'\nimport type { CSSProperties, MouseEventHandler } from 'react'\n\nexport interface PluginConfigAccess {\n settings?: ({ req }: { req: PayloadRequest }) => Promise<boolean> | boolean\n}\n\nexport type PluginConfigMediaUploadFunction = (\n result: { data: Record<any, any>; file: File },\n {\n collection,\n request,\n }: {\n collection: CollectionSlug\n request: PayloadRequest\n },\n) => Promise<DataFromCollectionSlug<CollectionSlug>>\n\nexport interface PluginConfig {\n access?: PluginConfigAccess\n collections: {\n [key: CollectionSlug]: boolean\n }\n debugging?: boolean\n disableSponsorMessage?: boolean\n editorConfig?: { nodes: JSONSchema[] }\n fields?: Field[]\n generatePromptOnInit?: boolean\n generationModels?: ((defaultModels: GenerationModel[]) => GenerationModel[]) | GenerationModel[]\n globals?: string[]\n interfaceName?: string\n mediaUpload?: PluginConfigMediaUploadFunction\n uploadCollectionSlug?: CollectionSlug\n}\n\nexport interface GenerationModel {\n fields: string[]\n generateText?: (prompt: string, system: string) => Promise<string>\n handler?: (prompt: string, options: any) => Promise<any> | Response\n id: string\n name: string\n output: 'audio' | 'file' | 'image' | 'json' | 'text' | 'video'\n settings?: GroupField\n supportsPromptOptimization?: boolean\n}\n\nexport interface GenerationConfig {\n models: GenerationModel[]\n provider: string\n}\n\nexport type GenerateTextarea<T = any> = (args: {\n collectionSlug: CollectionSlug\n doc: T\n documentId?: number | string\n locale?: string\n options?: any\n}) => Promise<string> | string\n\nexport interface Endpoints {\n textarea: Omit<Endpoint, 'root'>\n upload: Omit<Endpoint, 'root'>\n}\n\nexport type ActionMenuItems =\n | 'Compose'\n | 'Expand'\n | 'Proofread'\n | 'Rephrase'\n | 'Settings'\n | 'Simplify'\n | 'Summarize'\n | 'Tone'\n | 'Translate'\n\nexport type ActionMenuEvents =\n | 'onCompose'\n | 'onExpand'\n | 'onProofread'\n | 'onRephrase'\n | 'onSettings'\n | 'onSimplify'\n | 'onSummarize'\n | 'onTone'\n | 'onTranslate'\n\nexport type UseMenuEvents = {\n [key in ActionMenuEvents]?: (data?: unknown) => void\n}\n\nexport type UseMenuOptions = {\n isConfigAllowed: boolean\n}\n\nexport type BaseItemProps<T = any> = {\n children?: React.ReactNode\n disabled?: boolean\n hideIcon?: boolean\n isActive?: boolean\n isMenu?: boolean\n onClick: (data?: unknown) => void\n onMouseEnter?: MouseEventHandler<T> | undefined\n onMouseLeave?: MouseEventHandler<T> | undefined\n style?: CSSProperties | undefined\n title?: string\n}\n\nexport type ImageReference = {\n data: Blob\n name: string\n size: number\n type: string\n url: string\n}\n\nexport type GenerateImageParams = {\n images?: ImageReference[]\n size?: ImageGenerateParams['size']\n style?: ImageGenerateParams['style']\n version?: ImageGenerateParams['model']\n}\n"],"names":[],"mappings":"AAqHA,WAKC"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { JSONSchema } from 'openai/lib/jsonschema'\nimport type { ImageGenerateParams } from 'openai/resources/images'\nimport type {\n CollectionSlug,\n DataFromCollectionSlug,\n Endpoint,\n Field,\n File,\n GlobalConfig,\n GroupField,\n PayloadRequest,\n} from 'payload'\nimport type { CSSProperties, MouseEventHandler } from 'react'\n\nexport interface PluginConfigAccess {\n /**\n * Control access to AI generation features (generate text, images, audio)\n * @default () => !!req.user (requires authentication)\n */\n generate?: ({ req }: { req: PayloadRequest }) => Promise<boolean> | boolean\n /**\n * Control access to AI settings/configuration\n * @default () => !!req.user (requires authentication)\n */\n settings?: ({ req }: { req: PayloadRequest }) => Promise<boolean> | boolean\n}\n\nexport type PluginConfigMediaUploadFunction = (\n result: { data: Record<any, any>; file: File },\n {\n collection,\n request,\n }: {\n collection: CollectionSlug\n request: PayloadRequest\n },\n) => Promise<DataFromCollectionSlug<CollectionSlug>>\n\nexport interface PluginConfig {\n /**\n * Access control configuration for AI features\n * By default, all AI features require authentication\n */\n access?: PluginConfigAccess\n collections: {\n [key: CollectionSlug]: boolean\n }\n debugging?: boolean\n disableSponsorMessage?: boolean\n editorConfig?: { nodes: JSONSchema[] }\n fields?: Field[]\n generatePromptOnInit?: boolean\n generationModels?: ((defaultModels: GenerationModel[]) => GenerationModel[]) | GenerationModel[]\n globals?: {\n [key: GlobalConfig['slug']]: boolean\n }\n interfaceName?: string\n mediaUpload?: PluginConfigMediaUploadFunction\n uploadCollectionSlug?: CollectionSlug\n}\n\nexport interface GenerationModel {\n fields: string[]\n generateText?: (prompt: string, system: string) => Promise<string>\n handler?: (prompt: string, options: any) => Promise<any> | Response\n id: string\n name: string\n output: 'audio' | 'file' | 'image' | 'json' | 'text' | 'video'\n settings?: GroupField\n supportsPromptOptimization?: boolean\n}\n\nexport interface GenerationConfig {\n models: GenerationModel[]\n provider: string\n}\n\nexport type GenerateTextarea<T = any> = (args: {\n collectionSlug: CollectionSlug\n doc: T\n documentId?: number | string\n locale?: string\n options?: any\n}) => Promise<string> | string\n\nexport interface Endpoints {\n textarea: Omit<Endpoint, 'root'>\n upload: Omit<Endpoint, 'root'>\n}\n\nexport type ActionMenuItems =\n | 'Compose'\n | 'Expand'\n | 'Proofread'\n | 'Rephrase'\n | 'Settings'\n | 'Simplify'\n | 'Summarize'\n | 'Tone'\n | 'Translate'\n\nexport type ActionMenuEvents =\n | 'onCompose'\n | 'onExpand'\n | 'onProofread'\n | 'onRephrase'\n | 'onSettings'\n | 'onSimplify'\n | 'onSummarize'\n | 'onTone'\n | 'onTranslate'\n\nexport type UseMenuEvents = {\n [key in ActionMenuEvents]?: (data?: unknown) => void\n}\n\nexport type UseMenuOptions = {\n isConfigAllowed: boolean\n}\n\nexport type BaseItemProps<T = any> = {\n children?: React.ReactNode\n disabled?: boolean\n hideIcon?: boolean\n isActive?: boolean\n isMenu?: boolean\n onClick: (data?: unknown) => void\n onMouseEnter?: MouseEventHandler<T> | undefined\n onMouseLeave?: MouseEventHandler<T> | undefined\n style?: CSSProperties | undefined\n title?: string\n}\n\nexport type ImageReference = {\n data: Blob\n name: string\n size: number\n type: string\n url: string\n}\n\nexport type GenerateImageParams = {\n images?: ImageReference[]\n size?: ImageGenerateParams['size']\n style?: ImageGenerateParams['style']\n version?: ImageGenerateParams['model']\n}\n"],"names":[],"mappings":"AA6IA,WAKC"}
@@ -1,8 +1,8 @@
1
- import type { CollectionConfig } from 'payload';
1
+ import type { CollectionConfig, GlobalConfig } from 'payload';
2
2
  interface UpdateFieldsConfig {
3
3
  schemaPathMap: Record<string, string>;
4
- updatedCollectionConfig: CollectionConfig;
4
+ updatedCollectionConfig: CollectionConfig | GlobalConfig;
5
5
  }
6
- export declare const updateFieldsConfig: (collectionConfig: CollectionConfig) => UpdateFieldsConfig;
6
+ export declare const updateFieldsConfig: (collectionConfig: CollectionConfig | GlobalConfig) => UpdateFieldsConfig;
7
7
  export {};
8
8
  //# sourceMappingURL=updateFieldsConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"updateFieldsConfig.d.ts","sourceRoot":"","sources":["../../src/utilities/updateFieldsConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE/C,UAAU,kBAAkB;IAC1B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,uBAAuB,EAAE,gBAAgB,CAAA;CAC1C;AAED,eAAO,MAAM,kBAAkB,GAAI,kBAAkB,gBAAgB,KAAG,kBAkGvE,CAAA"}
1
+ {"version":3,"file":"updateFieldsConfig.d.ts","sourceRoot":"","sources":["../../src/utilities/updateFieldsConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE7D,UAAU,kBAAkB;IAC1B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,uBAAuB,EAAE,gBAAgB,GAAG,YAAY,CAAA;CACzD;AAED,eAAO,MAAM,kBAAkB,GAAI,kBAAkB,gBAAgB,GAAG,YAAY,KAAG,kBAkGtF,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, string>\n updatedCollectionConfig: CollectionConfig\n}\n\nexport const updateFieldsConfig = (collectionConfig: CollectionConfig): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n function updateField(field: any, parentPath = ''): any {\n const currentPath = parentPath ? `${parentPath}.${field.name}` : field.name\n const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`\n\n // Disabled fields/ field types\n if (\n field.admin?.disabled ||\n field.admin?.readOnly ||\n field.admin?.hidden ||\n field.type === 'row'\n ) {\n return field\n }\n\n // Map field path for global fieldInstructionsMap to load related instructions\n // This is done due to save extra API call to get instructions when Field components are loaded in admin\n // Doing is will only call instructions data when user clicks on settings\n if (['richText', 'text', 'textarea', 'upload'].includes(field.type)) {\n schemaPathMap = {\n ...schemaPathMap,\n [currentSchemaPath]: {\n type: field.type,\n label: field.label || field.name,\n relationTo: field.relationTo,\n },\n }\n }\n\n // Inject AI actions, richText is not included here as it has to be explicitly defined by user\n if (['text', 'textarea', 'upload'].includes(field.type)) {\n let customField = {}\n\n // Custom fields don't fully adhere to the Payload schema, making it difficult to\n // determine which components support injecting ComposeField as a Description.\n if (field.admin?.components?.Field || field.admin?.components?.Description) {\n // TODO: Do something?\n customField = {}\n }\n\n return {\n ...field,\n admin: {\n ...field.admin,\n components: {\n ...(field.admin?.components || {}),\n Description: '@ai-stack/payloadcms/fields#ComposeField',\n ...customField,\n },\n },\n }\n }\n\n if (field.fields) {\n return {\n ...field,\n fields: field.fields.map((subField: any) => updateField(subField, currentPath)),\n }\n }\n\n if (field.tabs) {\n return {\n ...field,\n tabs: field.tabs.map((tab: any) => {\n return {\n ...tab,\n fields: tab.fields.map((subField: any) => updateField(subField, tab.name)),\n }\n }),\n }\n }\n\n if (field.blocks) {\n return {\n ...field,\n blocks: field.blocks.map((block: any) => ({\n ...block,\n fields: block.fields.map((subField: any) =>\n updateField(subField, `${currentPath}.${block.slug}`),\n ),\n })),\n }\n }\n\n return field\n }\n\n const updatedCollectionConfig = {\n ...collectionConfig,\n fields: collectionConfig.fields.map((field) => updateField(field)),\n }\n\n return {\n schemaPathMap,\n updatedCollectionConfig,\n }\n}\n"],"names":["updateFieldsConfig","collectionConfig","schemaPathMap","updateField","field","parentPath","currentPath","name","currentSchemaPath","slug","admin","disabled","readOnly","hidden","type","includes","label","relationTo","customField","components","Field","Description","fields","map","subField","tabs","tab","blocks","block","updatedCollectionConfig"],"mappings":"AAOA,OAAO,MAAMA,qBAAqB,CAACC;IACjC,IAAIC,gBAAgB,CAAC;IAErB,SAASC,YAAYC,KAAU,EAAEC,aAAa,EAAE;QAC9C,MAAMC,cAAcD,aAAa,GAAGA,WAAW,CAAC,EAAED,MAAMG,IAAI,EAAE,GAAGH,MAAMG,IAAI;QAC3E,MAAMC,oBAAoB,GAAGP,iBAAiBQ,IAAI,CAAC,CAAC,EAAEH,aAAa;QAEnE,+BAA+B;QAC/B,IACEF,MAAMM,KAAK,EAAEC,YACbP,MAAMM,KAAK,EAAEE,YACbR,MAAMM,KAAK,EAAEG,UACbT,MAAMU,IAAI,KAAK,OACf;YACA,OAAOV;QACT;QAEA,8EAA8E;QAC9E,wGAAwG;QACxG,yEAAyE;QACzE,IAAI;YAAC;YAAY;YAAQ;YAAY;SAAS,CAACW,QAAQ,CAACX,MAAMU,IAAI,GAAG;YACnEZ,gBAAgB;gBACd,GAAGA,aAAa;gBAChB,CAACM,kBAAkB,EAAE;oBACnBM,MAAMV,MAAMU,IAAI;oBAChBE,OAAOZ,MAAMY,KAAK,IAAIZ,MAAMG,IAAI;oBAChCU,YAAYb,MAAMa,UAAU;gBAC9B;YACF;QACF;QAEA,8FAA8F;QAC9F,IAAI;YAAC;YAAQ;YAAY;SAAS,CAACF,QAAQ,CAACX,MAAMU,IAAI,GAAG;YACvD,IAAII,cAAc,CAAC;YAEnB,iFAAiF;YACjF,8EAA8E;YAC9E,IAAId,MAAMM,KAAK,EAAES,YAAYC,SAAShB,MAAMM,KAAK,EAAES,YAAYE,aAAa;gBAC1E,sBAAsB;gBACtBH,cAAc,CAAC;YACjB;YAEA,OAAO;gBACL,GAAGd,KAAK;gBACRM,OAAO;oBACL,GAAGN,MAAMM,KAAK;oBACdS,YAAY;wBACV,GAAIf,MAAMM,KAAK,EAAES,cAAc,CAAC,CAAC;wBACjCE,aAAa;wBACb,GAAGH,WAAW;oBAChB;gBACF;YACF;QACF;QAEA,IAAId,MAAMkB,MAAM,EAAE;YAChB,OAAO;gBACL,GAAGlB,KAAK;gBACRkB,QAAQlB,MAAMkB,MAAM,CAACC,GAAG,CAAC,CAACC,WAAkBrB,YAAYqB,UAAUlB;YACpE;QACF;QAEA,IAAIF,MAAMqB,IAAI,EAAE;YACd,OAAO;gBACL,GAAGrB,KAAK;gBACRqB,MAAMrB,MAAMqB,IAAI,CAACF,GAAG,CAAC,CAACG;oBACpB,OAAO;wBACL,GAAGA,GAAG;wBACNJ,QAAQI,IAAIJ,MAAM,CAACC,GAAG,CAAC,CAACC,WAAkBrB,YAAYqB,UAAUE,IAAInB,IAAI;oBAC1E;gBACF;YACF;QACF;QAEA,IAAIH,MAAMuB,MAAM,EAAE;YAChB,OAAO;gBACL,GAAGvB,KAAK;gBACRuB,QAAQvB,MAAMuB,MAAM,CAACJ,GAAG,CAAC,CAACK,QAAgB,CAAA;wBACxC,GAAGA,KAAK;wBACRN,QAAQM,MAAMN,MAAM,CAACC,GAAG,CAAC,CAACC,WACxBrB,YAAYqB,UAAU,GAAGlB,YAAY,CAAC,EAAEsB,MAAMnB,IAAI,EAAE;oBAExD,CAAA;YACF;QACF;QAEA,OAAOL;IACT;IAEA,MAAMyB,0BAA0B;QAC9B,GAAG5B,gBAAgB;QACnBqB,QAAQrB,iBAAiBqB,MAAM,CAACC,GAAG,CAAC,CAACnB,QAAUD,YAAYC;IAC7D;IAEA,OAAO;QACLF;QACA2B;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/utilities/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, string>\n updatedCollectionConfig: CollectionConfig | GlobalConfig\n}\n\nexport const updateFieldsConfig = (collectionConfig: CollectionConfig | GlobalConfig): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n function updateField(field: any, parentPath = ''): any {\n const currentPath = parentPath ? `${parentPath}.${field.name}` : field.name\n const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`\n\n // Disabled fields/ field types\n if (\n field.admin?.disabled ||\n field.admin?.readOnly ||\n field.admin?.hidden ||\n field.type === 'row'\n ) {\n return field\n }\n\n // Map field path for global fieldInstructionsMap to load related instructions\n // This is done due to save extra API call to get instructions when Field components are loaded in admin\n // Doing is will only call instructions data when user clicks on settings\n if (['richText', 'text', 'textarea', 'upload'].includes(field.type)) {\n schemaPathMap = {\n ...schemaPathMap,\n [currentSchemaPath]: {\n type: field.type,\n label: field.label || field.name,\n relationTo: field.relationTo,\n },\n }\n }\n\n // Inject AI actions, richText is not included here as it has to be explicitly defined by user\n if (['text', 'textarea', 'upload'].includes(field.type)) {\n let customField = {}\n\n // Custom fields don't fully adhere to the Payload schema, making it difficult to\n // determine which components support injecting ComposeField as a Description.\n if (field.admin?.components?.Field || field.admin?.components?.Description) {\n // TODO: Do something?\n customField = {}\n }\n\n return {\n ...field,\n admin: {\n ...field.admin,\n components: {\n ...(field.admin?.components || {}),\n Description: '@ai-stack/payloadcms/fields#ComposeField',\n ...customField,\n },\n },\n }\n }\n\n if (field.fields) {\n return {\n ...field,\n fields: field.fields.map((subField: any) => updateField(subField, currentPath)),\n }\n }\n\n if (field.tabs) {\n return {\n ...field,\n tabs: field.tabs.map((tab: any) => {\n return {\n ...tab,\n fields: tab.fields.map((subField: any) => updateField(subField, tab.name)),\n }\n }),\n }\n }\n\n if (field.blocks) {\n return {\n ...field,\n blocks: field.blocks.map((block: any) => ({\n ...block,\n fields: block.fields.map((subField: any) =>\n updateField(subField, `${currentPath}.${block.slug}`),\n ),\n })),\n }\n }\n\n return field\n }\n\n const updatedCollectionConfig = {\n ...collectionConfig,\n fields: collectionConfig.fields.map((field) => updateField(field)),\n }\n\n return {\n schemaPathMap,\n updatedCollectionConfig,\n }\n}\n"],"names":["updateFieldsConfig","collectionConfig","schemaPathMap","updateField","field","parentPath","currentPath","name","currentSchemaPath","slug","admin","disabled","readOnly","hidden","type","includes","label","relationTo","customField","components","Field","Description","fields","map","subField","tabs","tab","blocks","block","updatedCollectionConfig"],"mappings":"AAOA,OAAO,MAAMA,qBAAqB,CAACC;IACjC,IAAIC,gBAAgB,CAAC;IAErB,SAASC,YAAYC,KAAU,EAAEC,aAAa,EAAE;QAC9C,MAAMC,cAAcD,aAAa,GAAGA,WAAW,CAAC,EAAED,MAAMG,IAAI,EAAE,GAAGH,MAAMG,IAAI;QAC3E,MAAMC,oBAAoB,GAAGP,iBAAiBQ,IAAI,CAAC,CAAC,EAAEH,aAAa;QAEnE,+BAA+B;QAC/B,IACEF,MAAMM,KAAK,EAAEC,YACbP,MAAMM,KAAK,EAAEE,YACbR,MAAMM,KAAK,EAAEG,UACbT,MAAMU,IAAI,KAAK,OACf;YACA,OAAOV;QACT;QAEA,8EAA8E;QAC9E,wGAAwG;QACxG,yEAAyE;QACzE,IAAI;YAAC;YAAY;YAAQ;YAAY;SAAS,CAACW,QAAQ,CAACX,MAAMU,IAAI,GAAG;YACnEZ,gBAAgB;gBACd,GAAGA,aAAa;gBAChB,CAACM,kBAAkB,EAAE;oBACnBM,MAAMV,MAAMU,IAAI;oBAChBE,OAAOZ,MAAMY,KAAK,IAAIZ,MAAMG,IAAI;oBAChCU,YAAYb,MAAMa,UAAU;gBAC9B;YACF;QACF;QAEA,8FAA8F;QAC9F,IAAI;YAAC;YAAQ;YAAY;SAAS,CAACF,QAAQ,CAACX,MAAMU,IAAI,GAAG;YACvD,IAAII,cAAc,CAAC;YAEnB,iFAAiF;YACjF,8EAA8E;YAC9E,IAAId,MAAMM,KAAK,EAAES,YAAYC,SAAShB,MAAMM,KAAK,EAAES,YAAYE,aAAa;gBAC1E,sBAAsB;gBACtBH,cAAc,CAAC;YACjB;YAEA,OAAO;gBACL,GAAGd,KAAK;gBACRM,OAAO;oBACL,GAAGN,MAAMM,KAAK;oBACdS,YAAY;wBACV,GAAIf,MAAMM,KAAK,EAAES,cAAc,CAAC,CAAC;wBACjCE,aAAa;wBACb,GAAGH,WAAW;oBAChB;gBACF;YACF;QACF;QAEA,IAAId,MAAMkB,MAAM,EAAE;YAChB,OAAO;gBACL,GAAGlB,KAAK;gBACRkB,QAAQlB,MAAMkB,MAAM,CAACC,GAAG,CAAC,CAACC,WAAkBrB,YAAYqB,UAAUlB;YACpE;QACF;QAEA,IAAIF,MAAMqB,IAAI,EAAE;YACd,OAAO;gBACL,GAAGrB,KAAK;gBACRqB,MAAMrB,MAAMqB,IAAI,CAACF,GAAG,CAAC,CAACG;oBACpB,OAAO;wBACL,GAAGA,GAAG;wBACNJ,QAAQI,IAAIJ,MAAM,CAACC,GAAG,CAAC,CAACC,WAAkBrB,YAAYqB,UAAUE,IAAInB,IAAI;oBAC1E;gBACF;YACF;QACF;QAEA,IAAIH,MAAMuB,MAAM,EAAE;YAChB,OAAO;gBACL,GAAGvB,KAAK;gBACRuB,QAAQvB,MAAMuB,MAAM,CAACJ,GAAG,CAAC,CAACK,QAAgB,CAAA;wBACxC,GAAGA,KAAK;wBACRN,QAAQM,MAAMN,MAAM,CAACC,GAAG,CAAC,CAACC,WACxBrB,YAAYqB,UAAU,GAAGlB,YAAY,CAAC,EAAEsB,MAAMnB,IAAI,EAAE;oBAExD,CAAA;YACF;QACF;QAEA,OAAOL;IACT;IAEA,MAAMyB,0BAA0B;QAC9B,GAAG5B,gBAAgB;QACnBqB,QAAQrB,iBAAiBqB,MAAM,CAACC,GAAG,CAAC,CAACnB,QAAUD,YAAYC;IAC7D;IAEA,OAAO;QACLF;QACA2B;IACF;AACF,EAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-stack/payloadcms",
3
- "version": "3.2.13-beta",
3
+ "version": "3.2.15-beta",
4
4
  "private": false,
5
5
  "bugs": "https://github.com/ashbuilds/payload-ai/issues",
6
6
  "repository": "https://github.com/ashbuilds/payload-ai",