@ai-stack/payloadcms 3.2.25 → 3.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collections/Instructions.js +18 -7
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/endpoints/fetchFields.js +7 -0
- package/dist/endpoints/fetchFields.js.map +1 -1
- package/dist/endpoints/index.js +16 -8
- package/dist/endpoints/index.js.map +1 -1
- package/dist/init.js +48 -7
- package/dist/init.js.map +1 -1
- package/dist/plugin.js +41 -18
- package/dist/plugin.js.map +1 -1
- package/dist/providers/InstructionsProvider/useInstructions.js +6 -2
- package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
- package/dist/types.d.ts +13 -3
- package/dist/types.js.map +1 -1
- package/dist/utilities/getFieldBySchemaPath.d.ts +2 -2
- package/dist/utilities/getFieldBySchemaPath.js.map +1 -1
- package/dist/utilities/updateFieldsConfig.js +42 -20
- package/dist/utilities/updateFieldsConfig.js.map +1 -1
- package/package.json +1 -1
|
@@ -43,7 +43,9 @@ const defaultAdminConfig = {
|
|
|
43
43
|
group: 'Plugins',
|
|
44
44
|
hidden: true
|
|
45
45
|
};
|
|
46
|
-
export const instructionsCollection = (pluginConfig)=>
|
|
46
|
+
export const instructionsCollection = (pluginConfig)=>{
|
|
47
|
+
const isLocalized = pluginConfig._localization?.enabled && pluginConfig._localization.locales.length > 0;
|
|
48
|
+
return {
|
|
47
49
|
labels: {
|
|
48
50
|
plural: 'Compose Settings',
|
|
49
51
|
singular: 'Compose Setting'
|
|
@@ -58,6 +60,9 @@ export const instructionsCollection = (pluginConfig)=>({
|
|
|
58
60
|
...defaultAdminConfig,
|
|
59
61
|
...pluginConfig.overrideInstructions?.admin
|
|
60
62
|
},
|
|
63
|
+
...isLocalized ? {
|
|
64
|
+
localization: true
|
|
65
|
+
} : {},
|
|
61
66
|
fields: [
|
|
62
67
|
{
|
|
63
68
|
name: 'schema-path',
|
|
@@ -145,6 +150,10 @@ export const instructionsCollection = (pluginConfig)=>({
|
|
|
145
150
|
{
|
|
146
151
|
name: 'prompt',
|
|
147
152
|
type: 'textarea',
|
|
153
|
+
// Make prompt localized if localization is enabled
|
|
154
|
+
...isLocalized ? {
|
|
155
|
+
localized: true
|
|
156
|
+
} : {},
|
|
148
157
|
admin: {
|
|
149
158
|
components: {
|
|
150
159
|
Field: '@ai-stack/payloadcms/fields#PromptEditorField'
|
|
@@ -192,6 +201,9 @@ export const instructionsCollection = (pluginConfig)=>({
|
|
|
192
201
|
{
|
|
193
202
|
name: 'system',
|
|
194
203
|
type: 'textarea',
|
|
204
|
+
...isLocalized ? {
|
|
205
|
+
localized: true
|
|
206
|
+
} : {},
|
|
195
207
|
defaultValue: `INSTRUCTIONS:
|
|
196
208
|
You are a highly skilled and professional blog writer,
|
|
197
209
|
renowned for crafting engaging and well-organized articles.
|
|
@@ -216,13 +228,11 @@ informative and accurate but also captivating and beautifully structured.`,
|
|
|
216
228
|
* - User can add their own layout to collections and use it later for generate specific rich text
|
|
217
229
|
* - User can select previously added layout
|
|
218
230
|
* - IMP: Remove layout from default, this seem to affect other functions like rephrase etc.
|
|
219
|
-
*/ /** TODO:
|
|
220
|
-
* - Layouts can be saved in as an array
|
|
221
|
-
* - User can add their own layout to collections and use it later for generate specific rich text
|
|
222
|
-
* - User can select previously added layout
|
|
223
|
-
* - IMP: Remove layout from default, this seem to affect other functions like rephrase etc.
|
|
224
231
|
*/ name: 'layout',
|
|
225
232
|
type: 'textarea',
|
|
233
|
+
...isLocalized ? {
|
|
234
|
+
localized: true
|
|
235
|
+
} : {},
|
|
226
236
|
admin: {
|
|
227
237
|
condition: (_, current)=>{
|
|
228
238
|
return current['field-type'] === 'richText';
|
|
@@ -245,6 +255,7 @@ informative and accurate but also captivating and beautifully structured.`,
|
|
|
245
255
|
},
|
|
246
256
|
...groupSettings(pluginConfig)
|
|
247
257
|
]
|
|
248
|
-
}
|
|
258
|
+
};
|
|
259
|
+
};
|
|
249
260
|
|
|
250
261
|
//# sourceMappingURL=Instructions.js.map
|
|
@@ -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: ({ req }: { req: { user?: any } }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n delete: ({ req }: { req: { user?: any } }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n read: ({ req }: { req: { user?: any } }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n update: ({ req }: { req: { user?: any } }) => {\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 = (pluginConfig: PluginConfig) =>\n <CollectionConfig>{\n labels: {\n plural: 'Compose Settings',\n singular: 'Compose Setting',\n },\n ...pluginConfig.overrideInstructions,\n slug: PLUGIN_INSTRUCTIONS_TABLE,\n access: {\n ...defaultAccessConfig,\n ...pluginConfig.overrideInstructions?.access,\n },\n admin: {\n ...defaultAdminConfig,\n ...pluginConfig.overrideInstructions?.admin,\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 name: 'disabled',\n type: 'checkbox',\n admin: {\n description: 'Please reload your collection after applying the changes',\n },\n defaultValue: false,\n label: 'Hide Compose button for this field',\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 * - IMP: Remove layout from default, this seem to affect other functions like rephrase etc.\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 }\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","labels","plural","singular","overrideInstructions","slug","access","admin","type","description","unique","defaultValue","options","condition","_","current","components","Field","clientProps","filterByField","path","option","tabs","relationTo","uploadCollectionSlug"],"mappings":"AAGA,SAASA,yBAAyB,QAAQ,iBAAgB;AAC1D,SAASC,mBAAmB,QAAQ,sCAAqC;AAEzE,MAAMC,gBAAgB,CAACC,eACrB,AAACF,CAAAA,oBAAoBE,iBAAiB,EAAE,AAAD,EAAGC,MAAM,CAAC,CAACC,QAAQC;QACxD,IAAIA,MAAMC,QAAQ,EAAE;YAClBF,OAAOG,IAAI,CAACF,MAAMC,QAAQ;QAC5B;QACA,OAAOF;IACT,GAAG,EAAE;AAEP,MAAMI,eAAe,CAACN,eACpB,AAACF,CAAAA,oBAAoBE,iBAAiB,EAAE,AAAD,EAAGO,GAAG,CAAC,CAACJ;QAC7C,OAAO;YACLD,QAAQC,MAAMD,MAAM;YACpBM,OAAOL,MAAMM,IAAI;YACjBC,OAAOP,MAAMQ,EAAE;QACjB;IACF;AAEF,MAAMC,sBAAsB;IAC1BC,QAAQ,CAAC,EAAEC,GAAG,EAA2B;QACvC,IAAI,CAACA,IAAIC,IAAI,EAAE;YACb,OAAO;QACT;QACA,OAAO;IACT;IACAC,QAAQ,CAAC,EAAEF,GAAG,EAA2B;QACvC,IAAI,CAACA,IAAIC,IAAI,EAAE;YACb,OAAO;QACT;QACA,OAAO;IACT;IACAE,MAAM,CAAC,EAAEH,GAAG,EAA2B;QACrC,IAAI,CAACA,IAAIC,IAAI,EAAE;YACb,OAAO;QACT;QACA,OAAO;IACT;IACAG,QAAQ,CAAC,EAAEJ,GAAG,EAA2B;QACvC,IAAI,CAACA,IAAIC,IAAI,EAAE;YACb,OAAO;QACT;QACA,OAAO;IACT;AACF;AAEA,MAAMI,qBAAqB;IACzBC,OAAO;IACPC,QAAQ;AACV;AAEA,OAAO,MAAMC,yBAAyB,CAACtB,eACnB,CAAA;QAChBuB,QAAQ;YACNC,QAAQ;YACRC,UAAU;QACZ;QACA,GAAGzB,aAAa0B,oBAAoB;QACpCC,MAAM9B;QACN+B,QAAQ;YACN,GAAGhB,mBAAmB;YACtB,GAAGZ,aAAa0B,oBAAoB,EAAEE,MAAM;QAC9C;QACAC,OAAO;YACL,GAAGV,kBAAkB;YACrB,GAAGnB,aAAa0B,oBAAoB,EAAEG,KAAK;QAC7C;QACA3B,QAAQ;YACN;gBACEO,MAAM;gBACNqB,MAAM;gBACND,OAAO;oBACLE,aAAa;gBACf;gBACAC,QAAQ;YACV;YACA;gBACEvB,MAAM;gBACNqB,MAAM;gBACND,OAAO;oBACLE,aAAa;gBACf;gBACAE,cAAc;gBACdzB,OAAO;gBACP0B,SAAS;oBACP;wBACE1B,OAAO;wBACPE,OAAO;oBACT;oBACA;wBACEF,OAAO;wBACPE,OAAO;oBACT;oBACA;wBACEF,OAAO;wBACPE,OAAO;oBACT;oBACA;wBACEF,OAAO;wBACPE,OAAO;oBACT;iBACD;YACH;YACA;gBACED,MAAM;gBACNqB,MAAM;gBACND,OAAO;oBACLM,WAAW,CAACC,GAAGC;wBACb,OAAOA,OAAO,CAAC,aAAa,KAAK;oBACnC;gBACF;gBACA7B,OAAO;YACT;YACA;gBACEC,MAAM;gBACNqB,MAAM;gBACND,OAAO;oBACLS,YAAY;wBACVC,OAAO;4BACLC,aAAa;gCACXC,eAAe;gCACfP,SAAS5B,aAAaN;4BACxB;4BACA0C,MAAM;wBACR;oBACF;gBACF;gBACAlC,OAAO;gBACP0B,SAAS5B,aAAaN,cAAcO,GAAG,CAAC,CAACoC;oBACvC,OAAO;wBACLnC,OAAOmC,OAAOnC,KAAK;wBACnBE,OAAOiC,OAAOjC,KAAK;oBACrB;gBACF;YACF;YACA;gBACED,MAAM;gBACNqB,MAAM;gBACND,OAAO;oBACLE,aAAa;gBACf;gBACAE,cAAc;gBACdzB,OAAO;YACT;YACA;gBACEG,IAAI;gBACJmB,MAAM;gBACNc,MAAM;oBACJ;wBACEb,aACE;wBACF7B,QAAQ;4BACN;gCACEO,MAAM;gCACNqB,MAAM;gCACND,OAAO;oCACLS,YAAY;wCACVC,OAAO;oCACT;oCACAR,aAAa;gCACf;gCACAvB,OAAO;4BACT;yBACD;wBACDA,OAAO;oBACT;oBACA;wBACEqB,OAAO;4BACLM,WAAW,CAACC,GAAGC;gCACb,OAAOA,OAAO,CAAC,aAAa,KAAK,YAAYA,OAAO,CAAC,WAAW,KAAK;4BACvE;wBACF;wBACAN,aACE;wBACF7B,QAAQ;4BACN;gCACEO,MAAM;gCACNqB,MAAM;gCACN5B,QAAQ;oCACN;wCACEO,MAAM;wCACNqB,MAAM;wCACND,OAAO;4CACLE,aAAa;wCACf;wCACAc,YAAY7C,aAAa8C,oBAAoB,GACzC9C,aAAa8C,oBAAoB,GACjC;oCACN;iCACD;4BACH;yBACD;wBACDtC,OAAO;oBACT;oBACA;wBACEqB,OAAO;4BACLM,WAAW,CAACC,GAAGC;gCACb,OAAOA,OAAO,CAAC,aAAa,KAAK;4BACnC;wBACF;wBACAN,aAAa;wBACb7B,QAAQ;4BACN;gCACEO,MAAM;gCACNqB,MAAM;gCACNG,cAAc,CAAC;;;;yEAI0C,CAAC;gCAC1DzB,OAAO;4BACT;yBACD;wBACDA,OAAO;oBACT;oBACA;wBACEqB,OAAO;4BACLM,WAAW,CAACC,GAAGC;gCACb,OAAOA,OAAO,CAAC,aAAa,KAAK;4BACnC;wBACF;wBACAN,aAAa;wBACb7B,QAAQ;4BACN;gCACE;;;;;iBAKC,GALD;;;;;iBAKC,GACDO,MAAM;gCACNqB,MAAM;gCACND,OAAO;oCACLM,WAAW,CAACC,GAAGC;wCACb,OAAOA,OAAO,CAAC,aAAa,KAAK;oCACnC;gCACF;gCACAJ,cAAc,CAAC;;;;;;;2HAO4F,CAAC;gCAC5GzB,OAAO;4BACT;yBACD;wBACDA,OAAO;oBACT;iBACD;YACH;eACGT,cAAcC;SAClB;IACH,CAAA,EAAC"}
|
|
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 }: { req: { user?: unknown } }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n delete: ({ req }: { req: { user?: unknown } }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n read: ({ req }: { req: { user?: unknown } }) => {\n if (!req.user) {\n return false\n }\n return true\n },\n update: ({ req }: { req: { user?: unknown } }) => {\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 = (pluginConfig: PluginConfig) => {\n const isLocalized =\n pluginConfig._localization?.enabled && pluginConfig._localization.locales.length > 0\n\n return <CollectionConfig>{\n labels: {\n plural: 'Compose Settings',\n singular: 'Compose Setting',\n },\n ...pluginConfig.overrideInstructions,\n slug: PLUGIN_INSTRUCTIONS_TABLE,\n access: {\n ...defaultAccessConfig,\n ...pluginConfig.overrideInstructions?.access,\n },\n admin: {\n ...defaultAdminConfig,\n ...pluginConfig.overrideInstructions?.admin,\n },\n ...(isLocalized ? { localization: true } : {}),\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: (_: unknown, current: Record<string, unknown>) => {\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 name: 'disabled',\n type: 'checkbox',\n admin: {\n description: 'Please reload your collection after applying the changes',\n },\n defaultValue: false,\n label: 'Hide Compose button for this field',\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 // Make prompt localized if localization is enabled\n ...(isLocalized ? { localized: true } : {}),\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: (_: unknown, current: Record<string, unknown>) => {\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: (_: unknown, current: Record<string, unknown>) => {\n return current['field-type'] === 'richText'\n },\n },\n description: '',\n fields: [\n {\n name: 'system',\n type: 'textarea',\n ...(isLocalized ? { localized: true } : {}),\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: (_: unknown, current: Record<string, unknown>) => {\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 * - IMP: Remove layout from default, this seem to affect other functions like rephrase etc.\n */\n name: 'layout',\n type: 'textarea',\n ...(isLocalized ? { localized: true } : {}),\n admin: {\n condition: (_: unknown, current: Record<string, unknown>) => {\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 }\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","isLocalized","_localization","enabled","locales","length","labels","plural","singular","overrideInstructions","slug","access","admin","localization","type","description","unique","defaultValue","options","condition","_","current","components","Field","clientProps","filterByField","path","option","tabs","localized","relationTo","uploadCollectionSlug"],"mappings":"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"}
|
|
@@ -3,8 +3,15 @@ export const fetchFields = (config)=>{
|
|
|
3
3
|
const { access, options = {}, promptFields = [] } = config;
|
|
4
4
|
return {
|
|
5
5
|
handler: async (req)=>{
|
|
6
|
+
// Check if localization is enabled
|
|
7
|
+
const { locales = [] } = req.payload.config.localization || {};
|
|
8
|
+
const isLocalized = locales.length > 0;
|
|
9
|
+
// Get locale from request if available (from query params or headers)
|
|
10
|
+
const locale = req.query?.locale;
|
|
11
|
+
// Fetch instructions - if localized, fetch for the requested locale or default
|
|
6
12
|
const { docs = [] } = await req.payload.find({
|
|
7
13
|
collection: PLUGIN_INSTRUCTIONS_TABLE,
|
|
14
|
+
locale: isLocalized && locale ? locale : undefined,
|
|
8
15
|
pagination: false
|
|
9
16
|
});
|
|
10
17
|
let isConfigAllowed = true // Users allowed to update prompts by default
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/fetchFields.ts"],"sourcesContent":["import type { Endpoint, PayloadRequest } from 'payload'\n\nimport type { PluginConfig, SerializedPromptField } from '../types.js'\n\nimport { PLUGIN_FETCH_FIELDS_ENDPOINT, PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\n\nexport const fetchFields: (config: PluginConfig) => Endpoint = (config) => {\n const { access, options = {}, promptFields = [] } = config\n return {\n handler: async (req: PayloadRequest) => {\n const { docs = [] } = await req.payload.find({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n pagination: false,\n })\n\n let isConfigAllowed = true // Users allowed to update prompts by default\n\n if (access?.settings) {\n try {\n isConfigAllowed = await access.settings({ req })\n } catch (e) {\n req.payload.logger.error(req, 'Please check your \"access.settings\" for request')\n }\n }\n\n const fieldMap: Record<string, { disabled?: boolean; fieldType: any; id: any }> = {}\n docs.forEach((doc) => {\n fieldMap[doc['schema-path']] = {\n id: doc.id,\n disabled: !!doc['disabled'],\n fieldType: doc['field-type'],\n }\n })\n\n return Response.json({\n ...options,\n debugging: config.debugging,\n fields: fieldMap,\n isConfigAllowed,\n promptFields: promptFields.map(({ getter: _getter, ...field }): SerializedPromptField => {\n return field\n }),\n })\n },\n method: 'get',\n path: PLUGIN_FETCH_FIELDS_ENDPOINT,\n }\n}\n"],"names":["PLUGIN_FETCH_FIELDS_ENDPOINT","PLUGIN_INSTRUCTIONS_TABLE","fetchFields","config","access","options","promptFields","handler","req","
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/fetchFields.ts"],"sourcesContent":["import type { Endpoint, PayloadRequest } from 'payload'\n\nimport type { PluginConfig, SerializedPromptField } from '../types.js'\n\nimport { PLUGIN_FETCH_FIELDS_ENDPOINT, PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\n\nexport const fetchFields: (config: PluginConfig) => Endpoint = (config) => {\n const { access, options = {}, promptFields = [] } = config\n return {\n handler: async (req: PayloadRequest) => {\n // Check if localization is enabled\n const { locales = [] } = req.payload.config.localization || {}\n const isLocalized = locales.length > 0\n \n // Get locale from request if available (from query params or headers)\n const locale = req.query?.locale as string | undefined\n \n // Fetch instructions - if localized, fetch for the requested locale or default\n const { docs = [] } = await req.payload.find({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n locale: isLocalized && locale ? locale : undefined,\n pagination: false,\n })\n\n let isConfigAllowed = true // Users allowed to update prompts by default\n\n if (access?.settings) {\n try {\n isConfigAllowed = await access.settings({ req })\n } catch (e) {\n req.payload.logger.error(req, 'Please check your \"access.settings\" for request')\n }\n }\n\n const fieldMap: Record<string, { disabled?: boolean; fieldType: any; id: any }> = {}\n docs.forEach((doc) => {\n fieldMap[doc['schema-path']] = {\n id: doc.id,\n disabled: !!doc['disabled'],\n fieldType: doc['field-type'],\n }\n })\n\n return Response.json({\n ...options,\n debugging: config.debugging,\n fields: fieldMap,\n isConfigAllowed,\n promptFields: promptFields.map(({ getter: _getter, ...field }): SerializedPromptField => {\n return field\n }),\n })\n },\n method: 'get',\n path: PLUGIN_FETCH_FIELDS_ENDPOINT,\n }\n}\n"],"names":["PLUGIN_FETCH_FIELDS_ENDPOINT","PLUGIN_INSTRUCTIONS_TABLE","fetchFields","config","access","options","promptFields","handler","req","locales","payload","localization","isLocalized","length","locale","query","docs","find","collection","undefined","pagination","isConfigAllowed","settings","e","logger","error","fieldMap","forEach","doc","id","disabled","fieldType","Response","json","debugging","fields","map","getter","_getter","field","method","path"],"mappings":"AAIA,SAASA,4BAA4B,EAAEC,yBAAyB,QAAQ,iBAAgB;AAExF,OAAO,MAAMC,cAAkD,CAACC;IAC9D,MAAM,EAAEC,MAAM,EAAEC,UAAU,CAAC,CAAC,EAAEC,eAAe,EAAE,EAAE,GAAGH;IACpD,OAAO;QACLI,SAAS,OAAOC;YACd,mCAAmC;YACnC,MAAM,EAAEC,UAAU,EAAE,EAAE,GAAGD,IAAIE,OAAO,CAACP,MAAM,CAACQ,YAAY,IAAI,CAAC;YAC7D,MAAMC,cAAcH,QAAQI,MAAM,GAAG;YAErC,sEAAsE;YACtE,MAAMC,SAASN,IAAIO,KAAK,EAAED;YAE1B,+EAA+E;YAC/E,MAAM,EAAEE,OAAO,EAAE,EAAE,GAAG,MAAMR,IAAIE,OAAO,CAACO,IAAI,CAAC;gBAC3CC,YAAYjB;gBACZa,QAAQF,eAAeE,SAASA,SAASK;gBACzCC,YAAY;YACd;YAEA,IAAIC,kBAAkB,KAAK,6CAA6C;;YAExE,IAAIjB,QAAQkB,UAAU;gBACpB,IAAI;oBACFD,kBAAkB,MAAMjB,OAAOkB,QAAQ,CAAC;wBAAEd;oBAAI;gBAChD,EAAE,OAAOe,GAAG;oBACVf,IAAIE,OAAO,CAACc,MAAM,CAACC,KAAK,CAACjB,KAAK;gBAChC;YACF;YAEA,MAAMkB,WAA4E,CAAC;YACnFV,KAAKW,OAAO,CAAC,CAACC;gBACZF,QAAQ,CAACE,GAAG,CAAC,cAAc,CAAC,GAAG;oBAC7BC,IAAID,IAAIC,EAAE;oBACVC,UAAU,CAAC,CAACF,GAAG,CAAC,WAAW;oBAC3BG,WAAWH,GAAG,CAAC,aAAa;gBAC9B;YACF;YAEA,OAAOI,SAASC,IAAI,CAAC;gBACnB,GAAG5B,OAAO;gBACV6B,WAAW/B,OAAO+B,SAAS;gBAC3BC,QAAQT;gBACRL;gBACAf,cAAcA,aAAa8B,GAAG,CAAC,CAAC,EAAEC,QAAQC,OAAO,EAAE,GAAGC,OAAO;oBAC3D,OAAOA;gBACT;YACF;QACF;QACAC,QAAQ;QACRC,MAAMzC;IACR;AACF,EAAC"}
|
package/dist/endpoints/index.js
CHANGED
|
@@ -42,7 +42,7 @@ const extendContextWithPromptFields = (data, ctx, pluginConfig)=>{
|
|
|
42
42
|
return Promise.resolve(value).then((v)=>new asyncHandlebars.SafeString(v));
|
|
43
43
|
}
|
|
44
44
|
// {{prop}} escapes content by default. Here we make sure it won't be escaped.
|
|
45
|
-
const value = typeof target ===
|
|
45
|
+
const value = typeof target === 'object' ? target[prop] : undefined;
|
|
46
46
|
return typeof value === 'string' ? new asyncHandlebars.SafeString(value) : value;
|
|
47
47
|
},
|
|
48
48
|
// It's used by the handlebars library to determine if the property is enumerable
|
|
@@ -150,10 +150,15 @@ export const endpoints = (pluginConfig)=>({
|
|
|
150
150
|
if (!instructionId) {
|
|
151
151
|
throw new Error(`Instruction ID is required for "${PLUGIN_NAME}" to work, please check your configuration, or try again`);
|
|
152
152
|
}
|
|
153
|
+
const { defaultLocale, locales = [] } = req.payload.config.localization || {};
|
|
154
|
+
const localeData = locales.find((l)=>{
|
|
155
|
+
return l.code === locale;
|
|
156
|
+
});
|
|
153
157
|
// Verify user has access to the specific instruction
|
|
154
158
|
const instructions = await req.payload.findByID({
|
|
155
159
|
id: instructionId,
|
|
156
160
|
collection: PLUGIN_INSTRUCTIONS_TABLE,
|
|
161
|
+
locale: locales.length > 0 && locale ? locale : undefined,
|
|
157
162
|
req
|
|
158
163
|
});
|
|
159
164
|
const { collections } = req.payload.config;
|
|
@@ -173,10 +178,6 @@ export const endpoints = (pluginConfig)=>({
|
|
|
173
178
|
const collectionName = parts[0];
|
|
174
179
|
const fieldName = parts.length > 1 ? parts[parts.length - 1] : '';
|
|
175
180
|
registerEditorHelper(req.payload, schemaPath);
|
|
176
|
-
const { defaultLocale, locales = [] } = req.payload.config.localization || {};
|
|
177
|
-
const localeData = locales.find((l)=>{
|
|
178
|
-
return l.code === locale;
|
|
179
|
-
});
|
|
180
181
|
let localeInfo = locale;
|
|
181
182
|
if (localeData && defaultLocale && localeData.label && typeof localeData.label === 'object' && defaultLocale in localeData.label) {
|
|
182
183
|
localeInfo = localeData.label[defaultLocale];
|
|
@@ -186,7 +187,7 @@ export const endpoints = (pluginConfig)=>({
|
|
|
186
187
|
if (!model) {
|
|
187
188
|
throw new Error('Model not found');
|
|
188
189
|
}
|
|
189
|
-
const settingsName = model.settings &&
|
|
190
|
+
const settingsName = model.settings && 'name' in model.settings ? model.settings.name : undefined;
|
|
190
191
|
if (!settingsName) {
|
|
191
192
|
req.payload.logger.error('— AI Plugin: Error fetching settings name!');
|
|
192
193
|
}
|
|
@@ -212,8 +213,10 @@ export const endpoints = (pluginConfig)=>({
|
|
|
212
213
|
let jsonSchema = allowedEditorSchema;
|
|
213
214
|
try {
|
|
214
215
|
const targetCollection = req.payload.config.collections.find((c)=>c.slug === collectionName);
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
const targetGlobal = req.payload.config.globals?.find((g)=>g.slug === collectionName);
|
|
217
|
+
const targetConfig = targetCollection || targetGlobal;
|
|
218
|
+
if (targetConfig && fieldName) {
|
|
219
|
+
const targetField = getFieldBySchemaPath(targetConfig, schemaPath);
|
|
217
220
|
const supported = [
|
|
218
221
|
'text',
|
|
219
222
|
'textarea',
|
|
@@ -288,10 +291,15 @@ export const endpoints = (pluginConfig)=>({
|
|
|
288
291
|
prompt: ''
|
|
289
292
|
};
|
|
290
293
|
if (instructionId) {
|
|
294
|
+
// Get locale from request if available
|
|
295
|
+
const { locale: requestLocale } = data;
|
|
296
|
+
const { locales = [] } = req.payload.config.localization || {};
|
|
291
297
|
// Verify user has access to the specific instruction
|
|
298
|
+
// Pass locale if localization is enabled for the Instructions collection
|
|
292
299
|
instructions = await req.payload.findByID({
|
|
293
300
|
id: instructionId,
|
|
294
301
|
collection: PLUGIN_INSTRUCTIONS_TABLE,
|
|
302
|
+
locale: locales.length > 0 && requestLocale ? requestLocale : undefined,
|
|
295
303
|
req
|
|
296
304
|
});
|
|
297
305
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/index.ts"],"sourcesContent":["import type { CollectionSlug, PayloadRequest } from 'payload'\n\nimport * as process from 'node:process'\n\nimport type {\n ActionMenuItems,\n Endpoints,\n PluginConfig,\n PromptFieldGetterContext,\n} 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 { asyncHandlebars } from '../libraries/handlebars/asyncHandlebars.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 { fieldToJsonSchema } from '../utilities/fieldToJsonSchema.js'\nimport { getFieldBySchemaPath } from '../utilities/getFieldBySchemaPath.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 extendContextWithPromptFields = (\n data: object,\n ctx: PromptFieldGetterContext,\n pluginConfig: PluginConfig,\n) => {\n const { promptFields = [] } = pluginConfig\n const fieldsMap = new Map(\n promptFields\n .filter((f) => !f.collections || f.collections.includes(ctx.collection))\n .map((f) => [f.name, f]),\n )\n return new Proxy(data, {\n get: (target, prop: string) => {\n const field = fieldsMap.get(prop)\n if (field?.getter) {\n const value = field.getter(data, ctx)\n return Promise.resolve(value).then((v) => new asyncHandlebars.SafeString(v))\n }\n // {{prop}} escapes content by default. Here we make sure it won't be escaped.\n const value = typeof target === \"object\" ? (target as any)[prop] : undefined\n return typeof value === 'string' ? new asyncHandlebars.SafeString(value) : value\n },\n // It's used by the handlebars library to determine if the property is enumerable\n getOwnPropertyDescriptor: (target, prop) => {\n const field = fieldsMap.get(prop as string)\n if (field) {\n return {\n configurable: true,\n enumerable: true,\n }\n }\n return Object.getOwnPropertyDescriptor(target, prop)\n },\n has: (target, prop) => {\n return fieldsMap.has(prop as string) || (target && prop in target)\n },\n ownKeys: (target) => {\n return [...fieldsMap.keys(), ...Object.keys(target || {})]\n },\n })\n}\n\nconst buildRichTextSystem = (baseSystem: string, layout: string) => {\n return `${baseSystem}\n\nRULES:\n- Generate original and unique content based on the given topic.\n- Strictly adhere to the specified layout and formatting instructions.\n- Utilize the provided rich text editor tools for appropriate formatting.\n- Ensure the output follows the structure of the sample output object.\n- Produce valid JSON with no undefined or null values.\n---\nLAYOUT INSTRUCTIONS:\n${layout}\n\n---\nADDITIONAL GUIDELINES:\n- Ensure coherence and logical flow between all sections.\n- Maintain a consistent tone and style throughout the content.\n- Use clear and concise language appropriate for the target audience.\n`;\n};\n\nconst assignPrompt = async (\n action: ActionMenuItems,\n {\n type,\n actionParams,\n collection,\n context,\n field,\n layout,\n locale,\n pluginConfig,\n systemPrompt = '',\n template,\n }: {\n actionParams: Record<any, any>\n collection: CollectionSlug\n context: object\n field: string\n layout: string\n locale: string\n pluginConfig: PluginConfig\n systemPrompt: string\n template: string\n type: string\n },\n) => {\n const extendedContext = extendContextWithPromptFields(context, { type, collection }, pluginConfig)\n const prompt = await replacePlaceholders(template, extendedContext)\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' ? buildRichTextSystem(systemPrompt, layout) : undefined,\n }\n\n if (action === 'Compose') {\n if (locale && locale !== 'en') {\n /**\n * NOTE: Avoid using the \"system prompt\" for setting the output language,\n * as it causes quotation marks to appear in the output (Currently only tested with openai models).\n * Appending the language instruction directly to the prompt resolves this issue.\n **/\n assignedPrompts.prompt += `\n --- \n OUTPUT LANGUAGE: ${locale}\n `\n }\n\n return assignedPrompts\n }\n\n const prompts = [...(pluginConfig.prompts || []), ...defaultPrompts]\n const foundPrompt = prompts.find((p) => p.name === action)\n const getLayout = foundPrompt?.layout\n const getSystemPrompt = foundPrompt?.system\n\n let updatedLayout = layout\n if (getLayout) {\n updatedLayout = getLayout()\n }\n\n const system = getSystemPrompt\n ? getSystemPrompt({\n ...(actionParams || {}),\n prompt,\n systemPrompt,\n })\n : ''\n\n return {\n layout: updatedLayout,\n // TODO: revisit this toLexicalHTML\n prompt: await replacePlaceholders(`{{${toLexicalHTML} ${field}}}`, extendedContext),\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, or try again`,\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 if (!collection) {\n throw new Error('Collection not found')\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 parts = schemaPath?.split('.') || []\n const collectionName = parts[0]\n const fieldName = parts.length > 1 ? parts[parts.length - 1] : ''\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 let localeInfo = locale\n if (\n localeData &&\n defaultLocale &&\n localeData.label &&\n typeof localeData.label === 'object' &&\n defaultLocale in localeData.label\n ) {\n localeInfo = localeData.label[defaultLocale]\n }\n\n const models = getGenerationModels(pluginConfig)\n const model =\n models && Array.isArray(models)\n ? models.find((model) => model.id === instructions['model-id'])\n : undefined\n\n if (!model) {\n throw new Error('Model not found')\n }\n\n const settingsName = model.settings && \"name\" in model.settings ? model.settings.name : undefined\n if (!settingsName) {\n req.payload.logger.error('— AI Plugin: Error fetching settings name!')\n }\n\n const modelOptions = settingsName ? instructions[settingsName] || {} : {}\n\n const prompts = await assignPrompt(action, {\n type: String(instructions['field-type']),\n actionParams,\n collection: collectionName,\n context: contextData,\n field: fieldName || '',\n layout: instructions.layout,\n locale: localeInfo,\n pluginConfig,\n systemPrompt: instructions.system,\n template: String(promptTemplate),\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n { prompts },\n `— AI Plugin: Executing text prompt on ${schemaPath} using ${model.id}`,\n )\n }\n\n // Build per-field JSON schema for structured generation when applicable\n let jsonSchema= allowedEditorSchema\n try {\n const targetCollection = req.payload.config.collections.find(\n (c) => c.slug === collectionName,\n )\n if (targetCollection && fieldName) {\n const targetField = getFieldBySchemaPath(targetCollection, schemaPath)\n const supported = ['text', 'textarea', 'select', 'number', 'date', 'code', 'email', 'json']\n const t = String(targetField?.type || '')\n if (targetField && supported.includes(t)) {\n jsonSchema = fieldToJsonSchema(targetField as any, { nameOverride: fieldName })\n }\n }\n } catch (e) {\n req.payload.logger.error(e, '— AI Plugin: Error building field JSON schema')\n }\n\n return model.handler?.(prompts.prompt, {\n ...modelOptions,\n layout: prompts.layout,\n locale: localeInfo,\n schema: jsonSchema,\n system: prompts.system,\n })\n } catch (error) {\n req.payload.logger.error(error, 'Error generating content: ')\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as any).message\n : String(error)\n return new Response(JSON.stringify({ error: message }), {\n headers: { 'Content-Type': 'application/json' },\n status:\n message.includes('Authentication required') ||\n message.includes('Insufficient permissions')\n ? 401\n : 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 e,\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: Record<string, any> = { images: [], 'model-id': '', prompt: '' }\n\n if (instructionId) {\n // Verify user has access to the specific instruction\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 extendedContext = extendContextWithPromptFields(\n contextData,\n { type: instructions['field-type'], collection: collectionSlug },\n pluginConfig,\n )\n const text = await replacePlaceholders(promptTemplate, extendedContext)\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 const serverURL =\n req.payload.config?.serverURL ||\n process.env.SERVER_URL ||\n process.env.NEXT_PUBLIC_SERVER_URL\n\n let url = img.image.thumbnailURL || img.image.url\n if (!url.startsWith('http')) {\n url = `${serverURL}${url}`\n }\n\n try {\n\n const response = await fetch(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,\n })\n } catch (e) {\n req.payload.logger.error(e, `Error fetching reference image ${url}`)\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 modelsUpload = getGenerationModels(pluginConfig)\n const model =\n modelsUpload && Array.isArray(modelsUpload)\n ? modelsUpload.find((model) => model.id === modelId)\n : undefined\n\n if (!model) {\n throw new Error('Model not found')\n }\n\n // @ts-ignore\n const settingsName = model && model.settings ? model.settings.name : undefined\n if (!settingsName) {\n req.payload.logger.error('— AI Plugin: Error fetching settings name!')\n }\n\n let modelOptions = settingsName ? instructions[settingsName] || {} : {}\n modelOptions = {\n ...modelOptions,\n images: editImages,\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n { text },\n `— AI Plugin: Executing image prompt using ${model.id}`,\n )\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, 'Error generating upload: ')\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as any).message\n : String(error)\n return new Response(JSON.stringify({ error: message }), {\n headers: { 'Content-Type': 'application/json' },\n status:\n message.includes('Authentication required') ||\n message.includes('Insufficient permissions')\n ? 401\n : 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","asyncHandlebars","registerEditorHelper","handlebarsHelpersMap","replacePlaceholders","extractImageData","fieldToJsonSchema","getFieldBySchemaPath","getGenerationModels","requireAuthentication","req","user","Error","checkAccess","pluginConfig","access","generate","hasAccess","extendContextWithPromptFields","data","ctx","promptFields","fieldsMap","Map","filter","f","collections","includes","collection","map","name","Proxy","get","target","prop","field","getter","value","Promise","resolve","then","v","SafeString","undefined","getOwnPropertyDescriptor","configurable","enumerable","Object","has","ownKeys","keys","buildRichTextSystem","baseSystem","layout","assignPrompt","action","type","actionParams","context","locale","systemPrompt","template","extendedContext","prompt","toLexicalHTML","toHTML","assignedPrompts","system","prompts","foundPrompt","find","p","getLayout","getSystemPrompt","updatedLayout","endpoints","textarea","handler","json","allowedEditorNodes","options","instructionId","contextData","doc","instructions","payload","findByID","id","config","slug","custom","editorConfig","admin","schema","editorSchema","promptTemplate","allowedEditorSchema","length","schemaPath","parts","split","collectionName","fieldName","defaultLocale","locales","localization","localeData","l","code","localeInfo","label","models","model","Array","isArray","settingsName","settings","logger","error","modelOptions","String","debugging","info","jsonSchema","targetCollection","c","targetField","supported","t","nameOverride","e","message","Response","JSON","stringify","headers","status","method","path","upload","collectionSlug","documentId","docData","draft","images","sampleImages","text","modelId","uploadCollectionSlug","editImages","img","serverURL","env","SERVER_URL","NEXT_PUBLIC_SERVER_URL","url","image","thumbnailURL","startsWith","response","fetch","Authorization","blob","push","size","modelsUpload","result","assetData","mediaUpload","request","create","file","alt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/index.ts"],"sourcesContent":["import type { CollectionSlug, PayloadRequest } from 'payload'\n\nimport * as process from 'node:process'\n\nimport type {\n ActionMenuItems,\n Endpoints,\n PluginConfig,\n PromptFieldGetterContext,\n} 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 { asyncHandlebars } from '../libraries/handlebars/asyncHandlebars.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 { fieldToJsonSchema } from '../utilities/fieldToJsonSchema.js'\nimport { getFieldBySchemaPath } from '../utilities/getFieldBySchemaPath.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 extendContextWithPromptFields = (\n data: object,\n ctx: PromptFieldGetterContext,\n pluginConfig: PluginConfig,\n) => {\n const { promptFields = [] } = pluginConfig\n const fieldsMap = new Map(\n promptFields\n .filter((f) => !f.collections || f.collections.includes(ctx.collection))\n .map((f) => [f.name, f]),\n )\n return new Proxy(data, {\n get: (target, prop: string) => {\n const field = fieldsMap.get(prop)\n if (field?.getter) {\n const value = field.getter(data, ctx)\n return Promise.resolve(value).then((v) => new asyncHandlebars.SafeString(v))\n }\n // {{prop}} escapes content by default. Here we make sure it won't be escaped.\n const value = typeof target === 'object' ? (target as any)[prop] : undefined\n return typeof value === 'string' ? new asyncHandlebars.SafeString(value) : value\n },\n // It's used by the handlebars library to determine if the property is enumerable\n getOwnPropertyDescriptor: (target, prop) => {\n const field = fieldsMap.get(prop as string)\n if (field) {\n return {\n configurable: true,\n enumerable: true,\n }\n }\n return Object.getOwnPropertyDescriptor(target, prop)\n },\n has: (target, prop) => {\n return fieldsMap.has(prop as string) || (target && prop in target)\n },\n ownKeys: (target) => {\n return [...fieldsMap.keys(), ...Object.keys(target || {})]\n },\n })\n}\n\nconst buildRichTextSystem = (baseSystem: string, layout: string) => {\n return `${baseSystem}\n\nRULES:\n- Generate original and unique content based on the given topic.\n- Strictly adhere to the specified layout and formatting instructions.\n- Utilize the provided rich text editor tools for appropriate formatting.\n- Ensure the output follows the structure of the sample output object.\n- Produce valid JSON with no undefined or null values.\n---\nLAYOUT INSTRUCTIONS:\n${layout}\n\n---\nADDITIONAL GUIDELINES:\n- Ensure coherence and logical flow between all sections.\n- Maintain a consistent tone and style throughout the content.\n- Use clear and concise language appropriate for the target audience.\n`\n}\n\nconst assignPrompt = async (\n action: ActionMenuItems,\n {\n type,\n actionParams,\n collection,\n context,\n field,\n layout,\n locale,\n pluginConfig,\n systemPrompt = '',\n template,\n }: {\n actionParams: Record<any, any>\n collection: CollectionSlug\n context: object\n field: string\n layout: string\n locale: string\n pluginConfig: PluginConfig\n systemPrompt: string\n template: string\n type: string\n },\n) => {\n const extendedContext = extendContextWithPromptFields(context, { type, collection }, pluginConfig)\n const prompt = await replacePlaceholders(template, extendedContext)\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' ? buildRichTextSystem(systemPrompt, layout) : undefined,\n }\n\n if (action === 'Compose') {\n if (locale && locale !== 'en') {\n /**\n * NOTE: Avoid using the \"system prompt\" for setting the output language,\n * as it causes quotation marks to appear in the output (Currently only tested with openai models).\n * Appending the language instruction directly to the prompt resolves this issue.\n **/\n assignedPrompts.prompt += `\n --- \n OUTPUT LANGUAGE: ${locale}\n `\n }\n\n return assignedPrompts\n }\n\n const prompts = [...(pluginConfig.prompts || []), ...defaultPrompts]\n const foundPrompt = prompts.find((p) => p.name === action)\n const getLayout = foundPrompt?.layout\n const getSystemPrompt = foundPrompt?.system\n\n let updatedLayout = layout\n if (getLayout) {\n updatedLayout = getLayout()\n }\n\n const system = getSystemPrompt\n ? getSystemPrompt({\n ...(actionParams || {}),\n prompt,\n systemPrompt,\n })\n : ''\n\n return {\n layout: updatedLayout,\n // TODO: revisit this toLexicalHTML\n prompt: await replacePlaceholders(`{{${toLexicalHTML} ${field}}}`, extendedContext),\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, or try again`,\n )\n }\n\n const { defaultLocale, locales = [] } = req.payload.config.localization || {}\n const localeData = locales.find((l) => {\n return l.code === locale\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 locale: locales.length > 0 && locale ? locale : undefined,\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 if (!collection) {\n throw new Error('Collection not found')\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 parts = schemaPath?.split('.') || []\n const collectionName = parts[0]\n const fieldName = parts.length > 1 ? parts[parts.length - 1] : ''\n\n registerEditorHelper(req.payload, schemaPath)\n\n let localeInfo = locale\n if (\n localeData &&\n defaultLocale &&\n localeData.label &&\n typeof localeData.label === 'object' &&\n defaultLocale in localeData.label\n ) {\n localeInfo = localeData.label[defaultLocale]\n }\n\n const models = getGenerationModels(pluginConfig)\n const model =\n models && Array.isArray(models)\n ? models.find((model) => model.id === instructions['model-id'])\n : undefined\n\n if (!model) {\n throw new Error('Model not found')\n }\n\n const settingsName =\n model.settings && 'name' in model.settings ? model.settings.name : undefined\n if (!settingsName) {\n req.payload.logger.error('— AI Plugin: Error fetching settings name!')\n }\n\n const modelOptions = settingsName ? instructions[settingsName] || {} : {}\n\n const prompts = await assignPrompt(action, {\n type: String(instructions['field-type']),\n actionParams,\n collection: collectionName,\n context: contextData,\n field: fieldName || '',\n layout: instructions.layout,\n locale: localeInfo,\n pluginConfig,\n systemPrompt: instructions.system,\n template: String(promptTemplate),\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n { prompts },\n `— AI Plugin: Executing text prompt on ${schemaPath} using ${model.id}`,\n )\n }\n\n // Build per-field JSON schema for structured generation when applicable\n let jsonSchema = allowedEditorSchema\n try {\n \n const targetCollection = req.payload.config.collections.find(\n (c) => c.slug === collectionName,\n )\n\n const targetGlobal = req.payload.config.globals?.find(\n (g) => g.slug === collectionName,\n )\n\n const targetConfig = targetCollection || targetGlobal\n\n if (targetConfig && fieldName) {\n const targetField = getFieldBySchemaPath(targetConfig, schemaPath)\n const supported = [\n 'text',\n 'textarea',\n 'select',\n 'number',\n 'date',\n 'code',\n 'email',\n 'json',\n ]\n\n const t = String(targetField?.type || '')\n if (targetField && supported.includes(t)) {\n jsonSchema = fieldToJsonSchema(targetField as any, { nameOverride: fieldName })\n }\n }\n } catch (e) {\n req.payload.logger.error(e, '— AI Plugin: Error building field JSON schema')\n }\n\n return model.handler?.(prompts.prompt, {\n ...modelOptions,\n layout: prompts.layout,\n locale: localeInfo,\n schema: jsonSchema,\n system: prompts.system,\n })\n } catch (error) {\n req.payload.logger.error(error, 'Error generating content: ')\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as any).message\n : String(error)\n return new Response(JSON.stringify({ error: message }), {\n headers: { 'Content-Type': 'application/json' },\n status:\n message.includes('Authentication required') ||\n message.includes('Insufficient permissions')\n ? 401\n : 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 e,\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: Record<string, any> = { images: [], 'model-id': '', prompt: '' }\n\n if (instructionId) {\n // Get locale from request if available\n const { locale: requestLocale } = data\n const { locales = [] } = req.payload.config.localization || {}\n\n // Verify user has access to the specific instruction\n // Pass locale if localization is enabled for the Instructions collection\n instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n locale: locales.length > 0 && requestLocale ? requestLocale : undefined,\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 extendedContext = extendContextWithPromptFields(\n contextData,\n { type: instructions['field-type'], collection: collectionSlug },\n pluginConfig,\n )\n const text = await replacePlaceholders(promptTemplate, extendedContext)\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 const serverURL =\n req.payload.config?.serverURL ||\n process.env.SERVER_URL ||\n process.env.NEXT_PUBLIC_SERVER_URL\n\n let url = img.image.thumbnailURL || img.image.url\n if (!url.startsWith('http')) {\n url = `${serverURL}${url}`\n }\n\n try {\n const response = await fetch(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,\n })\n } catch (e) {\n req.payload.logger.error(e, `Error fetching reference image ${url}`)\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 modelsUpload = getGenerationModels(pluginConfig)\n const model =\n modelsUpload && Array.isArray(modelsUpload)\n ? modelsUpload.find((model) => model.id === modelId)\n : undefined\n\n if (!model) {\n throw new Error('Model not found')\n }\n\n // @ts-ignore\n const settingsName = model && model.settings ? model.settings.name : undefined\n if (!settingsName) {\n req.payload.logger.error('— AI Plugin: Error fetching settings name!')\n }\n\n let modelOptions = settingsName ? instructions[settingsName] || {} : {}\n modelOptions = {\n ...modelOptions,\n images: editImages,\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n { text },\n `— AI Plugin: Executing image prompt using ${model.id}`,\n )\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, 'Error generating upload: ')\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as any).message\n : String(error)\n return new Response(JSON.stringify({ error: message }), {\n headers: { 'Content-Type': 'application/json' },\n status:\n message.includes('Authentication required') ||\n message.includes('Insufficient permissions')\n ? 401\n : 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","asyncHandlebars","registerEditorHelper","handlebarsHelpersMap","replacePlaceholders","extractImageData","fieldToJsonSchema","getFieldBySchemaPath","getGenerationModels","requireAuthentication","req","user","Error","checkAccess","pluginConfig","access","generate","hasAccess","extendContextWithPromptFields","data","ctx","promptFields","fieldsMap","Map","filter","f","collections","includes","collection","map","name","Proxy","get","target","prop","field","getter","value","Promise","resolve","then","v","SafeString","undefined","getOwnPropertyDescriptor","configurable","enumerable","Object","has","ownKeys","keys","buildRichTextSystem","baseSystem","layout","assignPrompt","action","type","actionParams","context","locale","systemPrompt","template","extendedContext","prompt","toLexicalHTML","toHTML","assignedPrompts","system","prompts","foundPrompt","find","p","getLayout","getSystemPrompt","updatedLayout","endpoints","textarea","handler","json","allowedEditorNodes","options","instructionId","contextData","doc","defaultLocale","locales","payload","config","localization","localeData","l","code","instructions","findByID","id","length","slug","custom","editorConfig","admin","schema","editorSchema","promptTemplate","allowedEditorSchema","schemaPath","parts","split","collectionName","fieldName","localeInfo","label","models","model","Array","isArray","settingsName","settings","logger","error","modelOptions","String","debugging","info","jsonSchema","targetCollection","c","targetGlobal","globals","g","targetConfig","targetField","supported","t","nameOverride","e","message","Response","JSON","stringify","headers","status","method","path","upload","collectionSlug","documentId","docData","draft","images","requestLocale","sampleImages","text","modelId","uploadCollectionSlug","editImages","img","serverURL","env","SERVER_URL","NEXT_PUBLIC_SERVER_URL","url","image","thumbnailURL","startsWith","response","fetch","Authorization","blob","push","size","modelsUpload","result","assetData","mediaUpload","request","create","file","alt"],"mappings":"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"}
|
package/dist/init.js
CHANGED
|
@@ -10,12 +10,19 @@ export const init = async (payload, fieldSchemaPaths, pluginConfig)=>{
|
|
|
10
10
|
payload.logger.info(`— AI Plugin: Initializing...`);
|
|
11
11
|
}
|
|
12
12
|
const paths = Object.keys(fieldSchemaPaths);
|
|
13
|
+
// Note: schema-path is globally unique, so we create one entry per path regardless of localization
|
|
14
|
+
// Localization info is kept for potential future use or debugging
|
|
15
|
+
const _isLocalized = pluginConfig._localization?.enabled && pluginConfig._localization.locales.length > 0;
|
|
16
|
+
const _locales = pluginConfig._localization?.locales || [];
|
|
13
17
|
// Get all instructions for faster initialization
|
|
18
|
+
// Query with locale: 'all' to get entries from all locales when localization is enabled
|
|
14
19
|
const { docs: allInstructions } = await payload.find({
|
|
15
20
|
collection: PLUGIN_INSTRUCTIONS_TABLE,
|
|
16
21
|
depth: 0,
|
|
22
|
+
locale: 'all',
|
|
17
23
|
pagination: false,
|
|
18
24
|
select: {
|
|
25
|
+
id: true,
|
|
19
26
|
'field-type': true,
|
|
20
27
|
'schema-path': true
|
|
21
28
|
}
|
|
@@ -24,6 +31,7 @@ export const init = async (payload, fieldSchemaPaths, pluginConfig)=>{
|
|
|
24
31
|
for(let i = 0; i < paths.length; i++){
|
|
25
32
|
const path = paths[i];
|
|
26
33
|
const { type: fieldType, label: fieldLabel, relationTo } = fieldSchemaPaths[path];
|
|
34
|
+
// Find existing entry for this path (schema-path is globally unique, not per locale)
|
|
27
35
|
let instructions = allInstructions.find((entry)=>entry['schema-path'] === path);
|
|
28
36
|
if (!instructions) {
|
|
29
37
|
let seed;
|
|
@@ -71,12 +79,44 @@ export const init = async (payload, fieldSchemaPaths, pluginConfig)=>{
|
|
|
71
79
|
prompt: generatedPrompt,
|
|
72
80
|
...seed.data
|
|
73
81
|
}, `Prompt seeded for "${path}" field`);
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
})
|
|
82
|
+
try {
|
|
83
|
+
instructions = await payload.create({
|
|
84
|
+
collection: PLUGIN_INSTRUCTIONS_TABLE,
|
|
85
|
+
data
|
|
86
|
+
});
|
|
87
|
+
} catch (err) {
|
|
88
|
+
// Handle unique constraint violation - entry might already exist for another locale
|
|
89
|
+
const error = err;
|
|
90
|
+
if (error?.name === 'ValidationError' && error?.data?.errors?.some((e)=>e.path === 'schema-path')) {
|
|
91
|
+
// Try to find the existing entry across all locales
|
|
92
|
+
const { docs } = await payload.find({
|
|
93
|
+
collection: PLUGIN_INSTRUCTIONS_TABLE,
|
|
94
|
+
limit: 1,
|
|
95
|
+
locale: 'all',
|
|
96
|
+
select: {
|
|
97
|
+
id: true,
|
|
98
|
+
'field-type': true,
|
|
99
|
+
'schema-path': true
|
|
100
|
+
},
|
|
101
|
+
where: {
|
|
102
|
+
'schema-path': {
|
|
103
|
+
equals: path
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
const existingEntry = docs[0];
|
|
108
|
+
if (existingEntry) {
|
|
109
|
+
instructions = existingEntry;
|
|
110
|
+
if (pluginConfig.debugging) {
|
|
111
|
+
payload.logger.info(`— AI Plugin: Entry already exists for ${path}, using existing entry`);
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
payload.logger.error(err, `— AI Plugin: Error creating Compose settings for ${path}`);
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
payload.logger.error(err, `— AI Plugin: Error creating Compose settings for ${path}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
80
120
|
if (instructions?.id) {
|
|
81
121
|
fieldInstructionsMap[path] = {
|
|
82
122
|
id: instructions.id,
|
|
@@ -85,7 +125,8 @@ export const init = async (payload, fieldSchemaPaths, pluginConfig)=>{
|
|
|
85
125
|
}
|
|
86
126
|
} else {
|
|
87
127
|
if (instructions['field-type'] !== fieldType) {
|
|
88
|
-
|
|
128
|
+
const currentFieldType = instructions['field-type'];
|
|
129
|
+
payload.logger.warn(`— AI Plugin: Field type mismatch for ${path}! Was "${fieldType}", it is "${currentFieldType}" now. Updating...`);
|
|
89
130
|
await payload.update({
|
|
90
131
|
id: instructions.id,
|
|
91
132
|
collection: PLUGIN_INSTRUCTIONS_TABLE,
|
package/dist/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/init.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\nimport type { PluginConfig } from './types.js'\n\nimport { defaultSeedPrompts } from './ai/prompts.js'\nimport { systemGenerate } from './ai/utils/systemGenerate.js'\nimport { PLUGIN_INSTRUCTIONS_TABLE } from './defaults.js'\nimport { getGenerationModels } from './utilities/getGenerationModels.js'\n\nexport const init = async (\n payload: Payload,\n fieldSchemaPaths: Record<string, { label: string; relationTo?: string; type: string }>,\n pluginConfig: PluginConfig,\n) => {\n if (!pluginConfig.generatePromptOnInit) {\n return\n }\n\n if (pluginConfig.debugging) {\n payload.logger.info(`— AI Plugin: Initializing...`)\n }\n\n const paths = Object.keys(fieldSchemaPaths)\n\n // Get all instructions for faster initialization\n const { docs: allInstructions } = await payload.find({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n depth: 0,\n pagination: false,\n select: {\n 'field-type': true,\n 'schema-path': true,\n },\n })\n\n const fieldInstructionsMap: Record<string, { fieldType: any; id: any }> = {}\n\n for (let i = 0; i < paths.length; i++) {\n const path = paths[i]\n const { type: fieldType, label: fieldLabel, relationTo } = fieldSchemaPaths[path]\n let instructions = allInstructions.find((entry) => entry['schema-path'] === path)\n\n if (!instructions) {\n let seed\n const seedOptions = {\n fieldLabel,\n fieldSchemaPaths,\n fieldType,\n path,\n }\n\n if (pluginConfig.seedPrompts) {seed = await pluginConfig.seedPrompts(seedOptions)}\n if (seed === undefined) {seed = await defaultSeedPrompts(seedOptions)}\n // Field should be ignored\n if (!seed) {\n if (pluginConfig.debugging) {\n payload.logger.info(`— AI Plugin: No seed prompt for ${path}, ignoring...`)\n }\n continue\n }\n\n let generatedPrompt = '{{ title }}'\n if ('prompt' in seed) {\n // find the model that has the generateText function\n const models = getGenerationModels(pluginConfig)\n const model =\n models && Array.isArray(models) ? models.find((model) => model.generateText) : undefined\n generatedPrompt = await systemGenerate(\n {\n prompt: seed.prompt,\n system: seed.system,\n },\n model?.generateText,\n )\n }\n\n const modelsForId = getGenerationModels(pluginConfig)\n const modelForId =\n modelsForId && Array.isArray(modelsForId)\n ? modelsForId.find((a) => a.fields.includes(fieldType))\n : undefined\n\n const data = {\n 'model-id': modelForId?.id,\n prompt: generatedPrompt,\n ...seed.data, // allow to override data, but not the one below\n 'field-type': fieldType,\n 'relation-to': relationTo,\n 'schema-path': path,\n }\n\n payload.logger.info(\n {\n 'model-id': data['model-id'],\n prompt: generatedPrompt,\n ...seed.data,\n },\n `Prompt seeded for \"${path}\" field`,\n )\n\n instructions = (await payload\n .create({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n data,\n })\n .catch((err) => {\n payload.logger.error(err, '— AI Plugin: Error creating Compose settings-')\n })) as (typeof allInstructions)[0]\n\n if (instructions?.id) {\n fieldInstructionsMap[path] = {\n id: instructions.id,\n fieldType,\n }\n }\n } else {\n if (instructions['field-type'] !== fieldType) {\n payload.logger.warn(\n `— AI Plugin: Field type mismatch for ${path}! Was \"${fieldType}\", it is \"${instructions['field-type']}\" now. Updating...`,\n )\n await payload.update({\n id: instructions.id,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n data: {\n 'field-type': fieldType,\n },\n })\n instructions['field-type'] = fieldType\n }\n\n fieldInstructionsMap[path] = {\n id: instructions.id,\n fieldType,\n }\n }\n }\n\n if (pluginConfig.debugging) {\n payload.logger.info(\n `— AI Plugin: Enabled fields map: ${JSON.stringify(fieldInstructionsMap, null, 2)}`,\n )\n payload.logger.info(`— AI Plugin: Initialized!`)\n }\n\n if (pluginConfig.generatePromptOnInit) {\n payload.logger.info(\n '\\n\\n-AI Plugin: Example prompts are added to get you started, Now go break some code 🚀🚀🚀\\n\\n',\n )\n }\n}\n"],"names":["defaultSeedPrompts","systemGenerate","PLUGIN_INSTRUCTIONS_TABLE","getGenerationModels","init","payload","fieldSchemaPaths","pluginConfig","generatePromptOnInit","debugging","logger","info","paths","Object","keys","docs","allInstructions","find","collection","depth","pagination","select","fieldInstructionsMap","i","length","path","type","fieldType","label","fieldLabel","relationTo","instructions","entry","seed","seedOptions","seedPrompts","undefined","generatedPrompt","models","model","Array","isArray","generateText","prompt","system","modelsForId","modelForId","a","fields","includes","data","id","create","catch","err","error","warn","update","JSON","stringify"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/init.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\nimport type { PluginConfig } from './types.js'\n\nimport { defaultSeedPrompts } from './ai/prompts.js'\nimport { systemGenerate } from './ai/utils/systemGenerate.js'\nimport { PLUGIN_INSTRUCTIONS_TABLE } from './defaults.js'\nimport { getGenerationModels } from './utilities/getGenerationModels.js'\n\nexport const init = async (\n payload: Payload,\n fieldSchemaPaths: Record<string, { label: string; relationTo?: string; type: string }>,\n pluginConfig: PluginConfig,\n) => {\n if (!pluginConfig.generatePromptOnInit) {\n return\n }\n\n if (pluginConfig.debugging) {\n payload.logger.info(`— AI Plugin: Initializing...`)\n }\n\n const paths = Object.keys(fieldSchemaPaths)\n\n // Note: schema-path is globally unique, so we create one entry per path regardless of localization\n // Localization info is kept for potential future use or debugging\n const _isLocalized =\n pluginConfig._localization?.enabled && pluginConfig._localization.locales.length > 0\n const _locales = pluginConfig._localization?.locales || []\n\n // Get all instructions for faster initialization\n // Query with locale: 'all' to get entries from all locales when localization is enabled\n const { docs: allInstructions } = await payload.find({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n depth: 0,\n locale: 'all',\n pagination: false,\n select: {\n id: true,\n 'field-type': true,\n 'schema-path': true,\n },\n })\n\n const fieldInstructionsMap: Record<string, { fieldType: string; id: number | string }> = {}\n\n type InstructionDoc = (typeof allInstructions)[0]\n\n for (let i = 0; i < paths.length; i++) {\n const path = paths[i]\n const { type: fieldType, label: fieldLabel, relationTo } = fieldSchemaPaths[path]\n // Find existing entry for this path (schema-path is globally unique, not per locale)\n let instructions: InstructionDoc | undefined = allInstructions.find(\n (entry) => entry['schema-path'] === path,\n )\n\n if (!instructions) {\n let seed\n const seedOptions = {\n fieldLabel,\n fieldSchemaPaths,\n fieldType,\n path,\n }\n\n if (pluginConfig.seedPrompts) {\n seed = await pluginConfig.seedPrompts(seedOptions)\n }\n if (seed === undefined) {\n seed = await defaultSeedPrompts(seedOptions)\n }\n // Field should be ignored\n if (!seed) {\n if (pluginConfig.debugging) {\n payload.logger.info(`— AI Plugin: No seed prompt for ${path}, ignoring...`)\n }\n continue\n }\n\n let generatedPrompt = '{{ title }}'\n if ('prompt' in seed) {\n // find the model that has the generateText function\n const models = getGenerationModels(pluginConfig)\n const model =\n models && Array.isArray(models) ? models.find((model) => model.generateText) : undefined\n generatedPrompt = await systemGenerate(\n {\n prompt: seed.prompt,\n system: seed.system,\n },\n model?.generateText,\n )\n }\n\n const modelsForId = getGenerationModels(pluginConfig)\n const modelForId =\n modelsForId && Array.isArray(modelsForId)\n ? modelsForId.find((a) => a.fields.includes(fieldType))\n : undefined\n\n const data = {\n 'model-id': modelForId?.id,\n prompt: generatedPrompt,\n ...seed.data, // allow to override data, but not the one below\n 'field-type': fieldType,\n 'relation-to': relationTo,\n 'schema-path': path,\n }\n\n payload.logger.info(\n {\n 'model-id': data['model-id'],\n prompt: generatedPrompt,\n ...seed.data,\n },\n `Prompt seeded for \"${path}\" field`,\n )\n\n try {\n instructions = (await payload.create({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n data,\n })) as InstructionDoc\n } catch (err: unknown) {\n // Handle unique constraint violation - entry might already exist for another locale\n const error = err as { data?: { errors?: Array<{ path?: string }> }; name?: string }\n if (\n error?.name === 'ValidationError' &&\n error?.data?.errors?.some((e) => e.path === 'schema-path')\n ) {\n // Try to find the existing entry across all locales\n const { docs } = await payload.find({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n limit: 1,\n locale: 'all',\n select: {\n id: true,\n 'field-type': true,\n 'schema-path': true,\n },\n where: {\n 'schema-path': {\n equals: path,\n },\n },\n })\n\n const existingEntry = docs[0] as InstructionDoc | undefined\n if (existingEntry) {\n instructions = existingEntry\n if (pluginConfig.debugging) {\n payload.logger.info(\n `— AI Plugin: Entry already exists for ${path}, using existing entry`,\n )\n }\n } else {\n payload.logger.error(err, `— AI Plugin: Error creating Compose settings for ${path}`)\n }\n } else {\n payload.logger.error(err, `— AI Plugin: Error creating Compose settings for ${path}`)\n }\n }\n\n if (instructions?.id) {\n fieldInstructionsMap[path] = {\n id: instructions.id,\n fieldType,\n }\n }\n } else {\n if (instructions['field-type'] !== fieldType) {\n const currentFieldType = instructions['field-type'] as string\n payload.logger.warn(\n `— AI Plugin: Field type mismatch for ${path}! Was \"${fieldType}\", it is \"${currentFieldType}\" now. Updating...`,\n )\n await payload.update({\n id: instructions.id,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n data: {\n 'field-type': fieldType,\n },\n })\n instructions['field-type'] = fieldType\n }\n\n fieldInstructionsMap[path] = {\n id: instructions.id,\n fieldType,\n }\n }\n }\n\n if (pluginConfig.debugging) {\n payload.logger.info(\n `— AI Plugin: Enabled fields map: ${JSON.stringify(fieldInstructionsMap, null, 2)}`,\n )\n payload.logger.info(`— AI Plugin: Initialized!`)\n }\n\n if (pluginConfig.generatePromptOnInit) {\n payload.logger.info(\n '\\n\\n-AI Plugin: Example prompts are added to get you started, Now go break some code 🚀🚀🚀\\n\\n',\n )\n }\n}\n"],"names":["defaultSeedPrompts","systemGenerate","PLUGIN_INSTRUCTIONS_TABLE","getGenerationModels","init","payload","fieldSchemaPaths","pluginConfig","generatePromptOnInit","debugging","logger","info","paths","Object","keys","_isLocalized","_localization","enabled","locales","length","_locales","docs","allInstructions","find","collection","depth","locale","pagination","select","id","fieldInstructionsMap","i","path","type","fieldType","label","fieldLabel","relationTo","instructions","entry","seed","seedOptions","seedPrompts","undefined","generatedPrompt","models","model","Array","isArray","generateText","prompt","system","modelsForId","modelForId","a","fields","includes","data","create","err","error","name","errors","some","e","limit","where","equals","existingEntry","currentFieldType","warn","update","JSON","stringify"],"mappings":"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"}
|
package/dist/plugin.js
CHANGED
|
@@ -53,10 +53,36 @@ const securityMessage = `
|
|
|
53
53
|
║ them explicitly in your plugin configuration. ║
|
|
54
54
|
╚═══════════════════════════════════════════════════════════════╝
|
|
55
55
|
`;
|
|
56
|
+
const isLocalizationEnabled = (config)=>{
|
|
57
|
+
return config !== false && typeof config === 'object' && config !== null && 'locales' in config && Array.isArray(config.locales) && config.locales.length > 0;
|
|
58
|
+
};
|
|
59
|
+
const extractLocales = (config)=>{
|
|
60
|
+
if (config && typeof config === 'object' && 'locales' in config && Array.isArray(config.locales)) {
|
|
61
|
+
return {
|
|
62
|
+
defaultLocale: 'defaultLocale' in config && typeof config.defaultLocale === 'string' ? config.defaultLocale : undefined,
|
|
63
|
+
locales: config.locales.map((locale)=>typeof locale === 'string' ? locale : locale.code)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
locales: []
|
|
68
|
+
};
|
|
69
|
+
};
|
|
56
70
|
const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
71
|
+
const localizationConfig = incomingConfig.localization;
|
|
72
|
+
const hasLocalization = isLocalizationEnabled(localizationConfig);
|
|
73
|
+
const localizationData = hasLocalization ? extractLocales(localizationConfig) : {
|
|
74
|
+
locales: []
|
|
75
|
+
};
|
|
57
76
|
pluginConfig = {
|
|
58
77
|
...defaultPluginConfig,
|
|
59
78
|
...pluginConfig,
|
|
79
|
+
_localization: hasLocalization ? {
|
|
80
|
+
enabled: true,
|
|
81
|
+
...localizationData
|
|
82
|
+
} : {
|
|
83
|
+
enabled: false,
|
|
84
|
+
locales: []
|
|
85
|
+
},
|
|
60
86
|
access: {
|
|
61
87
|
...defaultPluginConfig.access,
|
|
62
88
|
...pluginConfig.access
|
|
@@ -67,7 +93,7 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
67
93
|
let updatedConfig = {
|
|
68
94
|
...incomingConfig
|
|
69
95
|
};
|
|
70
|
-
|
|
96
|
+
const collectionsFieldPathMap = {};
|
|
71
97
|
if (isActivated) {
|
|
72
98
|
const Instructions = instructionsCollection(pluginConfig);
|
|
73
99
|
// Inject editor schema to config, so that it can be accessed when /textarea endpoint will hit
|
|
@@ -110,19 +136,17 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
110
136
|
}
|
|
111
137
|
};
|
|
112
138
|
const pluginEndpoints = endpoints(pluginConfig);
|
|
139
|
+
const processedCollections = collections.map((collection)=>{
|
|
140
|
+
if (collectionSlugs[collection.slug]) {
|
|
141
|
+
const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(collection);
|
|
142
|
+
Object.assign(collectionsFieldPathMap, schemaPathMap);
|
|
143
|
+
return updatedCollectionConfig;
|
|
144
|
+
}
|
|
145
|
+
return collection;
|
|
146
|
+
});
|
|
113
147
|
updatedConfig = {
|
|
114
148
|
...incomingConfig,
|
|
115
|
-
collections:
|
|
116
|
-
if (collectionSlugs[collection.slug]) {
|
|
117
|
-
const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(collection);
|
|
118
|
-
collectionsFieldPathMap = {
|
|
119
|
-
...collectionsFieldPathMap,
|
|
120
|
-
...schemaPathMap
|
|
121
|
-
};
|
|
122
|
-
return updatedCollectionConfig;
|
|
123
|
-
}
|
|
124
|
-
return collection;
|
|
125
|
-
}),
|
|
149
|
+
collections: processedCollections,
|
|
126
150
|
endpoints: [
|
|
127
151
|
...incomingConfig.endpoints ?? [],
|
|
128
152
|
pluginEndpoints.textarea,
|
|
@@ -130,12 +154,9 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
130
154
|
fetchFields(pluginConfig)
|
|
131
155
|
],
|
|
132
156
|
globals: globals.map((global)=>{
|
|
133
|
-
if (globalsSlugs
|
|
157
|
+
if (globalsSlugs?.[global.slug]) {
|
|
134
158
|
const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(global);
|
|
135
|
-
collectionsFieldPathMap
|
|
136
|
-
...collectionsFieldPathMap,
|
|
137
|
-
...schemaPathMap
|
|
138
|
-
};
|
|
159
|
+
Object.assign(collectionsFieldPathMap, schemaPathMap);
|
|
139
160
|
return updatedCollectionConfig;
|
|
140
161
|
}
|
|
141
162
|
return global;
|
|
@@ -149,7 +170,9 @@ const payloadAiPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
149
170
|
};
|
|
150
171
|
}
|
|
151
172
|
updatedConfig.onInit = async (payload)=>{
|
|
152
|
-
if (incomingConfig.onInit)
|
|
173
|
+
if (incomingConfig.onInit) {
|
|
174
|
+
await incomingConfig.onInit(payload);
|
|
175
|
+
}
|
|
153
176
|
if (!isActivated) {
|
|
154
177
|
payload.logger.warn(`— AI Plugin: Not activated. Please verify your environment keys.`);
|
|
155
178
|
return;
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 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 Instructions.admin = {\n ...Instructions.admin,\n }\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),\n ],\n globals: globals.map((global) => {\n if (globalsSlugs && 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 payload.logger.error(error, `— AI Plugin: Initialization Error`)\n })\n .finally(() => {\n if (!pluginConfig.disableSponsorMessage) {\n setTimeout(() => {\n payload.logger.info(securityMessage)\n }, 1000)\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","access","generate","req","user","settings","collections","disableSponsorMessage","generatePromptOnInit","generationModels","sponsorMessage","securityMessage","payloadAiPlugin","pluginConfig","incomingConfig","isActivated","updatedConfig","collectionsFieldPathMap","Instructions","lexicalSchema","editorConfig","nodes","admin","debugging","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","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 isLocalizationEnabled = (config: Config['localization']) => {\n return (\n config !== false &&\n typeof config === 'object' &&\n config !== null &&\n 'locales' in config &&\n Array.isArray(config.locales) &&\n config.locales.length > 0\n )\n}\n\nconst extractLocales = (\n config: Config['localization'],\n): { defaultLocale?: string; locales: string[] } => {\n if (\n config &&\n typeof config === 'object' &&\n 'locales' in config &&\n Array.isArray(config.locales)\n ) {\n return {\n defaultLocale:\n 'defaultLocale' in config && typeof config.defaultLocale === 'string'\n ? config.defaultLocale\n : undefined,\n locales: config.locales.map((locale) =>\n typeof locale === 'string' ? locale : (locale as { code: string }).code,\n ),\n }\n }\n return { locales: [] }\n}\n\nconst payloadAiPlugin =\n (pluginConfig: PluginConfig) =>\n (incomingConfig: Config): Config => {\n const localizationConfig = incomingConfig.localization\n const hasLocalization = isLocalizationEnabled(localizationConfig)\n const localizationData = hasLocalization ? extractLocales(localizationConfig) : { locales: [] }\n\n pluginConfig = {\n ...defaultPluginConfig,\n ...pluginConfig,\n _localization: hasLocalization\n ? {\n enabled: true,\n ...localizationData,\n }\n : {\n enabled: false,\n locales: [],\n },\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 const collectionsFieldPathMap: Record<\n string,\n { label: string; relationTo?: string; type: string }\n > = {}\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 Instructions.admin = {\n ...Instructions.admin,\n }\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\n const processedCollections = collections.map((collection) => {\n if (collectionSlugs[collection.slug]) {\n const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(collection)\n Object.assign(collectionsFieldPathMap, schemaPathMap)\n return updatedCollectionConfig as CollectionConfig\n }\n return collection\n })\n\n updatedConfig = {\n ...incomingConfig,\n collections: processedCollections,\n endpoints: [\n ...(incomingConfig.endpoints ?? []),\n pluginEndpoints.textarea,\n pluginEndpoints.upload,\n fetchFields(pluginConfig),\n ],\n globals: globals.map((global) => {\n if (globalsSlugs?.[global.slug]) {\n const { schemaPathMap, updatedCollectionConfig } = updateFieldsConfig(global)\n Object.assign(collectionsFieldPathMap, schemaPathMap)\n return updatedCollectionConfig as GlobalConfig\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) {\n await incomingConfig.onInit(payload)\n }\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 payload.logger.error(error, `— AI Plugin: Initialization Error`)\n })\n .finally(() => {\n if (!pluginConfig.disableSponsorMessage) {\n setTimeout(() => {\n payload.logger.info(securityMessage)\n }, 1000)\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","access","generate","req","user","settings","collections","disableSponsorMessage","generatePromptOnInit","generationModels","sponsorMessage","securityMessage","isLocalizationEnabled","config","Array","isArray","locales","length","extractLocales","defaultLocale","undefined","map","locale","code","payloadAiPlugin","pluginConfig","incomingConfig","localizationConfig","localization","hasLocalization","localizationData","_localization","enabled","isActivated","updatedConfig","collectionsFieldPathMap","Instructions","lexicalSchema","editorConfig","nodes","admin","debugging","hidden","custom","schema","globals","collectionSlugs","globalsSlugs","components","providers","updatedProviders","path","pluginEndpoints","processedCollections","collection","slug","schemaPathMap","updatedCollectionConfig","Object","assign","textarea","upload","global","i18n","onInit","payload","logger","warn","catch","error","finally","setTimeout","info"],"mappings":"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"}
|
|
@@ -4,6 +4,9 @@ import { useContext, useEffect, useMemo, useState } from 'react';
|
|
|
4
4
|
import { PLUGIN_INSTRUCTIONS_TABLE } from '../../defaults.js';
|
|
5
5
|
import { handlebarsHelpers, handlebarsHelpersMap } from '../../libraries/handlebars/helpersMap.js';
|
|
6
6
|
const warnedOnceOnNoInstructionId = new Set();
|
|
7
|
+
const normalizePath = (path)=>{
|
|
8
|
+
return path.replace(/\._index-\d+-\d+/g, '');
|
|
9
|
+
};
|
|
7
10
|
const warnOnceOnMissingInstructions = (path)=>{
|
|
8
11
|
if (!warnedOnceOnNoInstructionId.has(path)) {
|
|
9
12
|
warnedOnceOnNoInstructionId.add(path);
|
|
@@ -14,7 +17,7 @@ const warnOnceOnMissingInstructions = (path)=>{
|
|
|
14
17
|
export const useInstructions = (update = {})=>{
|
|
15
18
|
const context = useContext(InstructionsContext);
|
|
16
19
|
const { collectionSlug } = useDocumentInfo();
|
|
17
|
-
const { activeCollection, hasInstructions, instructions, promptFields, setActiveCollection
|
|
20
|
+
const { activeCollection, debugging, hasInstructions, instructions, promptFields, setActiveCollection } = context;
|
|
18
21
|
const [schemaPath, setSchemaPath] = useState(update.schemaPath);
|
|
19
22
|
useEffect(()=>{
|
|
20
23
|
if (update.schemaPath !== schemaPath) {
|
|
@@ -84,7 +87,8 @@ export const useInstructions = (update = {})=>{
|
|
|
84
87
|
instructions,
|
|
85
88
|
promptFields
|
|
86
89
|
]);
|
|
87
|
-
const
|
|
90
|
+
const normalizedPath = schemaPath ? normalizePath(schemaPath) : '';
|
|
91
|
+
const pathInstructions = instructions[normalizedPath];
|
|
88
92
|
if (debugging && !pathInstructions && schemaPath && hasInstructions) {
|
|
89
93
|
warnOnceOnMissingInstructions(schemaPath);
|
|
90
94
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/InstructionsProvider/useInstructions.ts"],"sourcesContent":["import { InstructionsContext } from '@ai-stack/payloadcms/client'\nimport { useDocumentInfo } from '@payloadcms/ui'\nimport { useContext, useEffect, useMemo, useState } from 'react'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../../defaults.js'\nimport { handlebarsHelpers, handlebarsHelpersMap } from '../../libraries/handlebars/helpersMap.js'\n\
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/InstructionsProvider/useInstructions.ts"],"sourcesContent":["import { InstructionsContext } from '@ai-stack/payloadcms/client'\nimport { useDocumentInfo } from '@payloadcms/ui'\nimport { useContext, useEffect, useMemo, useState } from 'react'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../../defaults.js'\nimport { handlebarsHelpers, handlebarsHelpersMap } from '../../libraries/handlebars/helpersMap.js'\n\nconst warnedOnceOnNoInstructionId = new Set<string>()\n\nconst normalizePath = (path: string): string => {\n return path.replace(/\\._index-\\d+-\\d+/g, '')\n}\n\nconst warnOnceOnMissingInstructions = (path: string) => {\n if (!warnedOnceOnNoInstructionId.has(path)) {\n warnedOnceOnNoInstructionId.add(path)\n // eslint-disable-next-line no-console\n console.info(`[AI Plugin] There are no AI instructions for this field: ${path}. Enable \"generatePromptOnInit\" option to enable them.`)\n }\n}\n\nexport const useInstructions = (\n update: {\n schemaPath?: unknown\n } = {},\n) => {\n const context = useContext(InstructionsContext)\n const { collectionSlug } = useDocumentInfo()\n const { activeCollection, debugging, hasInstructions, instructions, promptFields, setActiveCollection } = context\n\n const [schemaPath, setSchemaPath] = useState(update.schemaPath as string)\n\n useEffect(() => {\n if (update.schemaPath !== schemaPath) {\n setSchemaPath((update.schemaPath as string) ?? '')\n }\n }, [update.schemaPath])\n\n useEffect(() => {\n if (\n activeCollection !== collectionSlug &&\n collectionSlug !== PLUGIN_INSTRUCTIONS_TABLE &&\n typeof setActiveCollection === 'function'\n ) {\n setActiveCollection(collectionSlug ?? '')\n }\n }, [activeCollection, collectionSlug, setActiveCollection])\n\n const groupedFields = useMemo(() => {\n const result: Record<string, string[]> = {}\n for (const fullKey of Object.keys(instructions || {})) {\n const [collection, ...pathParts] = fullKey.split('.')\n const path = pathParts.join('.')\n if (!result[collection]) {\n result[collection] = []\n }\n result[collection].push(path)\n }\n return result\n }, [instructions])\n\n // Suggestions for prompt editor\n const promptEditorSuggestions = useMemo(() => {\n const activeFields = groupedFields[activeCollection as string] || []\n const suggestions: string[] = []\n\n activeFields.forEach((f) => {\n const fieldKey = Object.keys(instructions).find((k) => k.endsWith(f))\n const fieldInfo = fieldKey ? instructions[fieldKey] : undefined\n if (!fieldInfo) { return }\n\n if (fieldInfo.fieldType === 'upload') {\n suggestions.push(`${f}.url`)\n return\n }\n\n const helpers = handlebarsHelpers.filter(\n (h) => (handlebarsHelpersMap as Record<string, any>)[h]?.field === fieldInfo.fieldType,\n )\n\n if (helpers.length) {\n for (const helper of helpers) {\n suggestions.push(`${helper} ${f}`)\n }\n } else {\n suggestions.push(f)\n }\n }, [])\n\n promptFields.forEach(({ name, collections }) => {\n if (!activeCollection) { return }\n if (!collections || collections.includes(activeCollection)) {\n suggestions.push(name)\n }\n })\n\n return suggestions\n }, [groupedFields, activeCollection, instructions, promptFields])\n\n const normalizedPath = schemaPath ? normalizePath(schemaPath) : ''\n const pathInstructions = instructions[normalizedPath]\n\n if (debugging && !pathInstructions && schemaPath && hasInstructions) {\n warnOnceOnMissingInstructions(schemaPath)\n }\n\n return {\n ...context,\n ...(pathInstructions || {}),\n promptEditorSuggestions,\n }\n}"],"names":["InstructionsContext","useDocumentInfo","useContext","useEffect","useMemo","useState","PLUGIN_INSTRUCTIONS_TABLE","handlebarsHelpers","handlebarsHelpersMap","warnedOnceOnNoInstructionId","Set","normalizePath","path","replace","warnOnceOnMissingInstructions","has","add","console","info","useInstructions","update","context","collectionSlug","activeCollection","debugging","hasInstructions","instructions","promptFields","setActiveCollection","schemaPath","setSchemaPath","groupedFields","result","fullKey","Object","keys","collection","pathParts","split","join","push","promptEditorSuggestions","activeFields","suggestions","forEach","f","fieldKey","find","k","endsWith","fieldInfo","undefined","fieldType","helpers","filter","h","field","length","helper","name","collections","includes","normalizedPath","pathInstructions"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { JSONSchema } from 'openai/lib/jsonschema';
|
|
|
2
2
|
import type { ImageGenerateParams } from 'openai/resources/images';
|
|
3
3
|
import type { CollectionConfig, CollectionSlug, DataFromCollectionSlug, Endpoint, Field, File, GlobalConfig, GroupField, PayloadRequest, TypedCollection } from 'payload';
|
|
4
4
|
import type { CSSProperties, MouseEventHandler } from 'react';
|
|
5
|
-
import type { PLUGIN_INSTRUCTIONS_TABLE } from
|
|
5
|
+
import type { PLUGIN_INSTRUCTIONS_TABLE } from './defaults.js';
|
|
6
6
|
export interface PluginConfigAccess {
|
|
7
7
|
/**
|
|
8
8
|
* Control access to AI generation features (generate text, images, audio)
|
|
@@ -36,6 +36,16 @@ export type PluginConfigMediaUploadFunction = (result: {
|
|
|
36
36
|
request: PayloadRequest;
|
|
37
37
|
}) => Promise<DataFromCollectionSlug<CollectionSlug>>;
|
|
38
38
|
export interface PluginConfig {
|
|
39
|
+
/**
|
|
40
|
+
* Localization configuration for Instructions collection
|
|
41
|
+
* Automatically populated from Payload config if localization is enabled
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
_localization?: {
|
|
45
|
+
defaultLocale?: string;
|
|
46
|
+
enabled: boolean;
|
|
47
|
+
locales: string[];
|
|
48
|
+
};
|
|
39
49
|
/**
|
|
40
50
|
* Access control configuration for AI features
|
|
41
51
|
* By default, all AI features require authentication
|
|
@@ -70,7 +80,7 @@ export interface PluginConfig {
|
|
|
70
80
|
* Custom seed prompt function for generating field-specific prompts
|
|
71
81
|
* If not provided, uses default seed prompt function
|
|
72
82
|
* You can access default seed prompts by importing { defaultSeedPrompts } from '@ai-stack/payloadcms'
|
|
73
|
-
|
|
83
|
+
*/
|
|
74
84
|
seedPrompts?: SeedPromptFunction;
|
|
75
85
|
uploadCollectionSlug?: CollectionSlug;
|
|
76
86
|
}
|
|
@@ -159,7 +169,7 @@ export type GenerateImageParams = {
|
|
|
159
169
|
version?: ImageGenerateParams['model'];
|
|
160
170
|
};
|
|
161
171
|
export type SerializedPromptField = {
|
|
162
|
-
collections?:
|
|
172
|
+
collections?: CollectionSlug[];
|
|
163
173
|
name: string;
|
|
164
174
|
};
|
|
165
175
|
export type PromptFieldGetterContext = {
|
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 {\n CollectionConfig,\n CollectionSlug,\n DataFromCollectionSlug,\n Endpoint,\n Field,\n File,\n GlobalConfig,\n GroupField,\n PayloadRequest,\n TypedCollection,\n} from 'payload'\nimport type { CSSProperties, MouseEventHandler } from 'react'\n\nimport type {PLUGIN_INSTRUCTIONS_TABLE} from
|
|
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 CollectionConfig,\n CollectionSlug,\n DataFromCollectionSlug,\n Endpoint,\n Field,\n File,\n GlobalConfig,\n GroupField,\n PayloadRequest,\n TypedCollection,\n} from 'payload'\nimport type { CSSProperties, MouseEventHandler } from 'react'\n\nimport type { PLUGIN_INSTRUCTIONS_TABLE } from './defaults.js'\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 }) => boolean | Promise<boolean>\n /**\n * Control access to AI settings/configuration\n * @default () => !!req.user (requires authentication)\n */\n settings?: ({ req }: { req: PayloadRequest }) => boolean | Promise<boolean>\n}\n\nexport interface PluginOptions {\n /**\n * Provide local tags to filter language options from the Translate Menu\n * Check for the available local tags,\n * visit: https://www.npmjs.com/package/locale-codes\n * Example: [\"en-US\", \"zh-SG\", \"zh-CN\", \"en\"]\n */\n enabledLanguages?: string[]\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 * Localization configuration for Instructions collection\n * Automatically populated from Payload config if localization is enabled\n * @internal\n */\n _localization?: {\n defaultLocale?: string\n enabled: boolean\n locales: string[]\n }\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 options?: PluginOptions\n // Override the instructions collection config\n overrideInstructions?: Partial<CollectionConfig>\n promptFields?: PromptField[]\n /**\n * Custom action prompts for AI text generation\n * If not provided, uses default prompts\n * You can access default prompts by importing { defaultPrompts } from '@ai-stack/payloadcms'\n */\n prompts?: ActionPrompt[]\n /**\n * Custom seed prompt function for generating field-specific prompts\n * If not provided, uses default seed prompt function\n * You can access default seed prompts by importing { defaultSeedPrompts } from '@ai-stack/payloadcms'\n */\n seedPrompts?: SeedPromptFunction\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 ActionPromptOptions = {\n layout?: string\n locale?: string\n prompt?: string\n systemPrompt?: string\n}\n\nexport type ActionPrompt = {\n layout?: (options?: ActionPromptOptions) => string\n name: ActionMenuItems\n system: (options: ActionPromptOptions) => string\n}\n\nexport type SeedPromptOptions = {\n fieldLabel: string\n fieldSchemaPaths: Record<string, any>\n fieldType: string\n path: string\n}\n\nexport type SeedPromptData = Omit<\n TypedCollection[typeof PLUGIN_INSTRUCTIONS_TABLE],\n 'createdAt' | 'id' | 'updatedAt'\n>\n\nexport type SeedPromptResult =\n | {\n data?: SeedPromptData\n }\n | {\n data?: SeedPromptData\n prompt: string\n system: string\n }\n | false\n | undefined\n | void\n\nexport type SeedPromptFunction = (\n options: SeedPromptOptions,\n) => Promise<SeedPromptResult> | SeedPromptResult\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\nexport type SerializedPromptField = {\n collections?: CollectionSlug[]\n name: string\n}\n\nexport type PromptFieldGetterContext = {\n collection: CollectionSlug\n type: string\n}\n\nexport type PromptField = {\n // If not provided, the value will be returned from the data object as-is\n getter?: (data: object, ctx: PromptFieldGetterContext) => Promise<string> | string\n} & SerializedPromptField\n"],"names":[],"mappings":"AAgPA,WAGyB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
type AnyCollectionConfig =
|
|
1
|
+
import type { Field, GlobalConfig, CollectionConfig, ClientGlobalConfig, ClientCollectionConfig } from 'payload';
|
|
2
|
+
type AnyCollectionConfig = GlobalConfig | CollectionConfig | ClientGlobalConfig | ClientCollectionConfig;
|
|
3
3
|
/**
|
|
4
4
|
* Resolve a Payload field definition by a full schemaPath like:
|
|
5
5
|
* "{collectionSlug}.fieldA.subFieldB.blockSlug.innerField"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/getFieldBySchemaPath.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getFieldBySchemaPath.ts"],"sourcesContent":["import type {\n Field,\n GlobalConfig,\n CollectionConfig,\n ClientGlobalConfig,\n ClientCollectionConfig,\n} from 'payload'\n\ntype AnyCollectionConfig =\n | GlobalConfig\n | CollectionConfig\n | ClientGlobalConfig\n | ClientCollectionConfig\n\n/**\n * Resolve a Payload field definition by a full schemaPath like:\n * \"{collectionSlug}.fieldA.subFieldB.blockSlug.innerField\"\n *\n * Notes:\n * - Tabs are a UI construct and are not part of schemaPath (fields inside tabs are at the same level).\n * - Blocks include the block slug as part of the path (we must consume it between the block field and its inner fields).\n * - Rows are skipped by this plugin's schema path mapping; support added defensively.\n */\nexport const getFieldBySchemaPath = (\n collectionConfig: AnyCollectionConfig,\n schemaPath: string,\n): Field | null => {\n if (!collectionConfig || !schemaPath) {\n return null\n }\n\n const parts = schemaPath.split('.')\n if (!parts.length) {\n return null\n }\n\n // Strip the collection slug prefix if present\n const [collectionSlug, ...rest] = parts\n const pathParts =\n collectionSlug === collectionConfig.slug ? rest.filter(Boolean) : parts.filter(Boolean)\n\n if (!pathParts.length) {\n return null\n }\n\n const findInFields = (fields: Field[], segments: string[]): Field | null => {\n if (!segments.length) {\n return null\n }\n\n const [current, ...remaining] = segments\n\n // First, try to match a field by name\n for (const field of fields) {\n // Tabs do not contribute to path segments; search inside all tabs with the same segments\n if ((field as any).tabs) {\n const tabs = (field as any).tabs as Array<{ fields?: Field[] }>\n for (const tab of tabs) {\n const foundInTab =\n tab.fields && tab.fields.length ? findInFields(tab.fields, segments) : null\n if (foundInTab) {\n return foundInTab\n }\n }\n }\n\n if ((field as any).name === current) {\n // If this is the last segment, we found the target field\n if (remaining.length === 0) {\n return field\n }\n\n // Recurse into composite field types\n if ((field as any).fields && Array.isArray((field as any).fields)) {\n const found = findInFields((field as any).fields, remaining)\n if (found) {\n return found\n }\n }\n\n if ((field as any).blocks && Array.isArray((field as any).blocks)) {\n // Next segment should be a block slug, then continue into block fields\n if (!remaining.length) {\n return field\n } // path stops at block container (unlikely for our mapping)\n const [blockSlug, ...afterBlock] = remaining\n const blocks = (field as any).blocks as Array<{ fields: Field[]; slug: string }>\n const block = blocks.find((b) => b.slug === blockSlug)\n if (block) {\n const found = findInFields(block.fields, afterBlock)\n if (found) {\n return found\n }\n }\n }\n }\n }\n\n // Not found at this level\n return null\n }\n\n const rootFields = (collectionConfig as any).fields as Field[] | undefined\n if (!rootFields || !Array.isArray(rootFields)) {\n return null\n }\n\n return findInFields(rootFields, pathParts)\n}\n"],"names":["getFieldBySchemaPath","collectionConfig","schemaPath","parts","split","length","collectionSlug","rest","pathParts","slug","filter","Boolean","findInFields","fields","segments","current","remaining","field","tabs","tab","foundInTab","name","Array","isArray","found","blocks","blockSlug","afterBlock","block","find","b","rootFields"],"mappings":"AAcA;;;;;;;;CAQC,GACD,OAAO,MAAMA,uBAAuB,CAClCC,kBACAC;IAEA,IAAI,CAACD,oBAAoB,CAACC,YAAY;QACpC,OAAO;IACT;IAEA,MAAMC,QAAQD,WAAWE,KAAK,CAAC;IAC/B,IAAI,CAACD,MAAME,MAAM,EAAE;QACjB,OAAO;IACT;IAEA,8CAA8C;IAC9C,MAAM,CAACC,gBAAgB,GAAGC,KAAK,GAAGJ;IAClC,MAAMK,YACJF,mBAAmBL,iBAAiBQ,IAAI,GAAGF,KAAKG,MAAM,CAACC,WAAWR,MAAMO,MAAM,CAACC;IAEjF,IAAI,CAACH,UAAUH,MAAM,EAAE;QACrB,OAAO;IACT;IAEA,MAAMO,eAAe,CAACC,QAAiBC;QACrC,IAAI,CAACA,SAAST,MAAM,EAAE;YACpB,OAAO;QACT;QAEA,MAAM,CAACU,SAAS,GAAGC,UAAU,GAAGF;QAEhC,sCAAsC;QACtC,KAAK,MAAMG,SAASJ,OAAQ;YAC1B,yFAAyF;YACzF,IAAI,AAACI,MAAcC,IAAI,EAAE;gBACvB,MAAMA,OAAO,AAACD,MAAcC,IAAI;gBAChC,KAAK,MAAMC,OAAOD,KAAM;oBACtB,MAAME,aACJD,IAAIN,MAAM,IAAIM,IAAIN,MAAM,CAACR,MAAM,GAAGO,aAAaO,IAAIN,MAAM,EAAEC,YAAY;oBACzE,IAAIM,YAAY;wBACd,OAAOA;oBACT;gBACF;YACF;YAEA,IAAI,AAACH,MAAcI,IAAI,KAAKN,SAAS;gBACnC,yDAAyD;gBACzD,IAAIC,UAAUX,MAAM,KAAK,GAAG;oBAC1B,OAAOY;gBACT;gBAEA,qCAAqC;gBACrC,IAAI,AAACA,MAAcJ,MAAM,IAAIS,MAAMC,OAAO,CAAC,AAACN,MAAcJ,MAAM,GAAG;oBACjE,MAAMW,QAAQZ,aAAa,AAACK,MAAcJ,MAAM,EAAEG;oBAClD,IAAIQ,OAAO;wBACT,OAAOA;oBACT;gBACF;gBAEA,IAAI,AAACP,MAAcQ,MAAM,IAAIH,MAAMC,OAAO,CAAC,AAACN,MAAcQ,MAAM,GAAG;oBACjE,uEAAuE;oBACvE,IAAI,CAACT,UAAUX,MAAM,EAAE;wBACrB,OAAOY;oBACT,EAAE,2DAA2D;oBAC7D,MAAM,CAACS,WAAW,GAAGC,WAAW,GAAGX;oBACnC,MAAMS,SAAS,AAACR,MAAcQ,MAAM;oBACpC,MAAMG,QAAQH,OAAOI,IAAI,CAAC,CAACC,IAAMA,EAAErB,IAAI,KAAKiB;oBAC5C,IAAIE,OAAO;wBACT,MAAMJ,QAAQZ,aAAagB,MAAMf,MAAM,EAAEc;wBACzC,IAAIH,OAAO;4BACT,OAAOA;wBACT;oBACF;gBACF;YACF;QACF;QAEA,0BAA0B;QAC1B,OAAO;IACT;IAEA,MAAMO,aAAa,AAAC9B,iBAAyBY,MAAM;IACnD,IAAI,CAACkB,cAAc,CAACT,MAAMC,OAAO,CAACQ,aAAa;QAC7C,OAAO;IACT;IAEA,OAAOnB,aAAamB,YAAYvB;AAClC,EAAC"}
|
|
@@ -1,50 +1,66 @@
|
|
|
1
1
|
export const updateFieldsConfig = (collectionConfig)=>{
|
|
2
2
|
let schemaPathMap = {};
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Recursively updates field configuration to inject AI components
|
|
5
|
+
* @param field - Payload field to process
|
|
6
|
+
* @param parentPath - Schema path from parent (for nested fields)
|
|
7
|
+
*/ function updateField(field, parentPath = '') {
|
|
8
|
+
const fieldWithName = field;
|
|
9
|
+
const currentPath = parentPath ? `${parentPath}.${fieldWithName.name}` : fieldWithName.name;
|
|
5
10
|
const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`;
|
|
6
|
-
// Disabled fields/ field types
|
|
7
|
-
|
|
11
|
+
// Disabled fields/ field types - skip processing
|
|
12
|
+
const admin = field.admin;
|
|
13
|
+
if (admin?.disabled || admin?.readOnly || admin?.hidden) {
|
|
8
14
|
return field;
|
|
9
15
|
}
|
|
16
|
+
// Rows are layout-only constructs and should not add to the schema path (like tabs)
|
|
17
|
+
// Process their nested fields but use parentPath to maintain correct path structure
|
|
18
|
+
if (field.type === 'row' && 'fields' in field) {
|
|
19
|
+
const fieldWithFields = field;
|
|
20
|
+
return {
|
|
21
|
+
...field,
|
|
22
|
+
fields: fieldWithFields.fields.map((subField)=>updateField(subField, parentPath))
|
|
23
|
+
};
|
|
24
|
+
}
|
|
10
25
|
// Map field path for global fieldInstructionsMap to load related instructions
|
|
11
26
|
// This is done due to save extra API call to get instructions when Field components are loaded in admin
|
|
12
27
|
// Doing is will only call instructions data when user clicks on settings
|
|
13
|
-
if ([
|
|
28
|
+
if (field.type && [
|
|
14
29
|
'richText',
|
|
15
30
|
'text',
|
|
16
31
|
'textarea',
|
|
17
32
|
'upload'
|
|
18
33
|
].includes(field.type)) {
|
|
34
|
+
const fieldAny = field;
|
|
19
35
|
schemaPathMap = {
|
|
20
36
|
...schemaPathMap,
|
|
21
37
|
[currentSchemaPath]: {
|
|
22
38
|
type: field.type,
|
|
23
|
-
label:
|
|
24
|
-
relationTo:
|
|
39
|
+
label: fieldAny.label || fieldWithName.name,
|
|
40
|
+
relationTo: fieldAny.relationTo
|
|
25
41
|
}
|
|
26
42
|
};
|
|
27
43
|
}
|
|
28
44
|
// Inject AI actions, richText is not included here as it has to be explicitly defined by user
|
|
29
|
-
if ([
|
|
45
|
+
if (field.type && [
|
|
30
46
|
'text',
|
|
31
47
|
'textarea',
|
|
32
48
|
'upload'
|
|
33
49
|
].includes(field.type)) {
|
|
34
|
-
|
|
50
|
+
const customField = {};
|
|
35
51
|
// Custom fields don't fully adhere to the Payload schema, making it difficult to
|
|
36
52
|
// determine which components support injecting ComposeField as a Description.
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
if (admin?.components) {
|
|
54
|
+
// TODO: If a field already provides its own Description, we still inject our ComposeField
|
|
55
|
+
// by overriding Description. If you need both, consider composing your own wrapper.
|
|
56
|
+
// customField would be used here if needed
|
|
41
57
|
}
|
|
42
58
|
return {
|
|
43
59
|
...field,
|
|
44
60
|
admin: {
|
|
45
61
|
...field.admin,
|
|
46
62
|
components: {
|
|
47
|
-
...
|
|
63
|
+
...admin?.components || {},
|
|
48
64
|
Description: {
|
|
49
65
|
clientProps: {
|
|
50
66
|
schemaPath: currentSchemaPath
|
|
@@ -56,16 +72,20 @@ export const updateFieldsConfig = (collectionConfig)=>{
|
|
|
56
72
|
}
|
|
57
73
|
};
|
|
58
74
|
}
|
|
59
|
-
|
|
75
|
+
// Handle fields with nested fields (group, collapsible, etc.)
|
|
76
|
+
if ('fields' in field && Array.isArray(field.fields)) {
|
|
77
|
+
const fieldWithFields = field;
|
|
60
78
|
return {
|
|
61
79
|
...field,
|
|
62
|
-
fields:
|
|
80
|
+
fields: fieldWithFields.fields.map((subField)=>updateField(subField, currentPath))
|
|
63
81
|
};
|
|
64
82
|
}
|
|
65
|
-
|
|
83
|
+
// Handle fields with tabs
|
|
84
|
+
if ('tabs' in field && Array.isArray(field.tabs)) {
|
|
85
|
+
const fieldWithTabs = field;
|
|
66
86
|
return {
|
|
67
87
|
...field,
|
|
68
|
-
tabs:
|
|
88
|
+
tabs: fieldWithTabs.tabs.map((tab)=>{
|
|
69
89
|
return {
|
|
70
90
|
...tab,
|
|
71
91
|
// Tabs are a UI construct and should not add to the schema path
|
|
@@ -74,10 +94,12 @@ export const updateFieldsConfig = (collectionConfig)=>{
|
|
|
74
94
|
})
|
|
75
95
|
};
|
|
76
96
|
}
|
|
77
|
-
|
|
97
|
+
// Handle fields with blocks
|
|
98
|
+
if ('blocks' in field && Array.isArray(field.blocks)) {
|
|
99
|
+
const fieldWithBlocks = field;
|
|
78
100
|
return {
|
|
79
101
|
...field,
|
|
80
|
-
blocks:
|
|
102
|
+
blocks: fieldWithBlocks.blocks.map((block)=>({
|
|
81
103
|
...block,
|
|
82
104
|
fields: block.fields.map((subField)=>updateField(subField, `${currentPath}.${block.slug}`))
|
|
83
105
|
}))
|
|
@@ -1 +1 @@
|
|
|
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:
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig, Field, GlobalConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, string>\n updatedCollectionConfig: CollectionConfig | GlobalConfig\n}\n\ntype FieldWithName = { name: string }\ntype FieldWithFields = { fields: Field[] }\ntype FieldWithTabs = { tabs: Array<{ fields?: Field[] }> }\ntype FieldWithBlocks = { blocks: Array<{ fields: Field[]; slug: string }> }\n\nexport const updateFieldsConfig = (\n collectionConfig: CollectionConfig | GlobalConfig,\n): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n /**\n * Recursively updates field configuration to inject AI components\n * @param field - Payload field to process\n * @param parentPath - Schema path from parent (for nested fields)\n */\n function updateField(field: Field, parentPath = ''): Field {\n const fieldWithName = field as Field & FieldWithName\n const currentPath = parentPath ? `${parentPath}.${fieldWithName.name}` : fieldWithName.name\n const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`\n\n // Disabled fields/ field types - skip processing\n const admin = field.admin as Record<string, unknown> | undefined\n if (admin?.disabled || admin?.readOnly || admin?.hidden) {\n return field\n }\n\n // Rows are layout-only constructs and should not add to the schema path (like tabs)\n // Process their nested fields but use parentPath to maintain correct path structure\n if (field.type === 'row' && 'fields' in field) {\n const fieldWithFields = field as Field & FieldWithFields\n return {\n ...field,\n fields: fieldWithFields.fields.map((subField) => updateField(subField, parentPath)),\n } as 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 (field.type && ['richText', 'text', 'textarea', 'upload'].includes(field.type)) {\n const fieldAny = field as Record<string, unknown>\n schemaPathMap = {\n ...schemaPathMap,\n [currentSchemaPath]: {\n type: field.type,\n label: fieldAny.label || fieldWithName.name,\n relationTo: fieldAny.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 (field.type && ['text', 'textarea', 'upload'].includes(field.type)) {\n const customField: Record<string, never> = {}\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 (admin?.components) {\n // TODO: If a field already provides its own Description, we still inject our ComposeField\n // by overriding Description. If you need both, consider composing your own wrapper.\n // customField would be used here if needed\n }\n\n return {\n ...field,\n admin: {\n ...(field.admin as Record<string, unknown>),\n components: {\n ...((admin?.components as Record<string, unknown>) || {}),\n Description: {\n clientProps: {\n schemaPath: currentSchemaPath,\n },\n path: '@ai-stack/payloadcms/fields#ComposeField',\n },\n ...customField,\n },\n },\n } as Field\n }\n\n // Handle fields with nested fields (group, collapsible, etc.)\n if ('fields' in field && Array.isArray(field.fields)) {\n const fieldWithFields = field as Field & FieldWithFields\n return {\n ...field,\n fields: fieldWithFields.fields.map((subField) => updateField(subField, currentPath)),\n } as Field\n }\n\n // Handle fields with tabs\n if ('tabs' in field && Array.isArray(field.tabs)) {\n const fieldWithTabs = field as Field & FieldWithTabs\n return {\n ...field,\n tabs: fieldWithTabs.tabs.map((tab) => {\n return {\n ...tab,\n // Tabs are a UI construct and should not add to the schema path\n fields: (tab.fields || []).map((subField) => updateField(subField, parentPath)),\n }\n }),\n } as Field\n }\n\n // Handle fields with blocks\n if ('blocks' in field && Array.isArray(field.blocks)) {\n const fieldWithBlocks = field as Field & FieldWithBlocks\n return {\n ...field,\n blocks: fieldWithBlocks.blocks.map((block) => ({\n ...block,\n fields: block.fields.map((subField) =>\n updateField(subField, `${currentPath}.${block.slug}`),\n ),\n })),\n } as Field\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","fieldWithName","currentPath","name","currentSchemaPath","slug","admin","disabled","readOnly","hidden","type","fieldWithFields","fields","map","subField","includes","fieldAny","label","relationTo","customField","components","Description","clientProps","schemaPath","path","Array","isArray","tabs","fieldWithTabs","tab","blocks","fieldWithBlocks","block","updatedCollectionConfig"],"mappings":"AAYA,OAAO,MAAMA,qBAAqB,CAChCC;IAEA,IAAIC,gBAAgB,CAAC;IAErB;;;;GAIC,GACD,SAASC,YAAYC,KAAY,EAAEC,aAAa,EAAE;QAChD,MAAMC,gBAAgBF;QACtB,MAAMG,cAAcF,aAAa,CAAC,EAAEA,WAAW,CAAC,EAAEC,cAAcE,IAAI,CAAC,CAAC,GAAGF,cAAcE,IAAI;QAC3F,MAAMC,oBAAoB,CAAC,EAAER,iBAAiBS,IAAI,CAAC,CAAC,EAAEH,YAAY,CAAC;QAEnE,iDAAiD;QACjD,MAAMI,QAAQP,MAAMO,KAAK;QACzB,IAAIA,OAAOC,YAAYD,OAAOE,YAAYF,OAAOG,QAAQ;YACvD,OAAOV;QACT;QAEA,oFAAoF;QACpF,oFAAoF;QACpF,IAAIA,MAAMW,IAAI,KAAK,SAAS,YAAYX,OAAO;YAC7C,MAAMY,kBAAkBZ;YACxB,OAAO;gBACL,GAAGA,KAAK;gBACRa,QAAQD,gBAAgBC,MAAM,CAACC,GAAG,CAAC,CAACC,WAAahB,YAAYgB,UAAUd;YACzE;QACF;QAEA,8EAA8E;QAC9E,wGAAwG;QACxG,yEAAyE;QACzE,IAAID,MAAMW,IAAI,IAAI;YAAC;YAAY;YAAQ;YAAY;SAAS,CAACK,QAAQ,CAAChB,MAAMW,IAAI,GAAG;YACjF,MAAMM,WAAWjB;YACjBF,gBAAgB;gBACd,GAAGA,aAAa;gBAChB,CAACO,kBAAkB,EAAE;oBACnBM,MAAMX,MAAMW,IAAI;oBAChBO,OAAOD,SAASC,KAAK,IAAIhB,cAAcE,IAAI;oBAC3Ce,YAAYF,SAASE,UAAU;gBACjC;YACF;QACF;QAEA,8FAA8F;QAC9F,IAAInB,MAAMW,IAAI,IAAI;YAAC;YAAQ;YAAY;SAAS,CAACK,QAAQ,CAAChB,MAAMW,IAAI,GAAG;YACrE,MAAMS,cAAqC,CAAC;YAE5C,iFAAiF;YACjF,8EAA8E;YAC9E,IAAIb,OAAOc,YAAY;YACrB,0FAA0F;YAC1F,oFAAoF;YACpF,2CAA2C;YAC7C;YAEA,OAAO;gBACL,GAAGrB,KAAK;gBACRO,OAAO;oBACL,GAAIP,MAAMO,KAAK;oBACfc,YAAY;wBACV,GAAI,AAACd,OAAOc,cAA0C,CAAC,CAAC;wBACxDC,aAAa;4BACXC,aAAa;gCACXC,YAAYnB;4BACd;4BACAoB,MAAM;wBACR;wBACA,GAAGL,WAAW;oBAChB;gBACF;YACF;QACF;QAEA,8DAA8D;QAC9D,IAAI,YAAYpB,SAAS0B,MAAMC,OAAO,CAAC3B,MAAMa,MAAM,GAAG;YACpD,MAAMD,kBAAkBZ;YACxB,OAAO;gBACL,GAAGA,KAAK;gBACRa,QAAQD,gBAAgBC,MAAM,CAACC,GAAG,CAAC,CAACC,WAAahB,YAAYgB,UAAUZ;YACzE;QACF;QAEA,0BAA0B;QAC1B,IAAI,UAAUH,SAAS0B,MAAMC,OAAO,CAAC3B,MAAM4B,IAAI,GAAG;YAChD,MAAMC,gBAAgB7B;YACtB,OAAO;gBACL,GAAGA,KAAK;gBACR4B,MAAMC,cAAcD,IAAI,CAACd,GAAG,CAAC,CAACgB;oBAC5B,OAAO;wBACL,GAAGA,GAAG;wBACN,gEAAgE;wBAChEjB,QAAQ,AAACiB,CAAAA,IAAIjB,MAAM,IAAI,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC,WAAahB,YAAYgB,UAAUd;oBACrE;gBACF;YACF;QACF;QAEA,4BAA4B;QAC5B,IAAI,YAAYD,SAAS0B,MAAMC,OAAO,CAAC3B,MAAM+B,MAAM,GAAG;YACpD,MAAMC,kBAAkBhC;YACxB,OAAO;gBACL,GAAGA,KAAK;gBACR+B,QAAQC,gBAAgBD,MAAM,CAACjB,GAAG,CAAC,CAACmB,QAAW,CAAA;wBAC7C,GAAGA,KAAK;wBACRpB,QAAQoB,MAAMpB,MAAM,CAACC,GAAG,CAAC,CAACC,WACxBhB,YAAYgB,UAAU,CAAC,EAAEZ,YAAY,CAAC,EAAE8B,MAAM3B,IAAI,CAAC,CAAC;oBAExD,CAAA;YACF;QACF;QAEA,OAAON;IACT;IAEA,MAAMkC,0BAA0B;QAC9B,GAAGrC,gBAAgB;QACnBgB,QAAQhB,iBAAiBgB,MAAM,CAACC,GAAG,CAAC,CAACd,QAAUD,YAAYC;IAC7D;IAEA,OAAO;QACLF;QACAoC;IACF;AACF,EAAC"}
|