@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 +27 -1
- package/dist/collections/Instructions.js +3 -2
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/defaults.d.ts +1 -0
- package/dist/defaults.js +5 -0
- package/dist/defaults.js.map +1 -1
- package/dist/endpoints/upload.js +2 -2
- package/dist/endpoints/upload.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.js.map +1 -1
- package/dist/utilities/encryption.js +15 -9
- package/dist/utilities/encryption.js.map +1 -1
- package/dist/utilities/images/fetchImages.js +2 -6
- package/dist/utilities/images/fetchImages.js.map +1 -1
- package/dist/utilities/init/autoSetupProviders.js +31 -11
- package/dist/utilities/init/autoSetupProviders.js.map +1 -1
- package/dist/utilities/runtime/resolveServerURL.d.ts +3 -0
- package/dist/utilities/runtime/resolveServerURL.js +67 -0
- package/dist/utilities/runtime/resolveServerURL.js.map +1 -0
- package/package.json +1 -1
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
|
-
|
|
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: '
|
|
107
|
-
singular: '
|
|
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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"}
|
package/dist/defaults.d.ts
CHANGED
|
@@ -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`;
|
package/dist/defaults.js.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/endpoints/upload.js
CHANGED
|
@@ -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
|
|
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":"
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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 //
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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,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"}
|