@ai-stack/payloadcms 3.76.0-beta.4 → 3.76.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -127,13 +127,39 @@ fields: [
127
127
  # .env
128
128
  OPENAI_API_KEY=your-openai-api-key
129
129
  ANTHROPIC_API_KEY=your-anthropic-api-key # Optional
130
- GOOGLE_AI_API_KEY=your-google-api-key # Optional
130
+ GOOGLE_GENERATIVE_AI_API_KEY=your-google-api-key # Optional
131
+ GEMINI_API_KEY=your-google-api-key # Optional alias
131
132
  XAI_API_KEY=your-xai-api-key # Optional
132
133
  ELEVENLABS_API_KEY=your-elevenlabs-api-key # Optional
133
134
  ```
134
135
 
135
136
  > **✨ Pro tip:** You can also configure API keys directly in the AI Settings panel within Payload Admin—encrypted and secure.
136
137
 
138
+ ### 4. Cloudflare / Edge Runtime (Optional)
139
+
140
+ If your runtime does not expose provider keys via `process.env`, pass them to the plugin explicitly.
141
+
142
+ ```typescript
143
+ import { aiPlugin } from '@ai-stack/payloadcms'
144
+
145
+ export default buildConfig({
146
+ plugins: [
147
+ aiPlugin({
148
+ // Resolution order: getEnv -> env -> process.env
149
+ env: {
150
+ OPENAI_API_KEY: cloudflare.env.OPENAI_API_KEY,
151
+ GOOGLE_GENERATIVE_AI_API_KEY: cloudflare.env.GOOGLE_GENERATIVE_AI_API_KEY,
152
+ },
153
+ // or provide a resolver:
154
+ getEnv: (key) => {
155
+ const value = (cloudflare.env as Record<string, unknown>)[key]
156
+ return typeof value === 'string' ? value : undefined
157
+ },
158
+ }),
159
+ ],
160
+ })
161
+ ```
162
+
137
163
  ---
138
164
 
139
165
  ## 🚀 Programmatic API (`payload.ai`)
@@ -103,8 +103,8 @@ const providerOptionsUIField = {
103
103
  };
104
104
  export const instructionsCollection = (pluginConfig)=>({
105
105
  labels: {
106
- plural: 'Compose Settings',
107
- singular: 'Compose Setting'
106
+ plural: 'Instructions',
107
+ singular: 'Instruction'
108
108
  },
109
109
  ...pluginConfig.overrideInstructions,
110
110
  slug: PLUGIN_INSTRUCTIONS_TABLE,
@@ -115,6 +115,7 @@ export const instructionsCollection = (pluginConfig)=>({
115
115
  admin: {
116
116
  description: 'Customize how AI interacts with specific fields within your enabled collections.',
117
117
  ...pluginCollectionAdmin,
118
+ group: 'AI Plugin',
118
119
  ...pluginConfig.overrideInstructions?.admin,
119
120
  components: {
120
121
  beforeList: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/collections/Instructions.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\nimport type { PluginConfig } from 'src/types.js'\n\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\nimport { PromptMentionsFeature } from '../fields/PromptEditorField/feature.server.js'\nimport { applyInstructionDefaultsForDisplay } from '../utilities/ai/resolveEffectiveInstructionSettings.js'\nimport { pluginCollectionAccess, pluginCollectionAdmin } from './shared.js'\n\n// Defined capabilities replacing src/ai/models/\nconst CAPABILITIES = [\n {\n id: 'text',\n name: 'Text Generation',\n fields: ['text', 'textarea'],\n },\n {\n id: 'richtext',\n name: 'Rich Text Generation',\n fields: ['richText'],\n },\n {\n id: 'image',\n name: 'Image Generation',\n fields: ['upload'],\n },\n {\n id: 'tts',\n name: 'Text to Speech',\n fields: ['upload'],\n },\n {\n id: 'array',\n name: 'Array Generation',\n fields: ['array'],\n },\n]\n\n\nconst providerSelect = {\n name: 'provider',\n type: 'text' as const,\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/ui/DynamicProviderSelect/index.js#DynamicProviderSelect',\n },\n },\n label: 'Provider',\n}\n\nconst modelSelect = {\n name: 'model',\n type: 'text' as const,\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/ui/DynamicModelSelect/index.js#DynamicModelSelect',\n },\n },\n label: 'Model',\n}\n\n\nconst commonTextParams = [\n {\n type: 'row' as const,\n fields: [\n {\n name: 'maxTokens',\n type: 'number' as const,\n admin: {\n placeholder: 'Model Default',\n },\n label: 'Max Tokens',\n },\n {\n name: 'temperature',\n type: 'number' as const,\n defaultValue: 0.7,\n label: 'Temperature',\n max: 1,\n min: 0,\n },\n ],\n },\n {\n name: 'extractAttachments',\n type: 'checkbox' as const,\n label: 'Extract Attachments',\n },\n]\n\nconst providerOptionsUIField = {\n name: 'providerOptions',\n type: 'json' as const,\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/ui/InstructionProviderOptions/index.js#InstructionProviderOptions',\n },\n },\n label: 'Provider Options',\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 ...pluginCollectionAccess,\n ...pluginConfig.overrideInstructions?.access,\n },\n admin: {\n description:\n 'Customize how AI interacts with specific fields within your enabled collections.',\n ...pluginCollectionAdmin,\n ...pluginConfig.overrideInstructions?.admin,\n components: {\n beforeList: ['@ai-stack/payloadcms/ui/ConfigDashboard/index.js#ConfigDashboard'],\n },\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 hidden: !pluginConfig.debugging,\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 hidden: !pluginConfig.debugging,\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 label: 'array',\n value: 'array',\n },\n ],\n },\n {\n name: 'relation-to',\n type: 'text',\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'upload'\n },\n hidden: !pluginConfig.debugging,\n },\n label: 'Relation to',\n },\n {\n name: 'hasMany',\n type: 'checkbox',\n admin: {\n hidden: true,\n },\n defaultValue: false,\n },\n {\n name: 'model-id',\n type: 'select',\n admin: {\n components: {\n Field: {\n clientProps: {\n filterByField: 'field-type',\n options: CAPABILITIES.map((c) => ({\n fields: c.fields,\n label: c.name,\n value: c.id,\n })),\n },\n path: '@ai-stack/payloadcms/fields/SelectField/SelectField.js#SelectField',\n },\n },\n },\n label: 'Capability',\n options: CAPABILITIES.map((c) => ({\n label: c.name,\n value: c.id,\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 name: 'alwaysShow',\n type: 'checkbox',\n admin: {\n condition: (_, current) => !current.disabled,\n description: 'Compose button will always be visible without requiring field focus',\n },\n defaultValue: false,\n label: 'Always show Compose button',\n },\n {\n name: 'appendGenerated',\n type: 'checkbox',\n admin: {\n condition: (_, current) => current?.hasMany === true && current?.disabled !== true,\n description: 'If enabled, generated values are appended to current values instead of replacing them.',\n },\n defaultValue: false,\n label: 'Append generated values',\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 { // TODO: update below to use PromptField\n name: 'prompt',\n type: 'richText',\n admin: {\n description: \"Click 'Compose' to run this custom prompt and generate content\",\n },\n editor: lexicalEditor({\n features: ({ rootFeatures: _rootFeatures }) => [PromptMentionsFeature()],\n }),\n label: '',\n },\n ],\n label: 'Prompt',\n },\n {\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'upload' && current['model-id'] === 'image'\n },\n },\n description:\n 'These images will be used to generate new visuals in a similar style, layout, or content.',\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 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\n // Inline Settings Groups by Capability\n\n // Text Settings\n {\n name: 'text-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'text',\n },\n fields: [\n providerSelect,\n modelSelect,\n ...commonTextParams,\n providerOptionsUIField,\n ],\n label: 'Text Settings',\n },\n\n // Rich Text Settings\n {\n name: 'richtext-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'richtext',\n },\n fields: [\n providerSelect,\n modelSelect,\n ...commonTextParams,\n providerOptionsUIField,\n ],\n label: 'Rich Text Settings',\n },\n\n // Image Settings\n {\n name: 'image-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'image',\n },\n fields: [providerSelect, modelSelect, providerOptionsUIField],\n label: 'Image Settings',\n },\n\n // TTS Settings\n {\n name: 'tts-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'tts',\n },\n fields: [\n providerSelect,\n modelSelect,\n {\n name: 'voice',\n type: 'text',\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/ui/DynamicVoiceSelect/index.js#DynamicVoiceSelect',\n },\n },\n label: 'Voice',\n },\n providerOptionsUIField,\n ],\n label: 'TTS Settings',\n },\n\n // Array Settings\n {\n name: 'array-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'array',\n },\n fields: [\n providerSelect,\n modelSelect,\n {\n name: 'count',\n type: 'number',\n admin: {\n description: 'Number of items to generate',\n },\n defaultValue: 3,\n label: 'Items to Generate',\n max: 20,\n min: 1,\n },\n providerOptionsUIField,\n ],\n label: 'Array Settings',\n },\n ],\n hooks: {\n ...pluginConfig.overrideInstructions?.hooks,\n afterRead: [\n ...(pluginConfig.overrideInstructions?.hooks?.afterRead || []),\n async ({ context, doc, req }) => {\n if (!doc || typeof doc !== 'object') {\n return doc\n }\n\n const cacheKey = '__aiProvidersDefaults'\n const hookContext = (context || {}) as Record<string, unknown>\n let defaults = hookContext[cacheKey] as Record<string, unknown> | undefined\n\n if (!defaults) {\n try {\n const aiSettings = await req.payload.findGlobal({\n slug: 'ai-providers',\n })\n defaults = (aiSettings?.defaults || {}) as Record<string, unknown>\n hookContext[cacheKey] = defaults\n } catch (_error) {\n return doc\n }\n }\n\n return applyInstructionDefaultsForDisplay({\n defaults,\n instructions: doc as Record<string, unknown>,\n })\n },\n ],\n },\n }\n"],"names":["lexicalEditor","PLUGIN_INSTRUCTIONS_TABLE","PromptMentionsFeature","applyInstructionDefaultsForDisplay","pluginCollectionAccess","pluginCollectionAdmin","CAPABILITIES","id","name","fields","providerSelect","type","admin","components","Field","label","modelSelect","commonTextParams","placeholder","defaultValue","max","min","providerOptionsUIField","instructionsCollection","pluginConfig","labels","plural","singular","overrideInstructions","slug","access","description","beforeList","hidden","debugging","unique","options","value","condition","_","current","clientProps","filterByField","map","c","path","disabled","hasMany","tabs","editor","features","rootFeatures","_rootFeatures","relationTo","uploadCollectionSlug","data","hooks","afterRead","context","doc","req","cacheKey","hookContext","defaults","aiSettings","payload","findGlobal","_error","instructions"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/collections/Instructions.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\nimport type { PluginConfig } from 'src/types.js'\n\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\nimport { PromptMentionsFeature } from '../fields/PromptEditorField/feature.server.js'\nimport { applyInstructionDefaultsForDisplay } from '../utilities/ai/resolveEffectiveInstructionSettings.js'\nimport { pluginCollectionAccess, pluginCollectionAdmin } from './shared.js'\n\n// Defined capabilities replacing src/ai/models/\nconst CAPABILITIES = [\n {\n id: 'text',\n name: 'Text Generation',\n fields: ['text', 'textarea'],\n },\n {\n id: 'richtext',\n name: 'Rich Text Generation',\n fields: ['richText'],\n },\n {\n id: 'image',\n name: 'Image Generation',\n fields: ['upload'],\n },\n {\n id: 'tts',\n name: 'Text to Speech',\n fields: ['upload'],\n },\n {\n id: 'array',\n name: 'Array Generation',\n fields: ['array'],\n },\n]\n\n\nconst providerSelect = {\n name: 'provider',\n type: 'text' as const,\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/ui/DynamicProviderSelect/index.js#DynamicProviderSelect',\n },\n },\n label: 'Provider',\n}\n\nconst modelSelect = {\n name: 'model',\n type: 'text' as const,\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/ui/DynamicModelSelect/index.js#DynamicModelSelect',\n },\n },\n label: 'Model',\n}\n\n\nconst commonTextParams = [\n {\n type: 'row' as const,\n fields: [\n {\n name: 'maxTokens',\n type: 'number' as const,\n admin: {\n placeholder: 'Model Default',\n },\n label: 'Max Tokens',\n },\n {\n name: 'temperature',\n type: 'number' as const,\n defaultValue: 0.7,\n label: 'Temperature',\n max: 1,\n min: 0,\n },\n ],\n },\n {\n name: 'extractAttachments',\n type: 'checkbox' as const,\n label: 'Extract Attachments',\n },\n]\n\nconst providerOptionsUIField = {\n name: 'providerOptions',\n type: 'json' as const,\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/ui/InstructionProviderOptions/index.js#InstructionProviderOptions',\n },\n },\n label: 'Provider Options',\n}\n\nexport const instructionsCollection = (pluginConfig: PluginConfig) =>\n <CollectionConfig>{\n labels: {\n plural: 'Instructions',\n singular: 'Instruction',\n },\n ...pluginConfig.overrideInstructions,\n slug: PLUGIN_INSTRUCTIONS_TABLE,\n access: {\n ...pluginCollectionAccess,\n ...pluginConfig.overrideInstructions?.access,\n },\n admin: {\n description:\n 'Customize how AI interacts with specific fields within your enabled collections.',\n ...pluginCollectionAdmin,\n group: 'AI Plugin',\n ...pluginConfig.overrideInstructions?.admin,\n components: {\n beforeList: ['@ai-stack/payloadcms/ui/ConfigDashboard/index.js#ConfigDashboard'],\n },\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 hidden: !pluginConfig.debugging,\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 hidden: !pluginConfig.debugging,\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 label: 'array',\n value: 'array',\n },\n ],\n },\n {\n name: 'relation-to',\n type: 'text',\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'upload'\n },\n hidden: !pluginConfig.debugging,\n },\n label: 'Relation to',\n },\n {\n name: 'hasMany',\n type: 'checkbox',\n admin: {\n hidden: true,\n },\n defaultValue: false,\n },\n {\n name: 'model-id',\n type: 'select',\n admin: {\n components: {\n Field: {\n clientProps: {\n filterByField: 'field-type',\n options: CAPABILITIES.map((c) => ({\n fields: c.fields,\n label: c.name,\n value: c.id,\n })),\n },\n path: '@ai-stack/payloadcms/fields/SelectField/SelectField.js#SelectField',\n },\n },\n },\n label: 'Capability',\n options: CAPABILITIES.map((c) => ({\n label: c.name,\n value: c.id,\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 name: 'alwaysShow',\n type: 'checkbox',\n admin: {\n condition: (_, current) => !current.disabled,\n description: 'Compose button will always be visible without requiring field focus',\n },\n defaultValue: false,\n label: 'Always show Compose button',\n },\n {\n name: 'appendGenerated',\n type: 'checkbox',\n admin: {\n condition: (_, current) => current?.hasMany === true && current?.disabled !== true,\n description: 'If enabled, generated values are appended to current values instead of replacing them.',\n },\n defaultValue: false,\n label: 'Append generated values',\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 { // TODO: update below to use PromptField\n name: 'prompt',\n type: 'richText',\n admin: {\n description: \"Click 'Compose' to run this custom prompt and generate content\",\n },\n editor: lexicalEditor({\n features: ({ rootFeatures: _rootFeatures }) => [PromptMentionsFeature()],\n }),\n label: '',\n },\n ],\n label: 'Prompt',\n },\n {\n admin: {\n condition: (_, current) => {\n return current['field-type'] === 'upload' && current['model-id'] === 'image'\n },\n },\n description:\n 'These images will be used to generate new visuals in a similar style, layout, or content.',\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 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\n // Inline Settings Groups by Capability\n\n // Text Settings\n {\n name: 'text-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'text',\n },\n fields: [\n providerSelect,\n modelSelect,\n ...commonTextParams,\n providerOptionsUIField,\n ],\n label: 'Text Settings',\n },\n\n // Rich Text Settings\n {\n name: 'richtext-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'richtext',\n },\n fields: [\n providerSelect,\n modelSelect,\n ...commonTextParams,\n providerOptionsUIField,\n ],\n label: 'Rich Text Settings',\n },\n\n // Image Settings\n {\n name: 'image-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'image',\n },\n fields: [providerSelect, modelSelect, providerOptionsUIField],\n label: 'Image Settings',\n },\n\n // TTS Settings\n {\n name: 'tts-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'tts',\n },\n fields: [\n providerSelect,\n modelSelect,\n {\n name: 'voice',\n type: 'text',\n admin: {\n components: {\n Field: '@ai-stack/payloadcms/ui/DynamicVoiceSelect/index.js#DynamicVoiceSelect',\n },\n },\n label: 'Voice',\n },\n providerOptionsUIField,\n ],\n label: 'TTS Settings',\n },\n\n // Array Settings\n {\n name: 'array-settings',\n type: 'group',\n admin: {\n condition: (data) => data['model-id'] === 'array',\n },\n fields: [\n providerSelect,\n modelSelect,\n {\n name: 'count',\n type: 'number',\n admin: {\n description: 'Number of items to generate',\n },\n defaultValue: 3,\n label: 'Items to Generate',\n max: 20,\n min: 1,\n },\n providerOptionsUIField,\n ],\n label: 'Array Settings',\n },\n ],\n hooks: {\n ...pluginConfig.overrideInstructions?.hooks,\n afterRead: [\n ...(pluginConfig.overrideInstructions?.hooks?.afterRead || []),\n async ({ context, doc, req }) => {\n if (!doc || typeof doc !== 'object') {\n return doc\n }\n\n const cacheKey = '__aiProvidersDefaults'\n const hookContext = (context || {}) as Record<string, unknown>\n let defaults = hookContext[cacheKey] as Record<string, unknown> | undefined\n\n if (!defaults) {\n try {\n const aiSettings = await req.payload.findGlobal({\n slug: 'ai-providers',\n })\n defaults = (aiSettings?.defaults || {}) as Record<string, unknown>\n hookContext[cacheKey] = defaults\n } catch (_error) {\n return doc\n }\n }\n\n return applyInstructionDefaultsForDisplay({\n defaults,\n instructions: doc as Record<string, unknown>,\n })\n },\n ],\n },\n }\n"],"names":["lexicalEditor","PLUGIN_INSTRUCTIONS_TABLE","PromptMentionsFeature","applyInstructionDefaultsForDisplay","pluginCollectionAccess","pluginCollectionAdmin","CAPABILITIES","id","name","fields","providerSelect","type","admin","components","Field","label","modelSelect","commonTextParams","placeholder","defaultValue","max","min","providerOptionsUIField","instructionsCollection","pluginConfig","labels","plural","singular","overrideInstructions","slug","access","description","group","beforeList","hidden","debugging","unique","options","value","condition","_","current","clientProps","filterByField","map","c","path","disabled","hasMany","tabs","editor","features","rootFeatures","_rootFeatures","relationTo","uploadCollectionSlug","data","hooks","afterRead","context","doc","req","cacheKey","hookContext","defaults","aiSettings","payload","findGlobal","_error","instructions"],"mappings":"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"}
@@ -8,6 +8,7 @@ export declare const PLUGIN_API_ENDPOINT_GENERATE_UPLOAD = "/plugin-ai/generate/
8
8
  export declare const PLUGIN_FETCH_FIELDS_ENDPOINT = "/plugin-ai/fetch-fields";
9
9
  export declare const PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK = "/plugin-ai/videogen/webhook";
10
10
  export declare const PLUGIN_API_ENDPOINT_FETCH_VOICES = "/plugin-ai/elevenlabs/fetch-voices";
11
+ export declare const PLUGIN_SERVER_URL_ENV_KEYS: readonly ["SERVER_URL", "NEXT_PUBLIC_SERVER_URL"];
11
12
  export declare const PLUGIN_DEFAULT_OPENAI_MODEL = "gpt-4o-mini";
12
13
  export declare const PLUGIN_DEFAULT_ANTHROPIC_MODEL = "claude-3-5-sonnet-latest";
13
14
  export declare const excludeCollections: string[];
package/dist/defaults.js CHANGED
@@ -9,6 +9,11 @@ export const PLUGIN_API_ENDPOINT_GENERATE_UPLOAD = `${PLUGIN_API_ENDPOINT_GENERA
9
9
  export const PLUGIN_FETCH_FIELDS_ENDPOINT = `${PLUGIN_API_ENDPOINT_BASE}/fetch-fields`;
10
10
  export const PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK = `${PLUGIN_API_ENDPOINT_BASE}/videogen/webhook`;
11
11
  export const PLUGIN_API_ENDPOINT_FETCH_VOICES = `${PLUGIN_API_ENDPOINT_BASE}/elevenlabs/fetch-voices`;
12
+ // Runtime URL resolution fallbacks
13
+ export const PLUGIN_SERVER_URL_ENV_KEYS = [
14
+ 'SERVER_URL',
15
+ 'NEXT_PUBLIC_SERVER_URL'
16
+ ];
12
17
  // LLM Settings
13
18
  export const PLUGIN_DEFAULT_OPENAI_MODEL = `gpt-4o-mini`;
14
19
  export const PLUGIN_DEFAULT_ANTHROPIC_MODEL = `claude-3-5-sonnet-latest`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["export const PLUGIN_NAME = 'plugin-ai'\nexport const PLUGIN_INSTRUCTIONS_TABLE = `${PLUGIN_NAME}-instructions`\nexport const PLUGIN_AI_JOBS_TABLE = `${PLUGIN_NAME}-ai-jobs`\nexport const PLUGIN_LEXICAL_EDITOR_FEATURE = `${PLUGIN_NAME}-actions-feature`\n\n// Endpoint defaults\nexport const PLUGIN_API_ENDPOINT_BASE = `/${PLUGIN_NAME}`\nexport const PLUGIN_API_ENDPOINT_GENERATE = `${PLUGIN_API_ENDPOINT_BASE}/generate`\nexport const PLUGIN_API_ENDPOINT_GENERATE_UPLOAD = `${PLUGIN_API_ENDPOINT_GENERATE}/upload`\nexport const PLUGIN_FETCH_FIELDS_ENDPOINT = `${PLUGIN_API_ENDPOINT_BASE}/fetch-fields`\nexport const PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK = `${PLUGIN_API_ENDPOINT_BASE}/videogen/webhook`\nexport const PLUGIN_API_ENDPOINT_FETCH_VOICES = `${PLUGIN_API_ENDPOINT_BASE}/elevenlabs/fetch-voices`\n\n// LLM Settings\nexport const PLUGIN_DEFAULT_OPENAI_MODEL = `gpt-4o-mini`\nexport const PLUGIN_DEFAULT_ANTHROPIC_MODEL = `claude-3-5-sonnet-latest`\n\nexport const excludeCollections = [\n 'payload-preferences',\n 'payload-migrations',\n 'payload-locked-documents',\n 'ai-providers',\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_AI_JOBS_TABLE,\n]\n"],"names":["PLUGIN_NAME","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_AI_JOBS_TABLE","PLUGIN_LEXICAL_EDITOR_FEATURE","PLUGIN_API_ENDPOINT_BASE","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_FETCH_FIELDS_ENDPOINT","PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK","PLUGIN_API_ENDPOINT_FETCH_VOICES","PLUGIN_DEFAULT_OPENAI_MODEL","PLUGIN_DEFAULT_ANTHROPIC_MODEL","excludeCollections"],"mappings":"AAAA,OAAO,MAAMA,cAAc,YAAW;AACtC,OAAO,MAAMC,4BAA4B,CAAC,EAAED,YAAY,aAAa,CAAC,CAAA;AACtE,OAAO,MAAME,uBAAuB,CAAC,EAAEF,YAAY,QAAQ,CAAC,CAAA;AAC5D,OAAO,MAAMG,gCAAgC,CAAC,EAAEH,YAAY,gBAAgB,CAAC,CAAA;AAE7E,oBAAoB;AACpB,OAAO,MAAMI,2BAA2B,CAAC,CAAC,EAAEJ,YAAY,CAAC,CAAA;AACzD,OAAO,MAAMK,+BAA+B,CAAC,EAAED,yBAAyB,SAAS,CAAC,CAAA;AAClF,OAAO,MAAME,sCAAsC,CAAC,EAAED,6BAA6B,OAAO,CAAC,CAAA;AAC3F,OAAO,MAAME,+BAA+B,CAAC,EAAEH,yBAAyB,aAAa,CAAC,CAAA;AACtF,OAAO,MAAMI,uCAAuC,CAAC,EAAEJ,yBAAyB,iBAAiB,CAAC,CAAA;AAClG,OAAO,MAAMK,mCAAmC,CAAC,EAAEL,yBAAyB,wBAAwB,CAAC,CAAA;AAErG,eAAe;AACf,OAAO,MAAMM,8BAA8B,CAAC,WAAW,CAAC,CAAA;AACxD,OAAO,MAAMC,iCAAiC,CAAC,wBAAwB,CAAC,CAAA;AAExE,OAAO,MAAMC,qBAAqB;IAChC;IACA;IACA;IACA;IACAX;IACAC;CACD,CAAA"}
1
+ {"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["export const PLUGIN_NAME = 'plugin-ai'\nexport const PLUGIN_INSTRUCTIONS_TABLE = `${PLUGIN_NAME}-instructions`\nexport const PLUGIN_AI_JOBS_TABLE = `${PLUGIN_NAME}-ai-jobs`\nexport const PLUGIN_LEXICAL_EDITOR_FEATURE = `${PLUGIN_NAME}-actions-feature`\n\n// Endpoint defaults\nexport const PLUGIN_API_ENDPOINT_BASE = `/${PLUGIN_NAME}`\nexport const PLUGIN_API_ENDPOINT_GENERATE = `${PLUGIN_API_ENDPOINT_BASE}/generate`\nexport const PLUGIN_API_ENDPOINT_GENERATE_UPLOAD = `${PLUGIN_API_ENDPOINT_GENERATE}/upload`\nexport const PLUGIN_FETCH_FIELDS_ENDPOINT = `${PLUGIN_API_ENDPOINT_BASE}/fetch-fields`\nexport const PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK = `${PLUGIN_API_ENDPOINT_BASE}/videogen/webhook`\nexport const PLUGIN_API_ENDPOINT_FETCH_VOICES = `${PLUGIN_API_ENDPOINT_BASE}/elevenlabs/fetch-voices`\n\n// Runtime URL resolution fallbacks\nexport const PLUGIN_SERVER_URL_ENV_KEYS = ['SERVER_URL', 'NEXT_PUBLIC_SERVER_URL'] as const\n\n// LLM Settings\nexport const PLUGIN_DEFAULT_OPENAI_MODEL = `gpt-4o-mini`\nexport const PLUGIN_DEFAULT_ANTHROPIC_MODEL = `claude-3-5-sonnet-latest`\n\nexport const excludeCollections = [\n 'payload-preferences',\n 'payload-migrations',\n 'payload-locked-documents',\n 'ai-providers',\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_AI_JOBS_TABLE,\n]\n"],"names":["PLUGIN_NAME","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_AI_JOBS_TABLE","PLUGIN_LEXICAL_EDITOR_FEATURE","PLUGIN_API_ENDPOINT_BASE","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_FETCH_FIELDS_ENDPOINT","PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK","PLUGIN_API_ENDPOINT_FETCH_VOICES","PLUGIN_SERVER_URL_ENV_KEYS","PLUGIN_DEFAULT_OPENAI_MODEL","PLUGIN_DEFAULT_ANTHROPIC_MODEL","excludeCollections"],"mappings":"AAAA,OAAO,MAAMA,cAAc,YAAW;AACtC,OAAO,MAAMC,4BAA4B,CAAC,EAAED,YAAY,aAAa,CAAC,CAAA;AACtE,OAAO,MAAME,uBAAuB,CAAC,EAAEF,YAAY,QAAQ,CAAC,CAAA;AAC5D,OAAO,MAAMG,gCAAgC,CAAC,EAAEH,YAAY,gBAAgB,CAAC,CAAA;AAE7E,oBAAoB;AACpB,OAAO,MAAMI,2BAA2B,CAAC,CAAC,EAAEJ,YAAY,CAAC,CAAA;AACzD,OAAO,MAAMK,+BAA+B,CAAC,EAAED,yBAAyB,SAAS,CAAC,CAAA;AAClF,OAAO,MAAME,sCAAsC,CAAC,EAAED,6BAA6B,OAAO,CAAC,CAAA;AAC3F,OAAO,MAAME,+BAA+B,CAAC,EAAEH,yBAAyB,aAAa,CAAC,CAAA;AACtF,OAAO,MAAMI,uCAAuC,CAAC,EAAEJ,yBAAyB,iBAAiB,CAAC,CAAA;AAClG,OAAO,MAAMK,mCAAmC,CAAC,EAAEL,yBAAyB,wBAAwB,CAAC,CAAA;AAErG,mCAAmC;AACnC,OAAO,MAAMM,6BAA6B;IAAC;IAAc;CAAyB,CAAS;AAE3F,eAAe;AACf,OAAO,MAAMC,8BAA8B,CAAC,WAAW,CAAC,CAAA;AACxD,OAAO,MAAMC,iCAAiC,CAAC,wBAAwB,CAAC,CAAA;AAExE,OAAO,MAAMC,qBAAqB;IAChC;IACA;IACA;IACA;IACAZ;IACAC;CACD,CAAA"}
@@ -1,4 +1,3 @@
1
- import * as process from 'node:process';
2
1
  import { PLUGIN_AI_JOBS_TABLE, PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK, PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js';
3
2
  import { registerEditorHelper } from '../libraries/handlebars/helpers.js';
4
3
  import { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js';
@@ -10,6 +9,7 @@ import { extractImageData } from '../utilities/images/extractImageData.js';
10
9
  import { fetchImages } from '../utilities/images/fetchImages.js';
11
10
  import { resolveImageReferences } from '../utilities/images/resolveImageReferences.js';
12
11
  import { lexicalToPromptTemplate } from '../utilities/lexical/lexicalToPromptTemplate.js';
12
+ import { resolveServerURL } from '../utilities/runtime/resolveServerURL.js';
13
13
  import { sanitizeLog } from '../utilities/sanitizeLog.js';
14
14
  /**
15
15
  * Image/video/audio upload generation endpoint handler.
@@ -139,7 +139,7 @@ import { sanitizeLog } from '../utilities/sanitizeLog.js';
139
139
  }), `— AI Plugin: Executing media generation`);
140
140
  }
141
141
  // Prepare callback URL for async jobs
142
- const serverURL = req.payload.config?.serverURL || process.env.SERVER_URL || process.env.NEXT_PUBLIC_SERVER_URL;
142
+ const serverURL = resolveServerURL(req);
143
143
  const callbackUrl = serverURL ? `${serverURL.replace(/\/$/, '')}/api${PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK}?instructionId=${instructionId}` : undefined;
144
144
  const modelId = instructions['model-id'];
145
145
  const aiSettings = await req.payload.findGlobal({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoints/upload.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { Field, PayloadRequest } from 'payload'\n\nimport * as process from 'node:process'\n\nimport type { PluginConfig } from '../types.js'\n\nimport { checkAccess } from '../access/checkAccess.js'\nimport {\n PLUGIN_AI_JOBS_TABLE,\n PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK,\n PLUGIN_INSTRUCTIONS_TABLE,\n} from '../defaults.js'\nimport { registerEditorHelper } from '../libraries/handlebars/helpers.js'\nimport { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js'\nimport { resolveEffectiveInstructionSettings } from '../utilities/ai/resolveEffectiveInstructionSettings.js'\nimport { extendContextWithPromptFields } from '../utilities/buildPromptUtils.js'\nimport { buildSmartPrompt, isGenericPrompt } from '../utilities/buildSmartPrompt.js'\nimport { getFieldBySchemaPath } from '../utilities/fields/getFieldBySchemaPath.js'\nimport { extractImageData } from '../utilities/images/extractImageData.js'\nimport { type FetchableImage, fetchImages } from '../utilities/images/fetchImages.js'\nimport { resolveImageReferences } from '../utilities/images/resolveImageReferences.js'\nimport { lexicalToPromptTemplate } from '../utilities/lexical/lexicalToPromptTemplate.js'\nimport { sanitizeLog } from '../utilities/sanitizeLog.js'\n\n/**\n * Image/video/audio upload generation endpoint handler.\n * Uses payload.ai.generateMedia for media generation.\n */\nexport const uploadHandler = (pluginConfig: PluginConfig) => 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 as string,\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 ...docData,\n ...data.doc,\n }\n\n let instructions: Record<string, unknown> = { 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 let { prompt: promptTemplate = '' } = instructions\n\n // Convert Lexical JSON to string template if needed\n if (promptTemplate && typeof promptTemplate === 'object') {\n promptTemplate = lexicalToPromptTemplate(promptTemplate)\n }\n\n const { images: sampleImages = [] } = instructions\n const schemaPath = String(instructions['schema-path'])\n registerEditorHelper(req.payload, schemaPath)\n\n // Smart fallback: if prompt is generic, build a contextual prompt from field metadata\n if (isGenericPrompt(promptTemplate as string)) {\n promptTemplate = buildSmartPrompt({\n documentData: contextData,\n payload: req.payload,\n schemaPath,\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n { smartPrompt: promptTemplate },\n `— AI Plugin: Using smart fallback prompt for ${schemaPath}`,\n )\n }\n }\n\n const extendedContext = extendContextWithPromptFields(\n contextData,\n { type: String(instructions['field-type']), collection: collectionSlug },\n pluginConfig,\n )\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog({\n contextDataKeys: Object.keys(contextData),\n contextDataSample: Object.fromEntries(\n Object.entries(contextData).map(([k, v]) => [\n k,\n typeof v === 'object' ? `[object]` : v,\n ]),\n ),\n promptTemplate,\n }),\n `— AI Plugin: DEBUG upload context before replacePlaceholders`,\n )\n }\n\n const text = await replacePlaceholders(promptTemplate as string, extendedContext)\n const uploadCollectionSlug = instructions['relation-to']\n\n // Resolve @field:filename references from the prompt\n const { images: resolvedImages, processedPrompt } = await resolveImageReferences(\n text,\n contextData,\n req,\n collectionSlug,\n )\n\n // Extract hardcoded URLs from the processed prompt and merge with resolved images and sample images\n const images = [\n ...extractImageData(processedPrompt),\n ...resolvedImages,\n ...(sampleImages as unknown[]),\n ] as FetchableImage[]\n\n // Process images - convert to ImagePart format using helper\n const editImages: ImagePart[] = await fetchImages(req, images)\n\n let promptToUse = processedPrompt\n let targetField: Field | null | undefined\n\n try {\n const targetCollection = req.payload.config.collections.find((c) => c.slug === collectionSlug)\n if (targetCollection && schemaPath) {\n targetField = getFieldBySchemaPath(targetCollection, schemaPath)\n }\n } catch (e) {\n req.payload.logger.error(e, '— AI Plugin: Error finding field for hooks')\n }\n\n if (targetField && (targetField as any).custom?.ai?.beforeGenerate) {\n const beforeHooks = (targetField as any).custom.ai.beforeGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of beforeHooks) {\n const result = await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n prompt: promptToUse,\n req,\n })\n\n if (result) {\n if (result.prompt) {\n promptToUse = result.prompt\n }\n if (result.instructions) {\n instructions = {\n ...instructions,\n ...result.instructions,\n }\n }\n }\n }\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(sanitizeLog({ text: promptToUse }), `— AI Plugin: Executing media generation`)\n }\n\n // Prepare callback URL for async jobs\n const serverURL =\n req.payload.config?.serverURL || process.env.SERVER_URL || process.env.NEXT_PUBLIC_SERVER_URL\n\n const callbackUrl = serverURL\n ? `${serverURL.replace(/\\/$/, '')}/api${PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK}?instructionId=${instructionId}`\n : undefined\n\n const modelId = instructions['model-id']\n const aiSettings = await req.payload.findGlobal({\n slug: 'ai-providers',\n context: { unsafe: true },\n })\n const { effectiveSettings: modelSettings, settingsName } = resolveEffectiveInstructionSettings({\n defaults: aiSettings?.defaults as Record<string, unknown> | undefined,\n instructions,\n })\n\n if (!settingsName) {\n throw new Error(`Unsupported model-id: ${modelId}`)\n }\n\n const generateParams = {\n callbackUrl,\n images: editImages,\n instructionId,\n model: modelSettings.model as string,\n prompt: promptToUse,\n provider: modelSettings.provider as string,\n providerOptions: modelSettings,\n ...modelSettings,\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog(generateParams),\n '— AI Plugin: Final generation parameters for media',\n )\n }\n\n // Use payload.ai.generateMedia directly! 🎉\n const result = await req.payload.ai.generateMedia(generateParams)\n\n if (targetField && (targetField as any).custom?.ai?.afterGenerate) {\n const afterHooks = (targetField as any).custom.ai.afterGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of afterHooks) {\n await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n req,\n result,\n })\n }\n }\n\n // If model returned files immediately, proceed with upload\n if (result && 'files' in result && Array.isArray(result.files) && result.files.length > 0) {\n const uploadedDocs: Array<{ alt?: string; id: number | string }> = []\n\n for (const file of result.files) {\n let assetData: { alt?: string; id: number | string }\n\n // Create a synthetic result for the single file to pass to mediaUpload\n const singleFileResult = {\n files: [file],\n }\n\n if (typeof pluginConfig.mediaUpload === 'function') {\n const uploadResult = await pluginConfig.mediaUpload(singleFileResult, {\n collection: uploadCollectionSlug as string,\n request: req,\n })\n assetData = { id: uploadResult.id, alt: (uploadResult as any).alt }\n } else {\n const created = await req.payload.create({\n collection: uploadCollectionSlug as string,\n data: { alt: text },\n file, // Pass the file object directly: { data, mimetype, name, size }\n req, // Pass req to ensure access control is applied\n })\n assetData = { id: created.id, alt: created.alt as string }\n }\n\n if (assetData.id) {\n uploadedDocs.push(assetData)\n }\n }\n\n if (uploadedDocs.length === 0) {\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 // Check if target field supports multiple values\n let hasMany = false\n if (targetField) {\n if (\n targetField.type === 'relationship' ||\n targetField.type === 'upload' ||\n targetField.type === 'select'\n ) {\n hasMany = (targetField as any).hasMany === true\n }\n }\n\n if (hasMany) {\n return new Response(\n JSON.stringify({\n result: uploadedDocs.map((d) => ({\n id: d.id,\n alt: d.alt,\n })),\n }),\n )\n }\n\n return new Response(\n JSON.stringify({\n result: {\n id: uploadedDocs[0].id,\n alt: uploadedDocs[0].alt,\n },\n }),\n )\n }\n\n // Otherwise, assume async job launch\n if (result && ('jobId' in result || 'taskId' in result)) {\n const externalTaskId = result.jobId || result.taskId\n const status = result.status || 'queued'\n const progress = result.progress ?? 0\n\n // Create AI Job doc and return only its id\n const createdJob = await req.payload.create({\n collection: PLUGIN_AI_JOBS_TABLE,\n data: {\n instructionId,\n progress,\n status,\n task_id: externalTaskId,\n },\n overrideAccess: true,\n req,\n })\n\n return new Response(JSON.stringify({ job: { id: createdJob.id } }), {\n headers: { 'Content-Type': 'application/json' },\n })\n }\n\n throw new Error('Unexpected model response.')\n } catch (error) {\n req.payload.logger.error(\n // @ts-expect-error\n error?.type || (error as Error).message,\n '— AI Plugin: Error generating media upload:',\n )\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as Error).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') || message.includes('Insufficient permissions')\n ? 401\n : 500,\n })\n }\n}\n"],"names":["process","PLUGIN_AI_JOBS_TABLE","PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK","PLUGIN_INSTRUCTIONS_TABLE","registerEditorHelper","replacePlaceholders","resolveEffectiveInstructionSettings","extendContextWithPromptFields","buildSmartPrompt","isGenericPrompt","getFieldBySchemaPath","extractImageData","fetchImages","resolveImageReferences","lexicalToPromptTemplate","sanitizeLog","uploadHandler","pluginConfig","req","data","json","collectionSlug","documentId","options","instructionId","docData","payload","findByID","id","collection","draft","e","logger","error","contextData","doc","instructions","images","prompt","promptTemplate","sampleImages","schemaPath","String","documentData","debugging","info","smartPrompt","extendedContext","type","contextDataKeys","Object","keys","contextDataSample","fromEntries","entries","map","k","v","text","uploadCollectionSlug","resolvedImages","processedPrompt","editImages","promptToUse","targetField","targetCollection","config","collections","find","c","slug","custom","ai","beforeGenerate","beforeHooks","hook","result","field","headers","serverURL","env","SERVER_URL","NEXT_PUBLIC_SERVER_URL","callbackUrl","replace","undefined","modelId","aiSettings","findGlobal","context","unsafe","effectiveSettings","modelSettings","settingsName","defaults","Error","generateParams","model","provider","providerOptions","generateMedia","afterGenerate","afterHooks","Array","isArray","files","length","uploadedDocs","file","assetData","singleFileResult","mediaUpload","uploadResult","request","alt","created","create","push","hasMany","Response","JSON","stringify","d","externalTaskId","jobId","taskId","status","progress","createdJob","task_id","overrideAccess","job","message","includes"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/endpoints/upload.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { Field, PayloadRequest } from 'payload'\n\nimport type { PluginConfig } from '../types.js'\n\nimport { checkAccess } from '../access/checkAccess.js'\nimport {\n PLUGIN_AI_JOBS_TABLE,\n PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK,\n PLUGIN_INSTRUCTIONS_TABLE,\n} from '../defaults.js'\nimport { registerEditorHelper } from '../libraries/handlebars/helpers.js'\nimport { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js'\nimport { resolveEffectiveInstructionSettings } from '../utilities/ai/resolveEffectiveInstructionSettings.js'\nimport { extendContextWithPromptFields } from '../utilities/buildPromptUtils.js'\nimport { buildSmartPrompt, isGenericPrompt } from '../utilities/buildSmartPrompt.js'\nimport { getFieldBySchemaPath } from '../utilities/fields/getFieldBySchemaPath.js'\nimport { extractImageData } from '../utilities/images/extractImageData.js'\nimport { type FetchableImage, fetchImages } from '../utilities/images/fetchImages.js'\nimport { resolveImageReferences } from '../utilities/images/resolveImageReferences.js'\nimport { lexicalToPromptTemplate } from '../utilities/lexical/lexicalToPromptTemplate.js'\nimport { resolveServerURL } from '../utilities/runtime/resolveServerURL.js'\nimport { sanitizeLog } from '../utilities/sanitizeLog.js'\n\n/**\n * Image/video/audio upload generation endpoint handler.\n * Uses payload.ai.generateMedia for media generation.\n */\nexport const uploadHandler = (pluginConfig: PluginConfig) => async (req: PayloadRequest) => {\n try {\n // Check authentication and authorization first\n // await checkAccess(req, pluginConfig)\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 as string,\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 ...docData,\n ...data.doc,\n }\n\n let instructions: Record<string, unknown> = { 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 let { prompt: promptTemplate = '' } = instructions\n\n // Convert Lexical JSON to string template if needed\n if (promptTemplate && typeof promptTemplate === 'object') {\n promptTemplate = lexicalToPromptTemplate(promptTemplate)\n }\n\n const { images: sampleImages = [] } = instructions\n const schemaPath = String(instructions['schema-path'])\n registerEditorHelper(req.payload, schemaPath)\n\n // Smart fallback: if prompt is generic, build a contextual prompt from field metadata\n if (isGenericPrompt(promptTemplate as string)) {\n promptTemplate = buildSmartPrompt({\n documentData: contextData,\n payload: req.payload,\n schemaPath,\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n { smartPrompt: promptTemplate },\n `— AI Plugin: Using smart fallback prompt for ${schemaPath}`,\n )\n }\n }\n\n const extendedContext = extendContextWithPromptFields(\n contextData,\n { type: String(instructions['field-type']), collection: collectionSlug },\n pluginConfig,\n )\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog({\n contextDataKeys: Object.keys(contextData),\n contextDataSample: Object.fromEntries(\n Object.entries(contextData).map(([k, v]) => [\n k,\n typeof v === 'object' ? `[object]` : v,\n ]),\n ),\n promptTemplate,\n }),\n `— AI Plugin: DEBUG upload context before replacePlaceholders`,\n )\n }\n\n const text = await replacePlaceholders(promptTemplate as string, extendedContext)\n const uploadCollectionSlug = instructions['relation-to']\n\n // Resolve @field:filename references from the prompt\n const { images: resolvedImages, processedPrompt } = await resolveImageReferences(\n text,\n contextData,\n req,\n collectionSlug,\n )\n\n // Extract hardcoded URLs from the processed prompt and merge with resolved images and sample images\n const images = [\n ...extractImageData(processedPrompt),\n ...resolvedImages,\n ...(sampleImages as unknown[]),\n ] as FetchableImage[]\n\n // Process images - convert to ImagePart format using helper\n const editImages: ImagePart[] = await fetchImages(req, images)\n\n let promptToUse = processedPrompt\n let targetField: Field | null | undefined\n\n try {\n const targetCollection = req.payload.config.collections.find((c) => c.slug === collectionSlug)\n if (targetCollection && schemaPath) {\n targetField = getFieldBySchemaPath(targetCollection, schemaPath)\n }\n } catch (e) {\n req.payload.logger.error(e, '— AI Plugin: Error finding field for hooks')\n }\n\n if (targetField && (targetField as any).custom?.ai?.beforeGenerate) {\n const beforeHooks = (targetField as any).custom.ai.beforeGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of beforeHooks) {\n const result = await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n prompt: promptToUse,\n req,\n })\n\n if (result) {\n if (result.prompt) {\n promptToUse = result.prompt\n }\n if (result.instructions) {\n instructions = {\n ...instructions,\n ...result.instructions,\n }\n }\n }\n }\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(sanitizeLog({ text: promptToUse }), `— AI Plugin: Executing media generation`)\n }\n\n // Prepare callback URL for async jobs\n const serverURL = resolveServerURL(req)\n\n const callbackUrl = serverURL\n ? `${serverURL.replace(/\\/$/, '')}/api${PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK}?instructionId=${instructionId}`\n : undefined\n\n const modelId = instructions['model-id']\n const aiSettings = await req.payload.findGlobal({\n slug: 'ai-providers',\n context: { unsafe: true },\n })\n const { effectiveSettings: modelSettings, settingsName } = resolveEffectiveInstructionSettings({\n defaults: aiSettings?.defaults as Record<string, unknown> | undefined,\n instructions,\n })\n\n if (!settingsName) {\n throw new Error(`Unsupported model-id: ${modelId}`)\n }\n\n const generateParams = {\n callbackUrl,\n images: editImages,\n instructionId,\n model: modelSettings.model as string,\n prompt: promptToUse,\n provider: modelSettings.provider as string,\n providerOptions: modelSettings,\n ...modelSettings,\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog(generateParams),\n '— AI Plugin: Final generation parameters for media',\n )\n }\n\n // Use payload.ai.generateMedia directly! 🎉\n const result = await req.payload.ai.generateMedia(generateParams)\n\n if (targetField && (targetField as any).custom?.ai?.afterGenerate) {\n const afterHooks = (targetField as any).custom.ai.afterGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of afterHooks) {\n await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n req,\n result,\n })\n }\n }\n\n // If model returned files immediately, proceed with upload\n if (result && 'files' in result && Array.isArray(result.files) && result.files.length > 0) {\n const uploadedDocs: Array<{ alt?: string; id: number | string }> = []\n\n for (const file of result.files) {\n let assetData: { alt?: string; id: number | string }\n\n // Create a synthetic result for the single file to pass to mediaUpload\n const singleFileResult = {\n files: [file],\n }\n\n if (typeof pluginConfig.mediaUpload === 'function') {\n const uploadResult = await pluginConfig.mediaUpload(singleFileResult, {\n collection: uploadCollectionSlug as string,\n request: req,\n })\n assetData = { id: uploadResult.id, alt: (uploadResult as any).alt }\n } else {\n const created = await req.payload.create({\n collection: uploadCollectionSlug as string,\n data: { alt: text },\n file, // Pass the file object directly: { data, mimetype, name, size }\n req, // Pass req to ensure access control is applied\n })\n assetData = { id: created.id, alt: created.alt as string }\n }\n\n if (assetData.id) {\n uploadedDocs.push(assetData)\n }\n }\n\n if (uploadedDocs.length === 0) {\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 // Check if target field supports multiple values\n let hasMany = false\n if (targetField) {\n if (\n targetField.type === 'relationship' ||\n targetField.type === 'upload' ||\n targetField.type === 'select'\n ) {\n hasMany = (targetField as any).hasMany === true\n }\n }\n\n if (hasMany) {\n return new Response(\n JSON.stringify({\n result: uploadedDocs.map((d) => ({\n id: d.id,\n alt: d.alt,\n })),\n }),\n )\n }\n\n return new Response(\n JSON.stringify({\n result: {\n id: uploadedDocs[0].id,\n alt: uploadedDocs[0].alt,\n },\n }),\n )\n }\n\n // Otherwise, assume async job launch\n if (result && ('jobId' in result || 'taskId' in result)) {\n const externalTaskId = result.jobId || result.taskId\n const status = result.status || 'queued'\n const progress = result.progress ?? 0\n\n // Create AI Job doc and return only its id\n const createdJob = await req.payload.create({\n collection: PLUGIN_AI_JOBS_TABLE,\n data: {\n instructionId,\n progress,\n status,\n task_id: externalTaskId,\n },\n overrideAccess: true,\n req,\n })\n\n return new Response(JSON.stringify({ job: { id: createdJob.id } }), {\n headers: { 'Content-Type': 'application/json' },\n })\n }\n\n throw new Error('Unexpected model response.')\n } catch (error) {\n req.payload.logger.error(\n // @ts-expect-error\n error?.type || (error as Error).message,\n '— AI Plugin: Error generating media upload:',\n )\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as Error).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') || message.includes('Insufficient permissions')\n ? 401\n : 500,\n })\n }\n}\n"],"names":["PLUGIN_AI_JOBS_TABLE","PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK","PLUGIN_INSTRUCTIONS_TABLE","registerEditorHelper","replacePlaceholders","resolveEffectiveInstructionSettings","extendContextWithPromptFields","buildSmartPrompt","isGenericPrompt","getFieldBySchemaPath","extractImageData","fetchImages","resolveImageReferences","lexicalToPromptTemplate","resolveServerURL","sanitizeLog","uploadHandler","pluginConfig","req","data","json","collectionSlug","documentId","options","instructionId","docData","payload","findByID","id","collection","draft","e","logger","error","contextData","doc","instructions","images","prompt","promptTemplate","sampleImages","schemaPath","String","documentData","debugging","info","smartPrompt","extendedContext","type","contextDataKeys","Object","keys","contextDataSample","fromEntries","entries","map","k","v","text","uploadCollectionSlug","resolvedImages","processedPrompt","editImages","promptToUse","targetField","targetCollection","config","collections","find","c","slug","custom","ai","beforeGenerate","beforeHooks","hook","result","field","headers","serverURL","callbackUrl","replace","undefined","modelId","aiSettings","findGlobal","context","unsafe","effectiveSettings","modelSettings","settingsName","defaults","Error","generateParams","model","provider","providerOptions","generateMedia","afterGenerate","afterHooks","Array","isArray","files","length","uploadedDocs","file","assetData","singleFileResult","mediaUpload","uploadResult","request","alt","created","create","push","hasMany","Response","JSON","stringify","d","externalTaskId","jobId","taskId","status","progress","createdJob","task_id","overrideAccess","job","message","includes"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -44,6 +44,11 @@ export interface PluginConfig {
44
44
  editorConfig?: {
45
45
  nodes: JSONSchema[];
46
46
  };
47
+ /**
48
+ * Optional runtime environment map for non-Node runtimes (Cloudflare Workers, Edge runtimes).
49
+ * Values in this map are checked before `process.env` during provider auto-setup.
50
+ */
51
+ env?: Partial<Record<string, string>>;
47
52
  fields?: Field[];
48
53
  /**
49
54
  * Defines default provider and models to be selected
@@ -69,6 +74,11 @@ export interface PluginConfig {
69
74
  };
70
75
  };
71
76
  generationModels?: ((defaultModels: GenerationModel[]) => GenerationModel[]) | GenerationModel[];
77
+ /**
78
+ * Optional runtime resolver for environment values.
79
+ * Resolution order is: `getEnv` -> `env` -> `process.env`.
80
+ */
81
+ getEnv?: (key: string) => string | undefined;
72
82
  globals?: {
73
83
  [key: GlobalConfig['slug']]: boolean;
74
84
  };
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { GenerateObjectResult, ModelMessage } from 'ai'\nimport 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'\n\nimport type { MediaResult } from './ai/core/index.js'\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: MediaResult,\n {\n collection,\n request,\n }: {\n collection: CollectionSlug\n request: PayloadRequest\n },\n) => Promise<DataFromCollectionSlug<CollectionSlug>>\n\nexport interface PluginConfig {\n /**\n * Access control configuration for AI features\n * By default, all AI features require authentication\n */\n access?: PluginConfigAccess\n debugging?: boolean\n disableSponsorMessage?: boolean\n editorConfig?: { nodes: JSONSchema[] }\n fields?: Field[]\n /**\n * Defines default provider and models to be selected\n * when creating initial database records for Generation Defaults.\n */\n generationDefaults?: {\n image?: { model: string; provider: string }\n text?: { model: string; provider: string }\n tts?: { model: string; provider: string; voice?: string }\n video?: { model: string; provider: string }\n }\n generationModels?: ((defaultModels: GenerationModel[]) => GenerationModel[]) | GenerationModel[]\n globals?: {\n [key: GlobalConfig['slug']]: boolean\n }\n interfaceName?: string\n mediaUpload?: PluginConfigMediaUploadFunction\n options?: PluginOptions\n overrideInstructions?: any\n promptFields?: any[]\n prompts?: ActionPrompt[]\n /**\n * Pre-configured options that get passed directly to AI SDK providers.\n * This allows devs to define AI options safely via payload.config.ts.\n */\n providerOptions?: {\n [key: string]: Record<string, any> | undefined // generic fallback\n anthropic?: Record<string, any>\n elevenlabs?: Record<string, any>\n fal?: Record<string, any>\n google?: Record<string, any>\n openai?: Record<string, any>\n }\n /**\n * Custom seed prompt function for generating field-specific prompts\n * If not provided, fields will have empty prompts by default\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) => File | 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 fetchVoices?: Omit<Endpoint, 'root'>\n promptMentions: Endpoint\n textarea: Omit<Endpoint, 'root'>\n upload: Omit<Endpoint, 'root'>\n videogenWebhook?: 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 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\nexport interface BeforeGenerateArgs<T = any> {\n doc: T\n field: Field\n headers: Record<string, string>\n instructions: Record<string, unknown> // The instruction document\n messages?: ModelMessage[]\n payload: PayloadRequest['payload']\n prompt: string\n req: PayloadRequest\n system: string\n}\n\nexport type BeforeGenerateResult = {\n messages?: ModelMessage[]\n prompt?: string\n system?: string\n} | void\n\nexport type BeforeGenerateHook<T = any> = (\n args: BeforeGenerateArgs<T>,\n) => BeforeGenerateResult | Promise<BeforeGenerateResult>\n\nexport interface AfterGenerateArgs<T = any> {\n doc: T\n field: Field\n headers: Record<string, string>\n instructions: Record<string, unknown>\n payload: PayloadRequest['payload']\n req: PayloadRequest\n result: GenerateObjectResult<any> | MediaResult | string // depends on context\n}\n\nexport type AfterGenerateHook<T = any> = (args: AfterGenerateArgs<T>) => Promise<void> | void\n\n// Add to PluginConfig or a new interface if accessed via custom.ai\nexport interface AIFieldConfig {\n [key: string]: unknown\n afterGenerate?: AfterGenerateHook[]\n /**\n * When true, the Compose button is always visible on this field,\n * bypassing the focus-based show/hide system.\n * Admin `disabled` in Instructions still takes priority.\n */\n alwaysShow?: boolean\n /**\n * When true and the field hasMany, generated values are appended\n * instead of replacing current field value(s).\n */\n appendGenerated?: boolean\n beforeGenerate?: BeforeGenerateHook[]\n /**\n * Default hidden state for Compose in instructions.\n * When true, Compose is hidden for this field.\n */\n disabled?: boolean\n /**\n * Set to false to opt-out of compose button injection for this field.\n * When false, no compose button is injected at build time.\n * @default true (compose is auto-injected on supported field types)\n */\n enabled?: boolean\n /** Custom prompt template for this field */\n prompt?: string\n /** Custom system prompt for this field */\n system?: string\n}\n"],"names":[],"mappings":"AA4PA,mEAAmE;AACnE,WA8BC"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { GenerateObjectResult, ModelMessage } from 'ai'\nimport 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'\n\nimport type { MediaResult } from './ai/core/index.js'\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: MediaResult,\n {\n collection,\n request,\n }: {\n collection: CollectionSlug\n request: PayloadRequest\n },\n) => Promise<DataFromCollectionSlug<CollectionSlug>>\n\nexport interface PluginConfig {\n /**\n * Access control configuration for AI features\n * By default, all AI features require authentication\n */\n access?: PluginConfigAccess\n debugging?: boolean\n disableSponsorMessage?: boolean\n editorConfig?: { nodes: JSONSchema[] }\n /**\n * Optional runtime environment map for non-Node runtimes (Cloudflare Workers, Edge runtimes).\n * Values in this map are checked before `process.env` during provider auto-setup.\n */\n env?: Partial<Record<string, string>>\n fields?: Field[]\n /**\n * Defines default provider and models to be selected\n * when creating initial database records for Generation Defaults.\n */\n generationDefaults?: {\n image?: { model: string; provider: string }\n text?: { model: string; provider: string }\n tts?: { model: string; provider: string; voice?: string }\n video?: { model: string; provider: string }\n }\n generationModels?: ((defaultModels: GenerationModel[]) => GenerationModel[]) | GenerationModel[]\n /**\n * Optional runtime resolver for environment values.\n * Resolution order is: `getEnv` -> `env` -> `process.env`.\n */\n getEnv?: (key: string) => string | undefined\n globals?: {\n [key: GlobalConfig['slug']]: boolean\n }\n interfaceName?: string\n mediaUpload?: PluginConfigMediaUploadFunction\n options?: PluginOptions\n overrideInstructions?: any\n promptFields?: any[]\n prompts?: ActionPrompt[]\n /**\n * Pre-configured options that get passed directly to AI SDK providers.\n * This allows devs to define AI options safely via payload.config.ts.\n */\n providerOptions?: {\n [key: string]: Record<string, any> | undefined // generic fallback\n anthropic?: Record<string, any>\n elevenlabs?: Record<string, any>\n fal?: Record<string, any>\n google?: Record<string, any>\n openai?: Record<string, any>\n }\n /**\n * Custom seed prompt function for generating field-specific prompts\n * If not provided, fields will have empty prompts by default\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) => File | 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 fetchVoices?: Omit<Endpoint, 'root'>\n promptMentions: Endpoint\n textarea: Omit<Endpoint, 'root'>\n upload: Omit<Endpoint, 'root'>\n videogenWebhook?: 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 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\nexport interface BeforeGenerateArgs<T = any> {\n doc: T\n field: Field\n headers: Record<string, string>\n instructions: Record<string, unknown> // The instruction document\n messages?: ModelMessage[]\n payload: PayloadRequest['payload']\n prompt: string\n req: PayloadRequest\n system: string\n}\n\nexport type BeforeGenerateResult = {\n messages?: ModelMessage[]\n prompt?: string\n system?: string\n} | void\n\nexport type BeforeGenerateHook<T = any> = (\n args: BeforeGenerateArgs<T>,\n) => BeforeGenerateResult | Promise<BeforeGenerateResult>\n\nexport interface AfterGenerateArgs<T = any> {\n doc: T\n field: Field\n headers: Record<string, string>\n instructions: Record<string, unknown>\n payload: PayloadRequest['payload']\n req: PayloadRequest\n result: GenerateObjectResult<any> | MediaResult | string // depends on context\n}\n\nexport type AfterGenerateHook<T = any> = (args: AfterGenerateArgs<T>) => Promise<void> | void\n\n// Add to PluginConfig or a new interface if accessed via custom.ai\nexport interface AIFieldConfig {\n [key: string]: unknown\n afterGenerate?: AfterGenerateHook[]\n /**\n * When true, the Compose button is always visible on this field,\n * bypassing the focus-based show/hide system.\n * Admin `disabled` in Instructions still takes priority.\n */\n alwaysShow?: boolean\n /**\n * When true and the field hasMany, generated values are appended\n * instead of replacing current field value(s).\n */\n appendGenerated?: boolean\n beforeGenerate?: BeforeGenerateHook[]\n /**\n * Default hidden state for Compose in instructions.\n * When true, Compose is hidden for this field.\n */\n disabled?: boolean\n /**\n * Set to false to opt-out of compose button injection for this field.\n * When false, no compose button is injected at build time.\n * @default true (compose is auto-injected on supported field types)\n */\n enabled?: boolean\n /** Custom prompt template for this field */\n prompt?: string\n /** Custom system prompt for this field */\n system?: string\n}\n"],"names":[],"mappings":"AAsQA,mEAAmE;AACnE,WA8BC"}
@@ -8,17 +8,16 @@ export function encrypt(text, secret) {
8
8
  if (!secret) {
9
9
  throw new Error('No secret provided for encryption');
10
10
  }
11
- // Ensure secret is 32 bytes
12
- const key = crypto.createHash('sha256').update(secret).digest();
11
+ // Cloudflare Workers' Node compatibility can require explicit UTF-8 handling.
12
+ const key = crypto.createHash('sha256').update(String(secret), 'utf8').digest();
13
13
  const iv = crypto.randomBytes(ivLength);
14
14
  const cipher = crypto.createCipheriv(algorithm, key, iv);
15
- let encrypted = cipher.update(text);
15
+ let encrypted = cipher.update(Buffer.from(String(text), 'utf8'));
16
16
  encrypted = Buffer.concat([
17
17
  encrypted,
18
18
  cipher.final()
19
19
  ]);
20
- const result = iv.toString('hex') + ':' + encrypted.toString('hex');
21
- return result;
20
+ return `${iv.toString('hex')}:${encrypted.toString('hex')}`;
22
21
  }
23
22
  export function decrypt(text, secret) {
24
23
  if (!text) {
@@ -29,17 +28,24 @@ export function decrypt(text, secret) {
29
28
  }
30
29
  try {
31
30
  const textParts = text.split(':');
32
- const iv = Buffer.from(textParts.shift(), 'hex');
31
+ const ivHex = textParts.shift();
32
+ if (!ivHex) {
33
+ return text;
34
+ }
35
+ const iv = Buffer.from(ivHex, 'hex');
36
+ if (iv.length !== ivLength) {
37
+ return text;
38
+ }
33
39
  const encryptedText = Buffer.from(textParts.join(':'), 'hex');
34
- const key = crypto.createHash('sha256').update(secret).digest();
40
+ const key = crypto.createHash('sha256').update(String(secret), 'utf8').digest();
35
41
  const decipher = crypto.createDecipheriv(algorithm, key, iv);
36
42
  let decrypted = decipher.update(encryptedText);
37
43
  decrypted = Buffer.concat([
38
44
  decrypted,
39
45
  decipher.final()
40
46
  ]);
41
- return decrypted.toString();
42
- } catch (e) {
47
+ return decrypted.toString('utf8');
48
+ } catch (_error) {
43
49
  // If decryption fails, return original text (might be already plain or invalid)
44
50
  return text;
45
51
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/encryption.ts"],"sourcesContent":["import crypto from 'crypto'\n\nconst algorithm = 'aes-256-cbc'\nconst ivLength = 16\n\nexport function encrypt(text: string, secret: string): string {\n if (!text) {\n return text\n }\n if (!secret) {\n throw new Error('No secret provided for encryption')\n }\n\n // Ensure secret is 32 bytes\n const key = crypto.createHash('sha256').update(secret).digest()\n const iv = crypto.randomBytes(ivLength)\n const cipher = crypto.createCipheriv(algorithm, key, iv)\n let encrypted = cipher.update(text)\n encrypted = Buffer.concat([encrypted, cipher.final()])\n const result = iv.toString('hex') + ':' + encrypted.toString('hex')\n\n return result\n}\n\nexport function decrypt(text: string, secret: string): string {\n if (!text) {\n return text\n }\n if (!secret) {\n throw new Error('No secret provided for decryption')\n }\n\n try {\n const textParts = text.split(':')\n const iv = Buffer.from(textParts.shift()!, 'hex')\n const encryptedText = Buffer.from(textParts.join(':'), 'hex')\n const key = crypto.createHash('sha256').update(secret).digest()\n const decipher = crypto.createDecipheriv(algorithm, key, iv)\n let decrypted = decipher.update(encryptedText)\n decrypted = Buffer.concat([decrypted, decipher.final()])\n return decrypted.toString()\n } catch (e) {\n // If decryption fails, return original text (might be already plain or invalid)\n return text\n }\n}\n"],"names":["crypto","algorithm","ivLength","encrypt","text","secret","Error","key","createHash","update","digest","iv","randomBytes","cipher","createCipheriv","encrypted","Buffer","concat","final","result","toString","decrypt","textParts","split","from","shift","encryptedText","join","decipher","createDecipheriv","decrypted","e"],"mappings":"AAAA,OAAOA,YAAY,SAAQ;AAE3B,MAAMC,YAAY;AAClB,MAAMC,WAAW;AAEjB,OAAO,SAASC,QAAQC,IAAY,EAAEC,MAAc;IAClD,IAAI,CAACD,MAAM;QACT,OAAOA;IACT;IACA,IAAI,CAACC,QAAQ;QACX,MAAM,IAAIC,MAAM;IAClB;IAEA,4BAA4B;IAC5B,MAAMC,MAAMP,OAAOQ,UAAU,CAAC,UAAUC,MAAM,CAACJ,QAAQK,MAAM;IAC7D,MAAMC,KAAKX,OAAOY,WAAW,CAACV;IAC9B,MAAMW,SAASb,OAAOc,cAAc,CAACb,WAAWM,KAAKI;IACrD,IAAII,YAAYF,OAAOJ,MAAM,CAACL;IAC9BW,YAAYC,OAAOC,MAAM,CAAC;QAACF;QAAWF,OAAOK,KAAK;KAAG;IACrD,MAAMC,SAASR,GAAGS,QAAQ,CAAC,SAAS,MAAML,UAAUK,QAAQ,CAAC;IAE7D,OAAOD;AACT;AAEA,OAAO,SAASE,QAAQjB,IAAY,EAAEC,MAAc;IAClD,IAAI,CAACD,MAAM;QACT,OAAOA;IACT;IACA,IAAI,CAACC,QAAQ;QACX,MAAM,IAAIC,MAAM;IAClB;IAEA,IAAI;QACF,MAAMgB,YAAYlB,KAAKmB,KAAK,CAAC;QAC7B,MAAMZ,KAAKK,OAAOQ,IAAI,CAACF,UAAUG,KAAK,IAAK;QAC3C,MAAMC,gBAAgBV,OAAOQ,IAAI,CAACF,UAAUK,IAAI,CAAC,MAAM;QACvD,MAAMpB,MAAMP,OAAOQ,UAAU,CAAC,UAAUC,MAAM,CAACJ,QAAQK,MAAM;QAC7D,MAAMkB,WAAW5B,OAAO6B,gBAAgB,CAAC5B,WAAWM,KAAKI;QACzD,IAAImB,YAAYF,SAASnB,MAAM,CAACiB;QAChCI,YAAYd,OAAOC,MAAM,CAAC;YAACa;YAAWF,SAASV,KAAK;SAAG;QACvD,OAAOY,UAAUV,QAAQ;IAC3B,EAAE,OAAOW,GAAG;QACV,gFAAgF;QAChF,OAAO3B;IACT;AACF"}
1
+ {"version":3,"sources":["../../src/utilities/encryption.ts"],"sourcesContent":["import crypto from 'crypto'\n\nconst algorithm = 'aes-256-cbc'\nconst ivLength = 16\n\nexport function encrypt(text: string, secret: string): string {\n if (!text) {\n return text\n }\n if (!secret) {\n throw new Error('No secret provided for encryption')\n }\n\n // Cloudflare Workers' Node compatibility can require explicit UTF-8 handling.\n const key = crypto.createHash('sha256').update(String(secret), 'utf8').digest()\n const iv = crypto.randomBytes(ivLength)\n const cipher = crypto.createCipheriv(algorithm, key, iv)\n let encrypted = cipher.update(Buffer.from(String(text), 'utf8'))\n encrypted = Buffer.concat([encrypted, cipher.final()])\n\n return `${iv.toString('hex')}:${encrypted.toString('hex')}`\n}\n\nexport function decrypt(text: string, secret: string): string {\n if (!text) {\n return text\n }\n if (!secret) {\n throw new Error('No secret provided for decryption')\n }\n\n try {\n const textParts = text.split(':')\n const ivHex = textParts.shift()\n if (!ivHex) {\n return text\n }\n\n const iv = Buffer.from(ivHex, 'hex')\n if (iv.length !== ivLength) {\n return text\n }\n\n const encryptedText = Buffer.from(textParts.join(':'), 'hex')\n const key = crypto.createHash('sha256').update(String(secret), 'utf8').digest()\n const decipher = crypto.createDecipheriv(algorithm, key, iv)\n let decrypted = decipher.update(encryptedText)\n decrypted = Buffer.concat([decrypted, decipher.final()])\n\n return decrypted.toString('utf8')\n } catch (_error) {\n // If decryption fails, return original text (might be already plain or invalid)\n return text\n }\n}\n"],"names":["crypto","algorithm","ivLength","encrypt","text","secret","Error","key","createHash","update","String","digest","iv","randomBytes","cipher","createCipheriv","encrypted","Buffer","from","concat","final","toString","decrypt","textParts","split","ivHex","shift","length","encryptedText","join","decipher","createDecipheriv","decrypted","_error"],"mappings":"AAAA,OAAOA,YAAY,SAAQ;AAE3B,MAAMC,YAAY;AAClB,MAAMC,WAAW;AAEjB,OAAO,SAASC,QAAQC,IAAY,EAAEC,MAAc;IAClD,IAAI,CAACD,MAAM;QACT,OAAOA;IACT;IACA,IAAI,CAACC,QAAQ;QACX,MAAM,IAAIC,MAAM;IAClB;IAEA,8EAA8E;IAC9E,MAAMC,MAAMP,OAAOQ,UAAU,CAAC,UAAUC,MAAM,CAACC,OAAOL,SAAS,QAAQM,MAAM;IAC7E,MAAMC,KAAKZ,OAAOa,WAAW,CAACX;IAC9B,MAAMY,SAASd,OAAOe,cAAc,CAACd,WAAWM,KAAKK;IACrD,IAAII,YAAYF,OAAOL,MAAM,CAACQ,OAAOC,IAAI,CAACR,OAAON,OAAO;IACxDY,YAAYC,OAAOE,MAAM,CAAC;QAACH;QAAWF,OAAOM,KAAK;KAAG;IAErD,OAAO,CAAC,EAAER,GAAGS,QAAQ,CAAC,OAAO,CAAC,EAAEL,UAAUK,QAAQ,CAAC,OAAO,CAAC;AAC7D;AAEA,OAAO,SAASC,QAAQlB,IAAY,EAAEC,MAAc;IAClD,IAAI,CAACD,MAAM;QACT,OAAOA;IACT;IACA,IAAI,CAACC,QAAQ;QACX,MAAM,IAAIC,MAAM;IAClB;IAEA,IAAI;QACF,MAAMiB,YAAYnB,KAAKoB,KAAK,CAAC;QAC7B,MAAMC,QAAQF,UAAUG,KAAK;QAC7B,IAAI,CAACD,OAAO;YACV,OAAOrB;QACT;QAEA,MAAMQ,KAAKK,OAAOC,IAAI,CAACO,OAAO;QAC9B,IAAIb,GAAGe,MAAM,KAAKzB,UAAU;YAC1B,OAAOE;QACT;QAEA,MAAMwB,gBAAgBX,OAAOC,IAAI,CAACK,UAAUM,IAAI,CAAC,MAAM;QACvD,MAAMtB,MAAMP,OAAOQ,UAAU,CAAC,UAAUC,MAAM,CAACC,OAAOL,SAAS,QAAQM,MAAM;QAC7E,MAAMmB,WAAW9B,OAAO+B,gBAAgB,CAAC9B,WAAWM,KAAKK;QACzD,IAAIoB,YAAYF,SAASrB,MAAM,CAACmB;QAChCI,YAAYf,OAAOE,MAAM,CAAC;YAACa;YAAWF,SAASV,KAAK;SAAG;QAEvD,OAAOY,UAAUX,QAAQ,CAAC;IAC5B,EAAE,OAAOY,QAAQ;QACf,gFAAgF;QAChF,OAAO7B;IACT;AACF"}
@@ -1,12 +1,8 @@
1
- import * as process from 'node:process';
1
+ import { resolveAbsoluteURL } from '../runtime/resolveServerURL.js';
2
2
  /**
3
3
  * Fetch a single image and convert to an AI SDK ImagePart.
4
4
  */ async function fetchSingleImage(req, img) {
5
- const serverURL = req.payload.config?.serverURL || process.env.SERVER_URL || process.env.NEXT_PUBLIC_SERVER_URL;
6
- let url = img.image.thumbnailURL || img.image.url;
7
- if (!url.startsWith('http')) {
8
- url = `${String(serverURL)}${String(url)}`;
9
- }
5
+ const url = resolveAbsoluteURL(img.image.thumbnailURL || img.image.url, req);
10
6
  const response = await fetch(url, {
11
7
  headers: {
12
8
  Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utilities/images/fetchImages.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { PayloadRequest } from 'payload'\n\nimport * as process from 'node:process'\n\nexport interface FetchableImage {\n image: {\n mimeType?: string\n thumbnailURL?: string\n url: string\n }\n}\n\n/**\n * Fetch a single image and convert to an AI SDK ImagePart.\n */\nasync function fetchSingleImage(\n req: PayloadRequest,\n img: FetchableImage,\n): Promise<ImagePart> {\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 = `${String(serverURL)}${String(url)}`\n }\n\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`,\n },\n method: 'GET',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch image: ${response.statusText}`)\n }\n\n const blob = await response.blob()\n const arrayBuffer = await blob.arrayBuffer()\n\n return {\n type: 'image',\n image: arrayBuffer,\n mediaType: img.image.mimeType || blob.type || 'image/png',\n }\n}\n\n/**\n * Fetches images in parallel from a list of objects containing URLs\n * and converts them to AI SDK compatible ImageParts.\n */\nexport async function fetchImages(\n req: PayloadRequest,\n images: FetchableImage[],\n): Promise<ImagePart[]> {\n if (images.length === 0) {\n return []\n }\n\n const results = await Promise.allSettled(\n images.map((img) => fetchSingleImage(req, img)),\n )\n\n const imageParts: ImagePart[] = []\n for (const result of results) {\n if (result.status === 'fulfilled') {\n imageParts.push(result.value)\n } else {\n req.payload.logger.error(result.reason, '— AI Plugin: Error fetching reference image')\n }\n }\n\n if (imageParts.length === 0 && images.length > 0) {\n throw new Error(\n \"We couldn't fetch any of the images. Please ensure the images are accessible and hosted publicly.\",\n )\n }\n\n return imageParts\n}\n"],"names":["process","fetchSingleImage","req","img","serverURL","payload","config","env","SERVER_URL","NEXT_PUBLIC_SERVER_URL","url","image","thumbnailURL","startsWith","String","response","fetch","headers","Authorization","get","split","method","ok","Error","statusText","blob","arrayBuffer","type","mediaType","mimeType","fetchImages","images","length","results","Promise","allSettled","map","imageParts","result","status","push","value","logger","error","reason"],"mappings":"AAGA,YAAYA,aAAa,eAAc;AAUvC;;CAEC,GACD,eAAeC,iBACbC,GAAmB,EACnBC,GAAmB;IAEnB,MAAMC,YACJF,IAAIG,OAAO,CAACC,MAAM,EAAEF,aACpBJ,QAAQO,GAAG,CAACC,UAAU,IACtBR,QAAQO,GAAG,CAACE,sBAAsB;IAEpC,IAAIC,MAAMP,IAAIQ,KAAK,CAACC,YAAY,IAAIT,IAAIQ,KAAK,CAACD,GAAG;IACjD,IAAI,CAACA,IAAIG,UAAU,CAAC,SAAS;QAC3BH,MAAM,CAAC,EAAEI,OAAOV,WAAW,EAAEU,OAAOJ,KAAK,CAAC;IAC5C;IAEA,MAAMK,WAAW,MAAMC,MAAMN,KAAK;QAChCO,SAAS;YACPC,eAAe,CAAC,OAAO,EAAEhB,IAAIe,OAAO,CAACE,GAAG,CAAC,kBAAkBC,MAAM,UAAU,CAAC,EAAE,IAAI,GAAG,CAAC;QACxF;QACAC,QAAQ;IACV;IAEA,IAAI,CAACN,SAASO,EAAE,EAAE;QAChB,MAAM,IAAIC,MAAM,CAAC,uBAAuB,EAAER,SAASS,UAAU,CAAC,CAAC;IACjE;IAEA,MAAMC,OAAO,MAAMV,SAASU,IAAI;IAChC,MAAMC,cAAc,MAAMD,KAAKC,WAAW;IAE1C,OAAO;QACLC,MAAM;QACNhB,OAAOe;QACPE,WAAWzB,IAAIQ,KAAK,CAACkB,QAAQ,IAAIJ,KAAKE,IAAI,IAAI;IAChD;AACF;AAEA;;;CAGC,GACD,OAAO,eAAeG,YACpB5B,GAAmB,EACnB6B,MAAwB;IAExB,IAAIA,OAAOC,MAAM,KAAK,GAAG;QACvB,OAAO,EAAE;IACX;IAEA,MAAMC,UAAU,MAAMC,QAAQC,UAAU,CACtCJ,OAAOK,GAAG,CAAC,CAACjC,MAAQF,iBAAiBC,KAAKC;IAG5C,MAAMkC,aAA0B,EAAE;IAClC,KAAK,MAAMC,UAAUL,QAAS;QAC5B,IAAIK,OAAOC,MAAM,KAAK,aAAa;YACjCF,WAAWG,IAAI,CAACF,OAAOG,KAAK;QAC9B,OAAO;YACLvC,IAAIG,OAAO,CAACqC,MAAM,CAACC,KAAK,CAACL,OAAOM,MAAM,EAAE;QAC1C;IACF;IAEA,IAAIP,WAAWL,MAAM,KAAK,KAAKD,OAAOC,MAAM,GAAG,GAAG;QAChD,MAAM,IAAIT,MACR;IAEJ;IAEA,OAAOc;AACT"}
1
+ {"version":3,"sources":["../../../src/utilities/images/fetchImages.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { PayloadRequest } from 'payload'\n\nimport { resolveAbsoluteURL } from '../runtime/resolveServerURL.js'\n\nexport interface FetchableImage {\n image: {\n mimeType?: string\n thumbnailURL?: string\n url: string\n }\n}\n\n/**\n * Fetch a single image and convert to an AI SDK ImagePart.\n */\nasync function fetchSingleImage(\n req: PayloadRequest,\n img: FetchableImage,\n): Promise<ImagePart> {\n const url = resolveAbsoluteURL(img.image.thumbnailURL || img.image.url, req)\n\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`,\n },\n method: 'GET',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch image: ${response.statusText}`)\n }\n\n const blob = await response.blob()\n const arrayBuffer = await blob.arrayBuffer()\n\n return {\n type: 'image',\n image: arrayBuffer,\n mediaType: img.image.mimeType || blob.type || 'image/png',\n }\n}\n\n/**\n * Fetches images in parallel from a list of objects containing URLs\n * and converts them to AI SDK compatible ImageParts.\n */\nexport async function fetchImages(\n req: PayloadRequest,\n images: FetchableImage[],\n): Promise<ImagePart[]> {\n if (images.length === 0) {\n return []\n }\n\n const results = await Promise.allSettled(\n images.map((img) => fetchSingleImage(req, img)),\n )\n\n const imageParts: ImagePart[] = []\n for (const result of results) {\n if (result.status === 'fulfilled') {\n imageParts.push(result.value)\n } else {\n req.payload.logger.error(result.reason, '— AI Plugin: Error fetching reference image')\n }\n }\n\n if (imageParts.length === 0 && images.length > 0) {\n throw new Error(\n \"We couldn't fetch any of the images. Please ensure the images are accessible and hosted publicly.\",\n )\n }\n\n return imageParts\n}\n"],"names":["resolveAbsoluteURL","fetchSingleImage","req","img","url","image","thumbnailURL","response","fetch","headers","Authorization","get","split","method","ok","Error","statusText","blob","arrayBuffer","type","mediaType","mimeType","fetchImages","images","length","results","Promise","allSettled","map","imageParts","result","status","push","value","payload","logger","error","reason"],"mappings":"AAGA,SAASA,kBAAkB,QAAQ,iCAAgC;AAUnE;;CAEC,GACD,eAAeC,iBACbC,GAAmB,EACnBC,GAAmB;IAEnB,MAAMC,MAAMJ,mBAAmBG,IAAIE,KAAK,CAACC,YAAY,IAAIH,IAAIE,KAAK,CAACD,GAAG,EAAEF;IAExE,MAAMK,WAAW,MAAMC,MAAMJ,KAAK;QAChCK,SAAS;YACPC,eAAe,CAAC,OAAO,EAAER,IAAIO,OAAO,CAACE,GAAG,CAAC,kBAAkBC,MAAM,UAAU,CAAC,EAAE,IAAI,GAAG,CAAC;QACxF;QACAC,QAAQ;IACV;IAEA,IAAI,CAACN,SAASO,EAAE,EAAE;QAChB,MAAM,IAAIC,MAAM,CAAC,uBAAuB,EAAER,SAASS,UAAU,CAAC,CAAC;IACjE;IAEA,MAAMC,OAAO,MAAMV,SAASU,IAAI;IAChC,MAAMC,cAAc,MAAMD,KAAKC,WAAW;IAE1C,OAAO;QACLC,MAAM;QACNd,OAAOa;QACPE,WAAWjB,IAAIE,KAAK,CAACgB,QAAQ,IAAIJ,KAAKE,IAAI,IAAI;IAChD;AACF;AAEA;;;CAGC,GACD,OAAO,eAAeG,YACpBpB,GAAmB,EACnBqB,MAAwB;IAExB,IAAIA,OAAOC,MAAM,KAAK,GAAG;QACvB,OAAO,EAAE;IACX;IAEA,MAAMC,UAAU,MAAMC,QAAQC,UAAU,CACtCJ,OAAOK,GAAG,CAAC,CAACzB,MAAQF,iBAAiBC,KAAKC;IAG5C,MAAM0B,aAA0B,EAAE;IAClC,KAAK,MAAMC,UAAUL,QAAS;QAC5B,IAAIK,OAAOC,MAAM,KAAK,aAAa;YACjCF,WAAWG,IAAI,CAACF,OAAOG,KAAK;QAC9B,OAAO;YACL/B,IAAIgC,OAAO,CAACC,MAAM,CAACC,KAAK,CAACN,OAAOO,MAAM,EAAE;QAC1C;IACF;IAEA,IAAIR,WAAWL,MAAM,KAAK,KAAKD,OAAOC,MAAM,GAAG,GAAG;QAChD,MAAM,IAAIT,MACR;IAEJ;IAEA,OAAOc;AACT"}
@@ -45,6 +45,21 @@ const providerKeys = {
45
45
  };
46
46
  export const autoSetupProviders = async (payload, config)=>{
47
47
  try {
48
+ const getEnvValue = (key)=>{
49
+ const fromResolver = config.getEnv?.(key);
50
+ if (typeof fromResolver === 'string' && fromResolver.length > 0) {
51
+ return fromResolver;
52
+ }
53
+ const fromMap = config.env?.[key];
54
+ if (typeof fromMap === 'string' && fromMap.length > 0) {
55
+ return fromMap;
56
+ }
57
+ const fromProcessEnv = process.env[key];
58
+ if (typeof fromProcessEnv === 'string' && fromProcessEnv.length > 0) {
59
+ return fromProcessEnv;
60
+ }
61
+ return undefined;
62
+ };
48
63
  const existing = await payload.findGlobal({
49
64
  slug: 'ai-providers'
50
65
  });
@@ -71,11 +86,12 @@ export const autoSetupProviders = async (payload, config)=>{
71
86
  };
72
87
  const { providerOptions } = config;
73
88
  // OpenAI Setup
74
- if (process.env[providerKeys.openai]) {
89
+ const openaiKey = getEnvValue(providerKeys.openai);
90
+ if (openaiKey) {
75
91
  const isAlreadyConfigured = existing.providers?.find((p)=>p.blockType === 'openai');
76
92
  if (!isAlreadyConfigured) {
77
93
  providersArray.push({
78
- apiKey: process.env[providerKeys.openai],
94
+ apiKey: openaiKey,
79
95
  blockType: 'openai',
80
96
  enabled: true,
81
97
  models: findModelsDefault(openaiBlock)
@@ -84,7 +100,7 @@ export const autoSetupProviders = async (payload, config)=>{
84
100
  }
85
101
  }
86
102
  // Google Setup
87
- const googleKey = process.env[providerKeys.google[0]] || process.env[providerKeys.google[1]];
103
+ const googleKey = getEnvValue(providerKeys.google[0]) || getEnvValue(providerKeys.google[1]);
88
104
  if (googleKey) {
89
105
  const isAlreadyConfigured = existing.providers?.find((p)=>p.blockType === 'google');
90
106
  if (!isAlreadyConfigured) {
@@ -98,11 +114,12 @@ export const autoSetupProviders = async (payload, config)=>{
98
114
  }
99
115
  }
100
116
  // Anthropic Setup
101
- if (process.env[providerKeys.anthropic]) {
117
+ const anthropicKey = getEnvValue(providerKeys.anthropic);
118
+ if (anthropicKey) {
102
119
  const isAlreadyConfigured = existing.providers?.find((p)=>p.blockType === 'anthropic');
103
120
  if (!isAlreadyConfigured) {
104
121
  providersArray.push({
105
- apiKey: process.env[providerKeys.anthropic],
122
+ apiKey: anthropicKey,
106
123
  blockType: 'anthropic',
107
124
  enabled: true,
108
125
  models: findModelsDefault(anthropicBlock)
@@ -111,11 +128,12 @@ export const autoSetupProviders = async (payload, config)=>{
111
128
  }
112
129
  }
113
130
  // ElevenLabs Setup
114
- if (process.env[providerKeys.elevenlabs]) {
131
+ const elevenlabsKey = getEnvValue(providerKeys.elevenlabs);
132
+ if (elevenlabsKey) {
115
133
  const isAlreadyConfigured = existing.providers?.find((p)=>p.blockType === 'elevenlabs');
116
134
  if (!isAlreadyConfigured) {
117
135
  providersArray.push({
118
- apiKey: process.env[providerKeys.elevenlabs],
136
+ apiKey: elevenlabsKey,
119
137
  blockType: 'elevenlabs',
120
138
  enabled: true,
121
139
  models: findModelsDefault(elevenlabsBlock)
@@ -124,11 +142,12 @@ export const autoSetupProviders = async (payload, config)=>{
124
142
  }
125
143
  }
126
144
  // XAI Setup
127
- if (process.env[providerKeys.xai]) {
145
+ const xaiKey = getEnvValue(providerKeys.xai);
146
+ if (xaiKey) {
128
147
  const isAlreadyConfigured = existing.providers?.find((p)=>p.blockType === 'xai');
129
148
  if (!isAlreadyConfigured) {
130
149
  providersArray.push({
131
- apiKey: process.env[providerKeys.xai],
150
+ apiKey: xaiKey,
132
151
  blockType: 'xai',
133
152
  enabled: true,
134
153
  models: findModelsDefault(xaiBlock)
@@ -137,11 +156,12 @@ export const autoSetupProviders = async (payload, config)=>{
137
156
  }
138
157
  }
139
158
  // Fal Setup
140
- if (process.env[providerKeys.fal]) {
159
+ const falKey = getEnvValue(providerKeys.fal);
160
+ if (falKey) {
141
161
  const isAlreadyConfigured = existing.providers?.find((p)=>p.blockType === 'fal');
142
162
  if (!isAlreadyConfigured) {
143
163
  providersArray.push({
144
- apiKey: process.env[providerKeys.fal],
164
+ apiKey: falKey,
145
165
  blockType: 'fal',
146
166
  enabled: true,
147
167
  models: findModelsDefault(falBlock)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utilities/init/autoSetupProviders.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\nimport type { PluginConfig } from '../../types.js'\n\nimport { anthropicBlock } from '../../ai/providers/blocks/anthropic.js'\nimport { elevenlabsBlock } from '../../ai/providers/blocks/elevenlabs.js'\nimport { falBlock } from '../../ai/providers/blocks/fal.js'\nimport { googleBlock } from '../../ai/providers/blocks/google.js'\nimport { openaiBlock } from '../../ai/providers/blocks/openai.js'\nimport { xaiBlock } from '../../ai/providers/blocks/xai.js'\n\n\nconst findModelsDefault = (block: any): any[] => {\n let defaultModels: any[] = []\n const search = (fields: any[]): boolean => {\n for (const f of fields) {\n if (f.name === 'models' && Array.isArray(f.defaultValue)) {\n defaultModels = f.defaultValue\n return true\n }\n if (f.tabs) {\n for (const t of f.tabs) {\n if (search(t.fields)) {\n return true\n }\n }\n }\n if (f.fields) {\n if (search(f.fields)) {\n return true\n }\n }\n }\n return false\n }\n if (block?.fields) {\n search(block.fields)\n }\n return defaultModels\n}\n\nconst providerKeys = {\n anthropic: 'ANTHROPIC_API_KEY',\n elevenlabs: 'ELEVENLABS_API_KEY',\n fal: 'FAL_KEY',\n google: ['GOOGLE_GENERATIVE_AI_API_KEY', 'GEMINI_API_KEY'],\n openai: 'OPENAI_API_KEY',\n xai: 'XAI_API_KEY',\n}\n\nexport const autoSetupProviders = async (payload: Payload, config: PluginConfig) => {\n try {\n const existing = await payload.findGlobal({ slug: 'ai-providers' })\n\n // Build the default array structure\n let initializedAny = false\n const providersArray: any[] = []\n const defaults = {\n image: existing.defaults?.image || { model: '', provider: '' },\n text: existing.defaults?.text || { model: '', provider: '' },\n tts: existing.defaults?.tts || { model: '', provider: '' },\n video: existing.defaults?.video || { model: '', provider: '' },\n }\n\n const { providerOptions } = config\n\n // OpenAI Setup\n if (process.env[providerKeys.openai]) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'openai')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: process.env[providerKeys.openai],\n blockType: 'openai',\n enabled: true,\n models: findModelsDefault(openaiBlock),\n })\n initializedAny = true\n }\n }\n\n // Google Setup\n const googleKey = process.env[providerKeys.google[0]] || process.env[providerKeys.google[1]]\n if (googleKey) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'google')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: googleKey,\n blockType: 'google',\n enabled: true,\n models: findModelsDefault(googleBlock),\n })\n initializedAny = true\n }\n }\n\n // Anthropic Setup\n if (process.env[providerKeys.anthropic]) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'anthropic')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: process.env[providerKeys.anthropic],\n blockType: 'anthropic',\n enabled: true,\n models: findModelsDefault(anthropicBlock),\n })\n initializedAny = true\n }\n }\n\n // ElevenLabs Setup\n if (process.env[providerKeys.elevenlabs]) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'elevenlabs')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: process.env[providerKeys.elevenlabs],\n blockType: 'elevenlabs',\n enabled: true,\n models: findModelsDefault(elevenlabsBlock),\n })\n initializedAny = true\n }\n }\n\n // XAI Setup\n if (process.env[providerKeys.xai]) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'xai')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: process.env[providerKeys.xai],\n blockType: 'xai',\n enabled: true,\n models: findModelsDefault(xaiBlock),\n })\n initializedAny = true\n }\n }\n\n // Fal Setup\n if (process.env[providerKeys.fal]) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'fal')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: process.env[providerKeys.fal],\n blockType: 'fal',\n enabled: true,\n models: findModelsDefault(falBlock),\n })\n initializedAny = true\n }\n }\n\n // Setup defaults globally regardless of whether providers were newly added or not\n const configuredProviders = [...(existing.providers || []), ...providersArray]\n if (configuredProviders.length > 0) {\n if (!defaults.text.provider && config.generationDefaults?.text) {\n defaults.text.provider = config.generationDefaults.text.provider\n defaults.text.model = config.generationDefaults.text.model\n initializedAny = true\n }\n \n const providerSchemaByProvider: Record<string, unknown> = {}\n for (const [providerName, options] of Object.entries(providerOptions || {})) {\n if (options && typeof options === 'object' && !Array.isArray(options)) {\n providerSchemaByProvider[providerName] = options\n }\n }\n\n if (!defaults.image.provider && config.generationDefaults?.image) {\n defaults.image.provider = config.generationDefaults.image.provider\n defaults.image.model = config.generationDefaults.image.model\n initializedAny = true\n }\n\n if (!defaults.tts.provider && config.generationDefaults?.tts) {\n defaults.tts.provider = config.generationDefaults.tts.provider\n defaults.tts.model = config.generationDefaults.tts.model\n defaults.tts.voice = config.generationDefaults.tts.voice\n initializedAny = true\n }\n\n if (!defaults.video.provider && config.generationDefaults?.video) {\n defaults.video.provider = config.generationDefaults.video.provider\n defaults.video.model = config.generationDefaults.video.model\n initializedAny = true\n }\n\n if (Object.keys(providerSchemaByProvider).length > 0) {\n const schemaForUseCases = JSON.stringify(providerSchemaByProvider)\n const useCases: Array<'image' | 'text' | 'tts' | 'video'> = ['text', 'image', 'tts', 'video']\n\n for (const useCase of useCases) {\n if (JSON.stringify(defaults[useCase].schema) !== schemaForUseCases) {\n defaults[useCase].schema = JSON.parse(schemaForUseCases)\n initializedAny = true\n }\n }\n }\n }\n\n if (initializedAny) {\n await payload.updateGlobal({\n slug: 'ai-providers',\n data: {\n defaults,\n providers: configuredProviders,\n },\n })\n payload.logger.info(\n `— AI Plugin: Auto-setup complete. Handled defaults for seeded providers.`,\n )\n }\n } catch (error) {\n payload.logger.warn(\n `— AI Plugin: Failed to auto-setup providers: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n}\n"],"names":["anthropicBlock","elevenlabsBlock","falBlock","googleBlock","openaiBlock","xaiBlock","findModelsDefault","block","defaultModels","search","fields","f","name","Array","isArray","defaultValue","tabs","t","providerKeys","anthropic","elevenlabs","fal","google","openai","xai","autoSetupProviders","payload","config","existing","findGlobal","slug","initializedAny","providersArray","defaults","image","model","provider","text","tts","video","providerOptions","process","env","isAlreadyConfigured","providers","find","p","blockType","push","apiKey","enabled","models","googleKey","configuredProviders","length","generationDefaults","providerSchemaByProvider","providerName","options","Object","entries","voice","keys","schemaForUseCases","JSON","stringify","useCases","useCase","schema","parse","updateGlobal","data","logger","info","error","warn","Error","message","String"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/utilities/init/autoSetupProviders.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\nimport type { PluginConfig } from '../../types.js'\n\nimport { anthropicBlock } from '../../ai/providers/blocks/anthropic.js'\nimport { elevenlabsBlock } from '../../ai/providers/blocks/elevenlabs.js'\nimport { falBlock } from '../../ai/providers/blocks/fal.js'\nimport { googleBlock } from '../../ai/providers/blocks/google.js'\nimport { openaiBlock } from '../../ai/providers/blocks/openai.js'\nimport { xaiBlock } from '../../ai/providers/blocks/xai.js'\n\n\nconst findModelsDefault = (block: any): any[] => {\n let defaultModels: any[] = []\n const search = (fields: any[]): boolean => {\n for (const f of fields) {\n if (f.name === 'models' && Array.isArray(f.defaultValue)) {\n defaultModels = f.defaultValue\n return true\n }\n if (f.tabs) {\n for (const t of f.tabs) {\n if (search(t.fields)) {\n return true\n }\n }\n }\n if (f.fields) {\n if (search(f.fields)) {\n return true\n }\n }\n }\n return false\n }\n if (block?.fields) {\n search(block.fields)\n }\n return defaultModels\n}\n\nconst providerKeys = {\n anthropic: 'ANTHROPIC_API_KEY',\n elevenlabs: 'ELEVENLABS_API_KEY',\n fal: 'FAL_KEY',\n google: ['GOOGLE_GENERATIVE_AI_API_KEY', 'GEMINI_API_KEY'],\n openai: 'OPENAI_API_KEY',\n xai: 'XAI_API_KEY',\n}\n\nexport const autoSetupProviders = async (payload: Payload, config: PluginConfig) => {\n try {\n const getEnvValue = (key: string): string | undefined => {\n const fromResolver = config.getEnv?.(key)\n if (typeof fromResolver === 'string' && fromResolver.length > 0) {\n return fromResolver\n }\n\n const fromMap = config.env?.[key]\n if (typeof fromMap === 'string' && fromMap.length > 0) {\n return fromMap\n }\n\n const fromProcessEnv = process.env[key]\n if (typeof fromProcessEnv === 'string' && fromProcessEnv.length > 0) {\n return fromProcessEnv\n }\n\n return undefined\n }\n\n const existing = await payload.findGlobal({ slug: 'ai-providers' })\n\n // Build the default array structure\n let initializedAny = false\n const providersArray: any[] = []\n const defaults = {\n image: existing.defaults?.image || { model: '', provider: '' },\n text: existing.defaults?.text || { model: '', provider: '' },\n tts: existing.defaults?.tts || { model: '', provider: '' },\n video: existing.defaults?.video || { model: '', provider: '' },\n }\n\n const { providerOptions } = config\n\n // OpenAI Setup\n const openaiKey = getEnvValue(providerKeys.openai)\n if (openaiKey) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'openai')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: openaiKey,\n blockType: 'openai',\n enabled: true,\n models: findModelsDefault(openaiBlock),\n })\n initializedAny = true\n }\n }\n\n // Google Setup\n const googleKey = getEnvValue(providerKeys.google[0]) || getEnvValue(providerKeys.google[1])\n if (googleKey) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'google')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: googleKey,\n blockType: 'google',\n enabled: true,\n models: findModelsDefault(googleBlock),\n })\n initializedAny = true\n }\n }\n\n // Anthropic Setup\n const anthropicKey = getEnvValue(providerKeys.anthropic)\n if (anthropicKey) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'anthropic')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: anthropicKey,\n blockType: 'anthropic',\n enabled: true,\n models: findModelsDefault(anthropicBlock),\n })\n initializedAny = true\n }\n }\n\n // ElevenLabs Setup\n const elevenlabsKey = getEnvValue(providerKeys.elevenlabs)\n if (elevenlabsKey) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'elevenlabs')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: elevenlabsKey,\n blockType: 'elevenlabs',\n enabled: true,\n models: findModelsDefault(elevenlabsBlock),\n })\n initializedAny = true\n }\n }\n\n // XAI Setup\n const xaiKey = getEnvValue(providerKeys.xai)\n if (xaiKey) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'xai')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: xaiKey,\n blockType: 'xai',\n enabled: true,\n models: findModelsDefault(xaiBlock),\n })\n initializedAny = true\n }\n }\n\n // Fal Setup\n const falKey = getEnvValue(providerKeys.fal)\n if (falKey) {\n const isAlreadyConfigured = existing.providers?.find((p: any) => p.blockType === 'fal')\n if (!isAlreadyConfigured) {\n providersArray.push({\n apiKey: falKey,\n blockType: 'fal',\n enabled: true,\n models: findModelsDefault(falBlock),\n })\n initializedAny = true\n }\n }\n\n // Setup defaults globally regardless of whether providers were newly added or not\n const configuredProviders = [...(existing.providers || []), ...providersArray]\n if (configuredProviders.length > 0) {\n if (!defaults.text.provider && config.generationDefaults?.text) {\n defaults.text.provider = config.generationDefaults.text.provider\n defaults.text.model = config.generationDefaults.text.model\n initializedAny = true\n }\n \n const providerSchemaByProvider: Record<string, unknown> = {}\n for (const [providerName, options] of Object.entries(providerOptions || {})) {\n if (options && typeof options === 'object' && !Array.isArray(options)) {\n providerSchemaByProvider[providerName] = options\n }\n }\n\n if (!defaults.image.provider && config.generationDefaults?.image) {\n defaults.image.provider = config.generationDefaults.image.provider\n defaults.image.model = config.generationDefaults.image.model\n initializedAny = true\n }\n\n if (!defaults.tts.provider && config.generationDefaults?.tts) {\n defaults.tts.provider = config.generationDefaults.tts.provider\n defaults.tts.model = config.generationDefaults.tts.model\n defaults.tts.voice = config.generationDefaults.tts.voice\n initializedAny = true\n }\n\n if (!defaults.video.provider && config.generationDefaults?.video) {\n defaults.video.provider = config.generationDefaults.video.provider\n defaults.video.model = config.generationDefaults.video.model\n initializedAny = true\n }\n\n if (Object.keys(providerSchemaByProvider).length > 0) {\n const schemaForUseCases = JSON.stringify(providerSchemaByProvider)\n const useCases: Array<'image' | 'text' | 'tts' | 'video'> = ['text', 'image', 'tts', 'video']\n\n for (const useCase of useCases) {\n if (JSON.stringify(defaults[useCase].schema) !== schemaForUseCases) {\n defaults[useCase].schema = JSON.parse(schemaForUseCases)\n initializedAny = true\n }\n }\n }\n }\n\n if (initializedAny) {\n await payload.updateGlobal({\n slug: 'ai-providers',\n data: {\n defaults,\n providers: configuredProviders,\n },\n })\n payload.logger.info(\n `— AI Plugin: Auto-setup complete. Handled defaults for seeded providers.`,\n )\n }\n } catch (error) {\n payload.logger.warn(\n `— AI Plugin: Failed to auto-setup providers: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n}\n"],"names":["anthropicBlock","elevenlabsBlock","falBlock","googleBlock","openaiBlock","xaiBlock","findModelsDefault","block","defaultModels","search","fields","f","name","Array","isArray","defaultValue","tabs","t","providerKeys","anthropic","elevenlabs","fal","google","openai","xai","autoSetupProviders","payload","config","getEnvValue","key","fromResolver","getEnv","length","fromMap","env","fromProcessEnv","process","undefined","existing","findGlobal","slug","initializedAny","providersArray","defaults","image","model","provider","text","tts","video","providerOptions","openaiKey","isAlreadyConfigured","providers","find","p","blockType","push","apiKey","enabled","models","googleKey","anthropicKey","elevenlabsKey","xaiKey","falKey","configuredProviders","generationDefaults","providerSchemaByProvider","providerName","options","Object","entries","voice","keys","schemaForUseCases","JSON","stringify","useCases","useCase","schema","parse","updateGlobal","data","logger","info","error","warn","Error","message","String"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { PayloadRequest } from 'payload';
2
+ export declare function resolveServerURL(req: PayloadRequest): string | undefined;
3
+ export declare function resolveAbsoluteURL(input: string, req: PayloadRequest): string;
@@ -0,0 +1,67 @@
1
+ import { PLUGIN_SERVER_URL_ENV_KEYS } from '../../defaults.js';
2
+ const normalizeServerURL = (value)=>{
3
+ if (!value) {
4
+ return undefined;
5
+ }
6
+ const trimmed = value.trim();
7
+ if (!trimmed) {
8
+ return undefined;
9
+ }
10
+ try {
11
+ const parsed = new URL(trimmed);
12
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
13
+ return undefined;
14
+ }
15
+ const normalizedPath = parsed.pathname === '/' ? '' : parsed.pathname.replace(/\/+$/, '');
16
+ return `${parsed.origin}${normalizedPath}`;
17
+ } catch {
18
+ return undefined;
19
+ }
20
+ };
21
+ const getProcessEnvValue = (key)=>{
22
+ if (typeof process === 'undefined' || !process.env) {
23
+ return undefined;
24
+ }
25
+ const value = process.env[key];
26
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
27
+ };
28
+ const getHeaderOrigin = (req)=>{
29
+ const forwardedProto = req.headers.get('x-forwarded-proto')?.split(',')[0]?.trim();
30
+ const forwardedHost = req.headers.get('x-forwarded-host')?.split(',')[0]?.trim();
31
+ if (forwardedProto && forwardedHost) {
32
+ return `${forwardedProto}://${forwardedHost}`;
33
+ }
34
+ const host = req.headers.get('host')?.trim();
35
+ if (!host) {
36
+ return undefined;
37
+ }
38
+ return `https://${host}`;
39
+ };
40
+ export function resolveServerURL(req) {
41
+ const candidates = [
42
+ req.payload.config?.serverURL || undefined,
43
+ ...PLUGIN_SERVER_URL_ENV_KEYS.map((key)=>getProcessEnvValue(key)),
44
+ req.url,
45
+ getHeaderOrigin(req)
46
+ ];
47
+ for (const candidate of candidates){
48
+ const normalized = normalizeServerURL(candidate);
49
+ if (normalized) {
50
+ return normalized;
51
+ }
52
+ }
53
+ return undefined;
54
+ }
55
+ export function resolveAbsoluteURL(input, req) {
56
+ if (/^https?:\/\//i.test(input)) {
57
+ return input;
58
+ }
59
+ const baseURL = resolveServerURL(req);
60
+ if (!baseURL) {
61
+ throw new Error('Could not resolve a server URL for relative asset path. Set `payload.config.serverURL` or SERVER_URL.');
62
+ }
63
+ const normalizedPath = input.startsWith('/') ? input : `/${input}`;
64
+ return `${baseURL}${normalizedPath}`;
65
+ }
66
+
67
+ //# sourceMappingURL=resolveServerURL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utilities/runtime/resolveServerURL.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { PLUGIN_SERVER_URL_ENV_KEYS } from '../../defaults.js'\n\nconst normalizeServerURL = (value: string | undefined): string | undefined => {\n if (!value) {\n return undefined\n }\n\n const trimmed = value.trim()\n if (!trimmed) {\n return undefined\n }\n\n try {\n const parsed = new URL(trimmed)\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return undefined\n }\n\n const normalizedPath = parsed.pathname === '/' ? '' : parsed.pathname.replace(/\\/+$/, '')\n return `${parsed.origin}${normalizedPath}`\n } catch {\n return undefined\n }\n}\n\nconst getProcessEnvValue = (key: string): string | undefined => {\n if (typeof process === 'undefined' || !process.env) {\n return undefined\n }\n\n const value = process.env[key]\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\nconst getHeaderOrigin = (req: PayloadRequest): string | undefined => {\n const forwardedProto = req.headers.get('x-forwarded-proto')?.split(',')[0]?.trim()\n const forwardedHost = req.headers.get('x-forwarded-host')?.split(',')[0]?.trim()\n\n if (forwardedProto && forwardedHost) {\n return `${forwardedProto}://${forwardedHost}`\n }\n\n const host = req.headers.get('host')?.trim()\n if (!host) {\n return undefined\n }\n\n return `https://${host}`\n}\n\nexport function resolveServerURL(req: PayloadRequest): string | undefined {\n const candidates: Array<string | undefined> = [\n req.payload.config?.serverURL || undefined,\n ...PLUGIN_SERVER_URL_ENV_KEYS.map((key) => getProcessEnvValue(key)),\n req.url,\n getHeaderOrigin(req),\n ]\n\n for (const candidate of candidates) {\n const normalized = normalizeServerURL(candidate)\n if (normalized) {\n return normalized\n }\n }\n\n return undefined\n}\n\nexport function resolveAbsoluteURL(input: string, req: PayloadRequest): string {\n if (/^https?:\\/\\//i.test(input)) {\n return input\n }\n\n const baseURL = resolveServerURL(req)\n if (!baseURL) {\n throw new Error(\n 'Could not resolve a server URL for relative asset path. Set `payload.config.serverURL` or SERVER_URL.',\n )\n }\n\n const normalizedPath = input.startsWith('/') ? input : `/${input}`\n return `${baseURL}${normalizedPath}`\n}\n"],"names":["PLUGIN_SERVER_URL_ENV_KEYS","normalizeServerURL","value","undefined","trimmed","trim","parsed","URL","protocol","normalizedPath","pathname","replace","origin","getProcessEnvValue","key","process","env","length","getHeaderOrigin","req","forwardedProto","headers","get","split","forwardedHost","host","resolveServerURL","candidates","payload","config","serverURL","map","url","candidate","normalized","resolveAbsoluteURL","input","test","baseURL","Error","startsWith"],"mappings":"AAEA,SAASA,0BAA0B,QAAQ,oBAAmB;AAE9D,MAAMC,qBAAqB,CAACC;IAC1B,IAAI,CAACA,OAAO;QACV,OAAOC;IACT;IAEA,MAAMC,UAAUF,MAAMG,IAAI;IAC1B,IAAI,CAACD,SAAS;QACZ,OAAOD;IACT;IAEA,IAAI;QACF,MAAMG,SAAS,IAAIC,IAAIH;QACvB,IAAIE,OAAOE,QAAQ,KAAK,WAAWF,OAAOE,QAAQ,KAAK,UAAU;YAC/D,OAAOL;QACT;QAEA,MAAMM,iBAAiBH,OAAOI,QAAQ,KAAK,MAAM,KAAKJ,OAAOI,QAAQ,CAACC,OAAO,CAAC,QAAQ;QACtF,OAAO,CAAC,EAAEL,OAAOM,MAAM,CAAC,EAAEH,eAAe,CAAC;IAC5C,EAAE,OAAM;QACN,OAAON;IACT;AACF;AAEA,MAAMU,qBAAqB,CAACC;IAC1B,IAAI,OAAOC,YAAY,eAAe,CAACA,QAAQC,GAAG,EAAE;QAClD,OAAOb;IACT;IAEA,MAAMD,QAAQa,QAAQC,GAAG,CAACF,IAAI;IAC9B,OAAO,OAAOZ,UAAU,YAAYA,MAAMe,MAAM,GAAG,IAAIf,QAAQC;AACjE;AAEA,MAAMe,kBAAkB,CAACC;IACvB,MAAMC,iBAAiBD,IAAIE,OAAO,CAACC,GAAG,CAAC,sBAAsBC,MAAM,IAAI,CAAC,EAAE,EAAElB;IAC5E,MAAMmB,gBAAgBL,IAAIE,OAAO,CAACC,GAAG,CAAC,qBAAqBC,MAAM,IAAI,CAAC,EAAE,EAAElB;IAE1E,IAAIe,kBAAkBI,eAAe;QACnC,OAAO,CAAC,EAAEJ,eAAe,GAAG,EAAEI,cAAc,CAAC;IAC/C;IAEA,MAAMC,OAAON,IAAIE,OAAO,CAACC,GAAG,CAAC,SAASjB;IACtC,IAAI,CAACoB,MAAM;QACT,OAAOtB;IACT;IAEA,OAAO,CAAC,QAAQ,EAAEsB,KAAK,CAAC;AAC1B;AAEA,OAAO,SAASC,iBAAiBP,GAAmB;IAClD,MAAMQ,aAAwC;QAC5CR,IAAIS,OAAO,CAACC,MAAM,EAAEC,aAAa3B;WAC9BH,2BAA2B+B,GAAG,CAAC,CAACjB,MAAQD,mBAAmBC;QAC9DK,IAAIa,GAAG;QACPd,gBAAgBC;KACjB;IAED,KAAK,MAAMc,aAAaN,WAAY;QAClC,MAAMO,aAAajC,mBAAmBgC;QACtC,IAAIC,YAAY;YACd,OAAOA;QACT;IACF;IAEA,OAAO/B;AACT;AAEA,OAAO,SAASgC,mBAAmBC,KAAa,EAAEjB,GAAmB;IACnE,IAAI,gBAAgBkB,IAAI,CAACD,QAAQ;QAC/B,OAAOA;IACT;IAEA,MAAME,UAAUZ,iBAAiBP;IACjC,IAAI,CAACmB,SAAS;QACZ,MAAM,IAAIC,MACR;IAEJ;IAEA,MAAM9B,iBAAiB2B,MAAMI,UAAU,CAAC,OAAOJ,QAAQ,CAAC,CAAC,EAAEA,MAAM,CAAC;IAClE,OAAO,CAAC,EAAEE,QAAQ,EAAE7B,eAAe,CAAC;AACtC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-stack/payloadcms",
3
- "version": "3.76.0-beta.4",
3
+ "version": "3.76.0-beta.6",
4
4
  "private": false,
5
5
  "bugs": "https://github.com/ashbuilds/payload-ai/issues",
6
6
  "repository": "https://github.com/ashbuilds/payload-ai",