@ai-stack/payloadcms 3.2.26 → 3.68.0-beta.2
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/{LICENSE.md → LICENSE} +1 -1
- package/README.md +218 -229
- package/dist/access/checkAccess.d.ts +4 -0
- package/dist/access/checkAccess.js +20 -0
- package/dist/access/checkAccess.js.map +1 -0
- package/dist/ai/core/generateObject.d.ts +7 -0
- package/dist/ai/core/generateObject.js +35 -0
- package/dist/ai/core/generateObject.js.map +1 -0
- package/dist/ai/core/generateText.d.ts +7 -0
- package/dist/ai/core/generateText.js +31 -0
- package/dist/ai/core/generateText.js.map +1 -0
- package/dist/ai/core/index.d.ts +11 -0
- package/dist/ai/core/index.js +10 -0
- package/dist/ai/core/index.js.map +1 -0
- package/dist/ai/core/media/generateMedia.d.ts +7 -0
- package/dist/ai/core/media/generateMedia.js +50 -0
- package/dist/ai/core/media/generateMedia.js.map +1 -0
- package/dist/ai/core/media/image/generateImage.d.ts +6 -0
- package/dist/ai/core/media/image/generateImage.js +41 -0
- package/dist/ai/core/media/image/generateImage.js.map +1 -0
- package/dist/ai/core/media/image/handlers/multimodal.d.ts +7 -0
- package/dist/ai/core/media/image/handlers/multimodal.js +100 -0
- package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -0
- package/dist/ai/core/media/image/handlers/standard.d.ts +7 -0
- package/dist/ai/core/media/image/handlers/standard.js +28 -0
- package/dist/ai/core/media/image/handlers/standard.js.map +1 -0
- package/dist/ai/core/media/image/index.d.ts +2 -0
- package/dist/ai/core/media/image/index.js +3 -0
- package/dist/ai/core/media/image/index.js.map +1 -0
- package/dist/ai/core/media/index.d.ts +2 -0
- package/dist/ai/core/media/index.js +3 -0
- package/dist/ai/core/media/index.js.map +1 -0
- package/dist/ai/core/media/speech/generateSpeech.d.ts +5 -0
- package/dist/ai/core/media/speech/generateSpeech.js +55 -0
- package/dist/ai/core/media/speech/generateSpeech.js.map +1 -0
- package/dist/ai/core/media/speech/index.d.ts +2 -0
- package/dist/ai/core/media/speech/index.js +3 -0
- package/dist/ai/core/media/speech/index.js.map +1 -0
- package/dist/ai/core/media/types.d.ts +74 -0
- package/dist/ai/core/media/types.js +5 -0
- package/dist/ai/core/media/types.js.map +1 -0
- package/dist/ai/core/media/utils.d.ts +11 -0
- package/dist/ai/core/media/utils.js +34 -0
- package/dist/ai/core/media/utils.js.map +1 -0
- package/dist/ai/core/media/video/generateVideo.d.ts +6 -0
- package/dist/ai/core/media/video/generateVideo.js +32 -0
- package/dist/ai/core/media/video/generateVideo.js.map +1 -0
- package/dist/ai/core/media/video/index.d.ts +2 -0
- package/dist/ai/core/media/video/index.js +3 -0
- package/dist/ai/core/media/video/index.js.map +1 -0
- package/dist/ai/core/streamObject.d.ts +7 -0
- package/dist/ai/core/streamObject.js +54 -0
- package/dist/ai/core/streamObject.js.map +1 -0
- package/dist/ai/core/streamText.d.ts +7 -0
- package/dist/ai/core/streamText.js +30 -0
- package/dist/ai/core/streamText.js.map +1 -0
- package/dist/ai/core/types.d.ts +85 -0
- package/dist/ai/core/types.js +5 -0
- package/dist/ai/core/types.js.map +1 -0
- package/dist/ai/index.d.ts +11 -0
- package/dist/ai/index.js +25 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/providers/blocks/anthropic.d.ts +2 -0
- package/dist/ai/providers/blocks/anthropic.js +223 -0
- package/dist/ai/providers/blocks/anthropic.js.map +1 -0
- package/dist/ai/providers/blocks/elevenlabs.d.ts +2 -0
- package/dist/ai/providers/blocks/elevenlabs.js +449 -0
- package/dist/ai/providers/blocks/elevenlabs.js.map +1 -0
- package/dist/ai/providers/blocks/fal.d.ts +2 -0
- package/dist/ai/providers/blocks/fal.js +312 -0
- package/dist/ai/providers/blocks/fal.js.map +1 -0
- package/dist/ai/providers/blocks/google.d.ts +2 -0
- package/dist/ai/providers/blocks/google.js +623 -0
- package/dist/ai/providers/blocks/google.js.map +1 -0
- package/dist/ai/providers/blocks/index.d.ts +2 -0
- package/dist/ai/providers/blocks/index.js +18 -0
- package/dist/ai/providers/blocks/index.js.map +1 -0
- package/dist/ai/providers/blocks/openai-compatible.d.ts +2 -0
- package/dist/ai/providers/blocks/openai-compatible.js +308 -0
- package/dist/ai/providers/blocks/openai-compatible.js.map +1 -0
- package/dist/ai/providers/blocks/openai.d.ts +2 -0
- package/dist/ai/providers/blocks/openai.js +600 -0
- package/dist/ai/providers/blocks/openai.js.map +1 -0
- package/dist/ai/providers/blocks/xai.d.ts +2 -0
- package/dist/ai/providers/blocks/xai.js +247 -0
- package/dist/ai/providers/blocks/xai.js.map +1 -0
- package/dist/ai/providers/icons.d.ts +7 -0
- package/dist/ai/providers/icons.js +9 -0
- package/dist/ai/providers/icons.js.map +1 -0
- package/dist/ai/providers/index.d.ts +2 -0
- package/dist/ai/providers/index.js +6 -0
- package/dist/ai/providers/index.js.map +1 -0
- package/dist/ai/providers/registry.d.ts +40 -0
- package/dist/ai/providers/registry.js +267 -0
- package/dist/ai/providers/registry.js.map +1 -0
- package/dist/ai/providers/types.d.ts +115 -0
- package/dist/ai/providers/types.js +4 -0
- package/dist/ai/providers/types.js.map +1 -0
- package/dist/ai/utils/systemGenerate.d.ts +1 -1
- package/dist/ai/utils/systemGenerate.js +19 -19
- package/dist/ai/utils/systemGenerate.js.map +1 -1
- package/dist/collections/AIJobs.d.ts +2 -0
- package/dist/collections/AIJobs.js +81 -0
- package/dist/collections/AIJobs.js.map +1 -0
- package/dist/collections/AISettings.d.ts +2 -0
- package/dist/collections/AISettings.js +279 -0
- package/dist/collections/AISettings.js.map +1 -0
- package/dist/collections/Instructions.js +224 -50
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/defaults.d.ts +3 -0
- package/dist/defaults.js +3 -0
- package/dist/defaults.js.map +1 -1
- package/dist/endpoints/buildPromptUtils.d.ts +19 -0
- package/dist/endpoints/buildPromptUtils.js +114 -0
- package/dist/endpoints/buildPromptUtils.js.map +1 -0
- package/dist/endpoints/chat.d.ts +4 -0
- package/dist/endpoints/fetchFields.js +0 -7
- package/dist/endpoints/fetchFields.js.map +1 -1
- package/dist/endpoints/fetchVoices.d.ts +2 -0
- package/dist/endpoints/fetchVoices.js +79 -0
- package/dist/endpoints/fetchVoices.js.map +1 -0
- package/dist/endpoints/index.js +339 -232
- package/dist/endpoints/index.js.map +1 -1
- package/dist/exports/client.d.ts +9 -0
- package/dist/exports/client.js +9 -0
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/fields.d.ts +1 -0
- package/dist/exports/fields.js +1 -0
- package/dist/exports/fields.js.map +1 -1
- package/dist/fields/ArrayComposeField/ArrayComposeField.d.ts +15 -0
- package/dist/fields/ArrayComposeField/ArrayComposeField.js +87 -0
- package/dist/fields/ArrayComposeField/ArrayComposeField.js.map +1 -0
- package/dist/fields/ArrayComposeField/ArrayComposeField.jsx +73 -0
- package/dist/fields/ComposeField/ComposeField.js +2 -2
- package/dist/fields/ComposeField/ComposeField.js.map +1 -1
- package/dist/fields/ComposeField/ComposeField.jsx +2 -2
- package/dist/fields/PromptEditorField/PromptEditorField.js +162 -16
- package/dist/fields/PromptEditorField/PromptEditorField.js.map +1 -1
- package/dist/fields/PromptEditorField/PromptEditorField.jsx +123 -5
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init.js +63 -65
- package/dist/init.js.map +1 -1
- package/dist/payload-ai.d.ts +149 -0
- package/dist/plugin.js +94 -46
- package/dist/plugin.js.map +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.js +38 -7
- package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +30 -4
- package/dist/providers/InstructionsProvider/context.d.ts +1 -0
- package/dist/providers/InstructionsProvider/context.js +1 -0
- package/dist/providers/InstructionsProvider/context.js.map +1 -1
- package/dist/providers/InstructionsProvider/useInstructions.js +30 -10
- package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
- package/dist/styles.d.ts +11 -0
- package/dist/types/handlebars-async-helpers.d.ts +1 -0
- package/dist/types/handlebars-dist-handlebars.d.ts +1 -0
- package/dist/types/react-mentions.d.ts +1 -0
- package/dist/types.d.ts +6 -16
- package/dist/types.js.map +1 -1
- package/dist/ui/AIConfigDashboard/index.d.ts +2 -0
- package/dist/ui/AIConfigDashboard/index.js +46 -0
- package/dist/ui/AIConfigDashboard/index.js.map +1 -0
- package/dist/ui/AIConfigDashboard/index.jsx +24 -0
- package/dist/ui/ApiKeyStatusIndicator/index.d.ts +6 -0
- package/dist/ui/ApiKeyStatusIndicator/index.js +39 -0
- package/dist/ui/ApiKeyStatusIndicator/index.js.map +1 -0
- package/dist/ui/ApiKeyStatusIndicator/index.jsx +29 -0
- package/dist/ui/Compose/Compose.d.ts +2 -2
- package/dist/ui/Compose/Compose.js +118 -92
- package/dist/ui/Compose/Compose.js.map +1 -1
- package/dist/ui/Compose/Compose.jsx +113 -103
- package/dist/ui/Compose/ComposePlaceholder.d.ts +7 -0
- package/dist/ui/Compose/ComposePlaceholder.js +78 -0
- package/dist/ui/Compose/ComposePlaceholder.js.map +1 -0
- package/dist/ui/Compose/ComposePlaceholder.jsx +66 -0
- package/dist/ui/Compose/UndoRedoActions.d.ts +2 -2
- package/dist/ui/Compose/UndoRedoActions.js +11 -6
- package/dist/ui/Compose/UndoRedoActions.js.map +1 -1
- package/dist/ui/Compose/UndoRedoActions.jsx +8 -6
- package/dist/ui/Compose/compose.module.css +57 -17
- package/dist/ui/Compose/hooks/menu/itemsMap.js +13 -7
- package/dist/ui/Compose/hooks/menu/itemsMap.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/useMenu.d.ts +2 -1
- package/dist/ui/Compose/hooks/menu/useMenu.js +28 -17
- package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/useMenu.jsx +27 -14
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js +69 -10
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
- package/dist/ui/Compose/hooks/useGenerate.d.ts +3 -0
- package/dist/ui/Compose/hooks/useGenerate.js +71 -11
- package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
- package/dist/ui/Compose/hooks/useHistory.d.ts +0 -1
- package/dist/ui/Compose/hooks/useHistory.js +113 -26
- package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
- package/dist/ui/DynamicModelSelect/index.d.ts +7 -0
- package/dist/ui/DynamicModelSelect/index.js +231 -0
- package/dist/ui/DynamicModelSelect/index.js.map +1 -0
- package/dist/ui/DynamicModelSelect/index.jsx +207 -0
- package/dist/ui/DynamicProviderSelect/index.d.ts +7 -0
- package/dist/ui/DynamicProviderSelect/index.js +101 -0
- package/dist/ui/DynamicProviderSelect/index.js.map +1 -0
- package/dist/ui/DynamicProviderSelect/index.jsx +90 -0
- package/dist/ui/DynamicVoiceSelect/index.d.ts +7 -0
- package/dist/ui/DynamicVoiceSelect/index.js +156 -0
- package/dist/ui/DynamicVoiceSelect/index.js.map +1 -0
- package/dist/ui/DynamicVoiceSelect/index.jsx +102 -0
- package/dist/ui/EncryptedTextField/index.d.ts +8 -0
- package/dist/ui/EncryptedTextField/index.js +74 -0
- package/dist/ui/EncryptedTextField/index.js.map +1 -0
- package/dist/ui/EncryptedTextField/index.jsx +35 -0
- package/dist/ui/Icons/LottieAnimation.js +3 -1
- package/dist/ui/Icons/LottieAnimation.js.map +1 -1
- package/dist/ui/Icons/LottieAnimation.jsx +2 -1
- package/dist/ui/ModelRowLabel/index.d.ts +6 -0
- package/dist/ui/ModelRowLabel/index.js +41 -0
- package/dist/ui/ModelRowLabel/index.js.map +1 -0
- package/dist/ui/ModelRowLabel/index.jsx +26 -0
- package/dist/ui/ProviderOptionsEditor/index.d.ts +7 -0
- package/dist/ui/ProviderOptionsEditor/index.js +291 -0
- package/dist/ui/ProviderOptionsEditor/index.js.map +1 -0
- package/dist/ui/ProviderOptionsEditor/index.jsx +210 -0
- package/dist/ui/VoicesFetcher/index.d.ts +7 -0
- package/dist/ui/VoicesFetcher/index.js +118 -0
- package/dist/ui/VoicesFetcher/index.js.map +1 -0
- package/dist/ui/VoicesFetcher/index.jsx +79 -0
- package/dist/utilities/buildSmartPrompt.d.ts +22 -0
- package/dist/utilities/buildSmartPrompt.js +143 -0
- package/dist/utilities/buildSmartPrompt.js.map +1 -0
- package/dist/utilities/encryption.d.ts +2 -0
- package/dist/utilities/encryption.js +47 -0
- package/dist/utilities/encryption.js.map +1 -0
- package/dist/utilities/extractImageData.d.ts +9 -0
- package/dist/utilities/extractImageData.js +12 -2
- package/dist/utilities/extractImageData.js.map +1 -1
- package/dist/utilities/fetchImages.d.ts +14 -0
- package/dist/utilities/fetchImages.js +38 -0
- package/dist/utilities/fetchImages.js.map +1 -0
- package/dist/utilities/fieldToJsonSchema.d.ts +2 -1
- package/dist/utilities/fieldToJsonSchema.js +66 -3
- package/dist/utilities/fieldToJsonSchema.js.map +1 -1
- package/dist/utilities/getFieldBySchemaPath.d.ts +2 -2
- package/dist/utilities/getFieldBySchemaPath.js +15 -0
- package/dist/utilities/getFieldBySchemaPath.js.map +1 -1
- package/dist/utilities/getProviderOptionsFields.d.ts +16 -0
- package/dist/utilities/getProviderOptionsFields.js +80 -0
- package/dist/utilities/getProviderOptionsFields.js.map +1 -0
- package/dist/utilities/isPluginActivated.js +1 -2
- package/dist/utilities/isPluginActivated.js.map +1 -1
- package/dist/utilities/lexicalToHTML.js.map +1 -1
- package/dist/utilities/resolveImageReferences.d.ts +30 -0
- package/dist/utilities/resolveImageReferences.js +167 -0
- package/dist/utilities/resolveImageReferences.js.map +1 -0
- package/dist/utilities/schemaConverter.d.ts +3 -0
- package/dist/utilities/schemaConverter.js +93 -0
- package/dist/utilities/schemaConverter.js.map +1 -0
- package/dist/utilities/setSafeLexicalState.d.ts +1 -3
- package/dist/utilities/setSafeLexicalState.js +1 -1
- package/dist/utilities/setSafeLexicalState.js.map +1 -1
- package/dist/utilities/updateFieldsConfig.js +27 -43
- package/dist/utilities/updateFieldsConfig.js.map +1 -1
- package/package.json +23 -24
- package/dist/ai/models/anthropic/index.d.ts +0 -2
- package/dist/ai/models/anthropic/index.js +0 -129
- package/dist/ai/models/anthropic/index.js.map +0 -1
- package/dist/ai/models/elevenLabs/generateVoice.d.ts +0 -8
- package/dist/ai/models/elevenLabs/generateVoice.js +0 -20
- package/dist/ai/models/elevenLabs/generateVoice.js.map +0 -1
- package/dist/ai/models/elevenLabs/index.d.ts +0 -2
- package/dist/ai/models/elevenLabs/index.js +0 -133
- package/dist/ai/models/elevenLabs/index.js.map +0 -1
- package/dist/ai/models/elevenLabs/voices.d.ts +0 -8
- package/dist/ai/models/elevenLabs/voices.js +0 -24
- package/dist/ai/models/elevenLabs/voices.js.map +0 -1
- package/dist/ai/models/generateObject.d.ts +0 -11
- package/dist/ai/models/generateObject.js +0 -22
- package/dist/ai/models/generateObject.js.map +0 -1
- package/dist/ai/models/google/generateImage.d.ts +0 -9
- package/dist/ai/models/google/generateImage.js +0 -27
- package/dist/ai/models/google/generateImage.js.map +0 -1
- package/dist/ai/models/google/index.d.ts +0 -2
- package/dist/ai/models/google/index.js +0 -201
- package/dist/ai/models/google/index.js.map +0 -1
- package/dist/ai/models/index.d.ts +0 -2
- package/dist/ai/models/index.js +0 -13
- package/dist/ai/models/index.js.map +0 -1
- package/dist/ai/models/openai/generateImage.d.ts +0 -5
- package/dist/ai/models/openai/generateImage.js +0 -31
- package/dist/ai/models/openai/generateImage.js.map +0 -1
- package/dist/ai/models/openai/generateVoice.d.ts +0 -6
- package/dist/ai/models/openai/generateVoice.js +0 -19
- package/dist/ai/models/openai/generateVoice.js.map +0 -1
- package/dist/ai/models/openai/index.d.ts +0 -2
- package/dist/ai/models/openai/index.js +0 -428
- package/dist/ai/models/openai/index.js.map +0 -1
- package/dist/ai/models/openai/openai.d.ts +0 -1
- package/dist/ai/models/openai/openai.js +0 -8
- package/dist/ai/models/openai/openai.js.map +0 -1
- package/dist/ai/utils/editImagesWithOpenAI.d.ts +0 -10
- package/dist/ai/utils/editImagesWithOpenAI.js +0 -37
- package/dist/ai/utils/editImagesWithOpenAI.js.map +0 -1
- package/dist/styles.d.js +0 -2
- package/dist/styles.d.js.map +0 -1
- package/dist/types/handlebars-async-helpers.d.js +0 -2
- package/dist/types/handlebars-async-helpers.d.js.map +0 -1
- package/dist/types/handlebars-dist-handlebars.d.js +0 -2
- package/dist/types/handlebars-dist-handlebars.d.js.map +0 -1
- package/dist/types/react-mentions.d.js +0 -2
- package/dist/types/react-mentions.d.js.map +0 -1
- package/dist/utilities/getGenerationModels.d.ts +0 -2
- package/dist/utilities/getGenerationModels.js +0 -10
- package/dist/utilities/getGenerationModels.js.map +0 -1
|
@@ -124,6 +124,67 @@ export function fieldToJsonSchema(fieldInput, opts) {
|
|
|
124
124
|
const type = field.type;
|
|
125
125
|
let valueSchema = null;
|
|
126
126
|
switch(type){
|
|
127
|
+
case 'array':
|
|
128
|
+
case 'group':
|
|
129
|
+
{
|
|
130
|
+
if ('fields' in field && Array.isArray(field.fields)) {
|
|
131
|
+
const properties = {};
|
|
132
|
+
const required = [];
|
|
133
|
+
const processFields = (fields)=>{
|
|
134
|
+
for (const subField of fields){
|
|
135
|
+
if (subField.type === 'row' || subField.type === 'collapsible') {
|
|
136
|
+
if (subField.fields) {
|
|
137
|
+
processFields(subField.fields);
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (!subField.name) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const subSchema = fieldToJsonSchema(subField, {
|
|
145
|
+
wrapObject: false
|
|
146
|
+
});
|
|
147
|
+
if (subSchema && Object.keys(subSchema).length > 0) {
|
|
148
|
+
properties[subField.name] = subSchema;
|
|
149
|
+
if (subField.required) {
|
|
150
|
+
required.push(subField.name);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
processFields(field.fields);
|
|
156
|
+
const objSchema = {
|
|
157
|
+
type: 'object',
|
|
158
|
+
additionalProperties: false,
|
|
159
|
+
properties,
|
|
160
|
+
required: required.length ? required : undefined
|
|
161
|
+
};
|
|
162
|
+
if (type === 'array') {
|
|
163
|
+
valueSchema = {
|
|
164
|
+
type: 'array',
|
|
165
|
+
items: objSchema
|
|
166
|
+
};
|
|
167
|
+
} else {
|
|
168
|
+
valueSchema = objSchema;
|
|
169
|
+
}
|
|
170
|
+
const description = getDescription(field);
|
|
171
|
+
if (description) {
|
|
172
|
+
valueSchema.description = description;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case 'checkbox':
|
|
178
|
+
{
|
|
179
|
+
valueSchema = {
|
|
180
|
+
type: 'boolean'
|
|
181
|
+
};
|
|
182
|
+
const description = getDescription(field);
|
|
183
|
+
if (description) {
|
|
184
|
+
valueSchema.description = description;
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
127
188
|
case 'code':
|
|
128
189
|
{
|
|
129
190
|
const base = codeSchema(field);
|
|
@@ -180,7 +241,6 @@ export function fieldToJsonSchema(fieldInput, opts) {
|
|
|
180
241
|
{
|
|
181
242
|
const base = numberWithBounds(field);
|
|
182
243
|
if (field.hasMany) {
|
|
183
|
-
// Respect hasMany only if truly configured; Payload rarely uses hasMany for number, but allow if present.
|
|
184
244
|
valueSchema = {
|
|
185
245
|
type: 'array',
|
|
186
246
|
items: base
|
|
@@ -243,9 +303,13 @@ export function fieldToJsonSchema(fieldInput, opts) {
|
|
|
243
303
|
}
|
|
244
304
|
break;
|
|
245
305
|
}
|
|
306
|
+
// Explicitly handle organizational types to avoid default breakage if passed directly
|
|
307
|
+
// though usually they are handled by parent recursion in group/array case above.
|
|
308
|
+
// If passed as root, we can't really return a meaningful single-value schema without a wrapper?
|
|
309
|
+
// But let's leave default for them or handle if necessary.
|
|
310
|
+
// For now, if someone passes a 'row' as root, it will fall to default (null).
|
|
246
311
|
default:
|
|
247
312
|
{
|
|
248
|
-
// Unsupported type: return null to allow caller to decide how to proceed (e.g., no schema)
|
|
249
313
|
valueSchema = null;
|
|
250
314
|
break;
|
|
251
315
|
}
|
|
@@ -255,7 +319,6 @@ export function fieldToJsonSchema(fieldInput, opts) {
|
|
|
255
319
|
return valueSchema || {};
|
|
256
320
|
}
|
|
257
321
|
if (!valueSchema) {
|
|
258
|
-
// Return undefined-like schema if not supported; caller may choose to skip passing schema
|
|
259
322
|
return {};
|
|
260
323
|
}
|
|
261
324
|
const schema = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/fieldToJsonSchema.ts"],"sourcesContent":["/**\n * fieldToJsonSchema\n * Convert a Payload Field (server or client) into a minimal JSON Schema object,\n * wrapped as { type: 'object', properties: { [name]: valueSchema }, required: [...] }\n *\n * Supported types:\n * - text, textarea, select, number, date, code, email, json\n * Arrays are emitted only when field.hasMany is true and the field type supports hasMany\n * (text, textarea, select; for others only if your config truly sets hasMany).\n */\n\nexport type JsonSchema = Record<string, any>;\n\n// Narrowed minimal typing to avoid anywhere possible without pulling the full payload types at runtime.\n// In a Payload project, you can import type { Field, ClientField } from 'payload' and use those instead.\ntype BaseField = {\n admin?: {\n description?: unknown;\n language?: unknown;\n };\n hasMany?: boolean;\n // json\n jsonSchema?: unknown;\n max?: number;\n maxRows?: number;\n // number\n min?: number;\n // text/textarea\n minRows?: number;\n name?: string;\n // select\n options?: Array<\n | {\n label?: unknown;\n value: number | string;\n }\n | number\n | string\n >;\n required?: boolean;\n schema?: unknown;\n type?: string;\n typescriptSchema?: unknown;\n};\n\nfunction isString(s: unknown): s is string {\n return typeof s === 'string';\n}\n\nfunction isPlainObject(o: unknown): o is Record<string, unknown> {\n return !!o && typeof o === 'object' && !Array.isArray(o);\n}\n\nfunction getDescription(field: BaseField): string | undefined {\n const d = field?.admin?.description;\n return typeof d === 'string' ? d : undefined;\n}\n\nfunction stringWithDescription(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction numberWithBounds(field: BaseField) {\n const out: Record<string, any> = { type: 'number' };\n if (typeof field.min === 'number') {out.minimum = field.min;}\n if (typeof field.max === 'number') {out.maximum = field.max;}\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction dateSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'date-time' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction codeSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n let description = getDescription(field);\n const lang = field?.admin?.language;\n if (typeof lang === 'string' && lang.trim()) {\n description = description ? `${description} (language: ${lang})` : `language: ${lang}`;\n }\n if (description) {out.description = description;}\n return out;\n}\n\nfunction emailSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'email' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction jsonValueSchema(field: BaseField) {\n // Prefer a provided JSON Schema object\n if (isPlainObject(field.jsonSchema)) {return field.jsonSchema as object;}\n if (isPlainObject(field.schema)) {return field.schema as object;}\n\n // typescriptSchema cannot be executed here; default to object\n return { type: 'object' };\n}\n\nfunction normalizeSelectOptions(field: BaseField): { values: Array<number | string>; valueType: 'number' | 'string' } {\n const raw = field.options || [];\n const values: Array<number | string> = [];\n\n for (const opt of raw) {\n if (typeof opt === 'string' || typeof opt === 'number') {\n values.push(opt);\n } else if (isPlainObject(opt) && ('value' in opt)) {\n const v = (opt as any).value;\n if (typeof v === 'string' || typeof v === 'number') {\n values.push(v);\n }\n }\n }\n\n // Infer primitive type\n const allNumbers = values.length > 0 && values.every((v) => typeof v === 'number');\n const valueType: 'number' | 'string' = allNumbers ? 'number' : 'string';\n return { values, valueType };\n}\n\nfunction supportsHasMany(fieldType: string | undefined): boolean {\n // Out of the box: text, textarea, select support hasMany\n // Others can be arrays only if your config truly sets hasMany; we return boolean based on type here.\n return fieldType === 'text' || fieldType === 'textarea' || fieldType === 'select';\n}\n\nexport function fieldToJsonSchema(\n fieldInput: BaseField,\n opts?: { nameOverride?: string; wrapObject?: boolean },\n): JsonSchema {\n const field: BaseField = fieldInput || {};\n const name = isString(opts?.nameOverride) && opts?.nameOverride.length ? opts.nameOverride : (field.name || 'value');\n const type = field.type;\n\n let valueSchema: null | Record<string, any> = null;\n\n switch (type) {\n case 'code': {\n const base = codeSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n case 'date': {\n const base = dateSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'email': {\n const base = emailSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'json': {\n const base = jsonValueSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base as Record<string, any>;\n }\n break;\n }\n\n case 'number': {\n const base = numberWithBounds(field);\n if (field.hasMany) {\n // Respect hasMany only if truly configured; Payload rarely uses hasMany for number, but allow if present.\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'select': {\n const { values, valueType } = normalizeSelectOptions(field);\n const baseSingle: Record<string, any> = { type: valueType, enum: values };\n const description = getDescription(field);\n if (description) {baseSingle.description = description;}\n\n if (field.hasMany && supportsHasMany(type)) {\n valueSchema = {\n type: 'array',\n items: { type: valueType, enum: values },\n ...(description ? { description } : {}),\n };\n } else {\n valueSchema = baseSingle;\n }\n break;\n }\n\n case 'text':\n case 'textarea': {\n const base = stringWithDescription(field);\n if (field.hasMany && supportsHasMany(type)) {\n const arr: Record<string, any> = {\n type: 'array',\n items: { type: 'string' },\n };\n if (typeof field.minRows === 'number') {arr.minItems = field.minRows;}\n if (typeof field.maxRows === 'number') {arr.maxItems = field.maxRows;}\n if (base.description) {arr.description = base.description;}\n valueSchema = arr;\n } else {\n valueSchema = base;\n }\n break;\n }\n\n default: {\n // Unsupported type: return null to allow caller to decide how to proceed (e.g., no schema)\n valueSchema = null;\n break;\n }\n }\n\n const wrap = opts?.wrapObject !== false;\n\n if (!wrap) {\n return (valueSchema || {}) as JsonSchema;\n }\n\n if (!valueSchema) {\n // Return undefined-like schema if not supported; caller may choose to skip passing schema\n return {} as JsonSchema;\n }\n\n const schema: JsonSchema = {\n type: 'object',\n additionalProperties: false,\n properties: {\n [name]: valueSchema,\n },\n required: [name]\n };\n\n return schema;\n}\n"],"names":["isString","s","isPlainObject","o","Array","isArray","getDescription","field","d","admin","description","undefined","stringWithDescription","out","type","numberWithBounds","min","minimum","max","maximum","dateSchema","format","codeSchema","lang","language","trim","emailSchema","jsonValueSchema","jsonSchema","schema","normalizeSelectOptions","raw","options","values","opt","push","v","value","allNumbers","length","every","valueType","supportsHasMany","fieldType","fieldToJsonSchema","fieldInput","opts","name","nameOverride","valueSchema","base","hasMany","items","baseSingle","enum","arr","minRows","minItems","maxRows","maxItems","wrap","wrapObject","additionalProperties","properties","required"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/fieldToJsonSchema.ts"],"sourcesContent":["/**\n * fieldToJsonSchema\n * Convert a Payload Field (server or client) into a minimal JSON Schema object,\n * wrapped as { type: 'object', properties: { [name]: valueSchema }, required: [...] }\n *\n * Supported types:\n * - text, textarea, select, number, date, code, email, json\n * Arrays are emitted only when field.hasMany is true and the field type supports hasMany\n * (text, textarea, select; for others only if your config truly sets hasMany).\n */\nimport type { Field } from 'payload'\n\nexport type JsonSchema = Record<string, any>;\n\n// Narrowed minimal typing to avoid anywhere possible without pulling the full payload types at runtime.\n// In a Payload project, you can import type { Field, ClientField } from 'payload' and use those instead.\ntype BaseField = {\n admin?: {\n description?: unknown;\n language?: unknown;\n };\n hasMany?: boolean;\n // json\n jsonSchema?: unknown;\n max?: number;\n maxRows?: number;\n // number\n min?: number;\n // text/textarea\n minRows?: number;\n name?: string;\n // select\n options?: Array<\n | {\n label?: unknown;\n value: number | string;\n }\n | number\n | string\n >;\n required?: boolean;\n schema?: unknown;\n type?: string;\n typescriptSchema?: unknown;\n};\n\nfunction isString(s: unknown): s is string {\n return typeof s === 'string';\n}\n\nfunction isPlainObject(o: unknown): o is Record<string, unknown> {\n return !!o && typeof o === 'object' && !Array.isArray(o);\n}\n\nfunction getDescription(field: BaseField): string | undefined {\n const d = field?.admin?.description;\n return typeof d === 'string' ? d : undefined;\n}\n\nfunction stringWithDescription(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction numberWithBounds(field: BaseField) {\n const out: Record<string, any> = { type: 'number' };\n if (typeof field.min === 'number') {out.minimum = field.min;}\n if (typeof field.max === 'number') {out.maximum = field.max;}\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction dateSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'date-time' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction codeSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n let description = getDescription(field);\n const lang = field?.admin?.language;\n if (typeof lang === 'string' && lang.trim()) {\n description = description ? `${description} (language: ${lang})` : `language: ${lang}`;\n }\n if (description) {out.description = description;}\n return out;\n}\n\nfunction emailSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'email' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction jsonValueSchema(field: BaseField) {\n // Prefer a provided JSON Schema object\n if (isPlainObject(field.jsonSchema)) {return field.jsonSchema as object;}\n if (isPlainObject(field.schema)) {return field.schema as object;}\n\n // typescriptSchema cannot be executed here; default to object\n return { type: 'object' };\n}\n\nfunction normalizeSelectOptions(field: BaseField): { values: Array<number | string>; valueType: 'number' | 'string' } {\n const raw = field.options || [];\n const values: Array<number | string> = [];\n\n for (const opt of raw) {\n if (typeof opt === 'string' || typeof opt === 'number') {\n values.push(opt);\n } else if (isPlainObject(opt) && ('value' in opt)) {\n const v = (opt as any).value;\n if (typeof v === 'string' || typeof v === 'number') {\n values.push(v);\n }\n }\n }\n\n // Infer primitive type\n const allNumbers = values.length > 0 && values.every((v) => typeof v === 'number');\n const valueType: 'number' | 'string' = allNumbers ? 'number' : 'string';\n return { values, valueType };\n}\n\nfunction supportsHasMany(fieldType: string | undefined): boolean {\n // Out of the box: text, textarea, select support hasMany\n // Others can be arrays only if your config truly sets hasMany; we return boolean based on type here.\n return fieldType === 'text' || fieldType === 'textarea' || fieldType === 'select';\n}\n\nexport function fieldToJsonSchema(\n fieldInput: BaseField & Field,\n opts?: { nameOverride?: string; wrapObject?: boolean },\n): JsonSchema {\n const field = fieldInput || {};\n const name = isString(opts?.nameOverride) && opts?.nameOverride.length ? opts.nameOverride : (field.name || 'value');\n const type = field.type;\n\n let valueSchema: null | Record<string, any> = null;\n\n switch (type) {\n case 'array':\n case 'group': {\n if ('fields' in field && Array.isArray(field.fields)) {\n const properties: Record<string, any> = {}\n const required: string[] = []\n \n const processFields = (fields: any[]) => {\n for (const subField of fields) {\n if (subField.type === 'row' || subField.type === 'collapsible') {\n if (subField.fields) {processFields(subField.fields)}\n continue\n }\n if (!subField.name) {continue}\n\n const subSchema = fieldToJsonSchema(subField, { wrapObject: false })\n if (subSchema && Object.keys(subSchema).length > 0) {\n properties[subField.name] = subSchema\n if (subField.required) {required.push(subField.name)}\n }\n }\n }\n \n processFields(field.fields)\n\n const objSchema = {\n type: 'object',\n additionalProperties: false,\n properties,\n required: required.length ? required : undefined\n }\n\n if (type === 'array') {\n valueSchema = {\n type: 'array',\n items: objSchema\n }\n } else {\n valueSchema = objSchema\n }\n \n const description = getDescription(field);\n if (description) {valueSchema.description = description;}\n }\n break;\n }\n\n case 'checkbox': {\n valueSchema = { type: 'boolean' };\n const description = getDescription(field);\n if (description) {valueSchema.description = description;}\n break;\n }\n\n case 'code': {\n const base = codeSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'date': {\n const base = dateSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'email': {\n const base = emailSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'json': {\n const base = jsonValueSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base as Record<string, any>;\n }\n break;\n }\n\n case 'number': {\n const base = numberWithBounds(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n case 'select': {\n const { values, valueType } = normalizeSelectOptions(field);\n const baseSingle: Record<string, any> = { type: valueType, enum: values };\n const description = getDescription(field);\n if (description) {baseSingle.description = description;}\n\n if (field.hasMany && supportsHasMany(type)) {\n valueSchema = {\n type: 'array',\n items: { type: valueType, enum: values },\n ...(description ? { description } : {}),\n };\n } else {\n valueSchema = baseSingle;\n }\n break;\n }\n\n case 'text':\n case 'textarea': {\n const base = stringWithDescription(field);\n if (field.hasMany && supportsHasMany(type)) {\n const arr: Record<string, any> = {\n type: 'array',\n items: { type: 'string' },\n };\n if (typeof field.minRows === 'number') {arr.minItems = field.minRows;}\n if (typeof field.maxRows === 'number') {arr.maxItems = field.maxRows;}\n if (base.description) {arr.description = base.description;}\n valueSchema = arr;\n } else {\n valueSchema = base;\n }\n break;\n }\n \n // Explicitly handle organizational types to avoid default breakage if passed directly\n // though usually they are handled by parent recursion in group/array case above.\n // If passed as root, we can't really return a meaningful single-value schema without a wrapper?\n // But let's leave default for them or handle if necessary. \n // For now, if someone passes a 'row' as root, it will fall to default (null).\n\n default: {\n valueSchema = null;\n break;\n }\n }\n\n const wrap = opts?.wrapObject !== false;\n\n if (!wrap) {\n return (valueSchema || {}) as JsonSchema;\n }\n\n if (!valueSchema) {\n return {} as JsonSchema;\n }\n\n const schema: JsonSchema = {\n type: 'object',\n additionalProperties: false,\n properties: {\n [name]: valueSchema,\n },\n required: [name]\n };\n\n return schema;\n}\n"],"names":["isString","s","isPlainObject","o","Array","isArray","getDescription","field","d","admin","description","undefined","stringWithDescription","out","type","numberWithBounds","min","minimum","max","maximum","dateSchema","format","codeSchema","lang","language","trim","emailSchema","jsonValueSchema","jsonSchema","schema","normalizeSelectOptions","raw","options","values","opt","push","v","value","allNumbers","length","every","valueType","supportsHasMany","fieldType","fieldToJsonSchema","fieldInput","opts","name","nameOverride","valueSchema","fields","properties","required","processFields","subField","subSchema","wrapObject","Object","keys","objSchema","additionalProperties","items","base","hasMany","baseSingle","enum","arr","minRows","minItems","maxRows","maxItems","wrap"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
type AnyCollectionConfig =
|
|
1
|
+
import type { ClientCollectionConfig, CollectionConfig, Field } from 'payload';
|
|
2
|
+
type AnyCollectionConfig = ClientCollectionConfig | CollectionConfig;
|
|
3
3
|
/**
|
|
4
4
|
* Resolve a Payload field definition by a full schemaPath like:
|
|
5
5
|
* "{collectionSlug}.fieldA.subFieldB.blockSlug.innerField"
|
|
@@ -37,6 +37,21 @@
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
// Handle unnamed groups and collapsibles (they don't contribute to path)
|
|
41
|
+
// Groups without names are just wrappers, their children are at the same path level
|
|
42
|
+
if (field.type === 'group' && !field.name && field.fields) {
|
|
43
|
+
const foundInUnnamedGroup = findInFields(field.fields, segments);
|
|
44
|
+
if (foundInUnnamedGroup) {
|
|
45
|
+
return foundInUnnamedGroup;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Handle unnamed collapsibles similarly
|
|
49
|
+
if (field.type === 'collapsible' && field.fields) {
|
|
50
|
+
const foundInCollapsible = findInFields(field.fields, segments);
|
|
51
|
+
if (foundInCollapsible) {
|
|
52
|
+
return foundInCollapsible;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
40
55
|
if (field.name === current) {
|
|
41
56
|
// If this is the last segment, we found the target field
|
|
42
57
|
if (remaining.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/getFieldBySchemaPath.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getFieldBySchemaPath.ts"],"sourcesContent":["import type { ClientCollectionConfig, CollectionConfig, Field } from 'payload'\n\ntype AnyCollectionConfig = ClientCollectionConfig | CollectionConfig\n\n/**\n * Resolve a Payload field definition by a full schemaPath like:\n * \"{collectionSlug}.fieldA.subFieldB.blockSlug.innerField\"\n *\n * Notes:\n * - Tabs are a UI construct and are not part of schemaPath (fields inside tabs are at the same level).\n * - Blocks include the block slug as part of the path (we must consume it between the block field and its inner fields).\n * - Rows are skipped by this plugin's schema path mapping; support added defensively.\n */\nexport const getFieldBySchemaPath = (\n collectionConfig: AnyCollectionConfig,\n schemaPath: string,\n): Field | null => {\n if (!collectionConfig || !schemaPath) {\n return null\n }\n\n const parts = schemaPath.split('.')\n if (!parts.length) {\n return null\n }\n\n // Strip the collection slug prefix if present\n const [collectionSlug, ...rest] = parts\n const pathParts =\n collectionSlug === collectionConfig.slug ? rest.filter(Boolean) : parts.filter(Boolean)\n\n if (!pathParts.length) {\n return null\n }\n\n const findInFields = (fields: Field[], segments: string[]): Field | null => {\n if (!segments.length) {\n return null\n }\n\n const [current, ...remaining] = segments\n\n // First, try to match a field by name\n for (const field of fields) {\n // Tabs do not contribute to path segments; search inside all tabs with the same segments\n if ((field as any).tabs) {\n const tabs = (field as any).tabs as Array<{ fields?: Field[] }>\n for (const tab of tabs) {\n const foundInTab =\n tab.fields && tab.fields.length ? findInFields(tab.fields, segments) : null\n if (foundInTab) {\n return foundInTab\n }\n }\n }\n\n // Handle unnamed groups and collapsibles (they don't contribute to path)\n // Groups without names are just wrappers, their children are at the same path level\n if ((field as any).type === 'group' && !(field as any).name && (field as any).fields) {\n const foundInUnnamedGroup = findInFields((field as any).fields, segments)\n if (foundInUnnamedGroup) {\n return foundInUnnamedGroup\n }\n }\n\n // Handle unnamed collapsibles similarly\n if ((field as any).type === 'collapsible' && (field as any).fields) {\n const foundInCollapsible = findInFields((field as any).fields, segments)\n if (foundInCollapsible) {\n return foundInCollapsible\n }\n }\n\n if ((field as any).name === current) {\n // If this is the last segment, we found the target field\n if (remaining.length === 0) {\n return field\n }\n\n // Recurse into composite field types\n if ((field as any).fields && Array.isArray((field as any).fields)) {\n const found = findInFields((field as any).fields, remaining)\n if (found) {\n return found\n }\n }\n\n if ((field as any).blocks && Array.isArray((field as any).blocks)) {\n // Next segment should be a block slug, then continue into block fields\n if (!remaining.length) {\n return field\n } // path stops at block container (unlikely for our mapping)\n const [blockSlug, ...afterBlock] = remaining\n const blocks = (field as any).blocks as Array<{ fields: Field[]; slug: string }>\n const block = blocks.find((b) => b.slug === blockSlug)\n if (block) {\n const found = findInFields(block.fields, afterBlock)\n if (found) {\n return found\n }\n }\n }\n }\n }\n\n // Not found at this level\n return null\n }\n\n const rootFields = (collectionConfig as any).fields as Field[] | undefined\n if (!rootFields || !Array.isArray(rootFields)) {\n return null\n }\n\n return findInFields(rootFields, pathParts)\n}\n"],"names":["getFieldBySchemaPath","collectionConfig","schemaPath","parts","split","length","collectionSlug","rest","pathParts","slug","filter","Boolean","findInFields","fields","segments","current","remaining","field","tabs","tab","foundInTab","type","name","foundInUnnamedGroup","foundInCollapsible","Array","isArray","found","blocks","blockSlug","afterBlock","block","find","b","rootFields"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Field } from 'payload';
|
|
2
|
+
type UseCase = 'image' | 'text' | 'tts' | 'video';
|
|
3
|
+
/**
|
|
4
|
+
* Extract provider options fields for a given provider and use case.
|
|
5
|
+
* Returns the inner fields of the {useCase}ProviderOptions group.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getProviderOptionsFields(providerSlug: string, useCase: UseCase): Field[];
|
|
8
|
+
/**
|
|
9
|
+
* Get the default values from provider options fields
|
|
10
|
+
*/
|
|
11
|
+
export declare function getProviderOptionsDefaults(providerSlug: string, useCase: UseCase): Record<string, unknown>;
|
|
12
|
+
/**
|
|
13
|
+
* Check if a provider supports a given use case
|
|
14
|
+
*/
|
|
15
|
+
export declare function providerSupportsUseCase(providerSlug: string, useCase: UseCase): boolean;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { allProviderBlocks } from '../ai/providers/blocks/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get the provider options field group name for a given use case
|
|
4
|
+
*/ function getOptionsGroupName(useCase) {
|
|
5
|
+
return `${useCase}ProviderOptions`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Find a field by name within a block's fields, searching through tabs
|
|
9
|
+
*/ function findFieldInBlock(block, fieldName) {
|
|
10
|
+
const searchFields = (fields)=>{
|
|
11
|
+
for (const field of fields){
|
|
12
|
+
if ('name' in field && field.name === fieldName) {
|
|
13
|
+
return field;
|
|
14
|
+
}
|
|
15
|
+
if (field.type === 'tabs' && 'tabs' in field) {
|
|
16
|
+
for (const tab of field.tabs){
|
|
17
|
+
const found = searchFields(tab.fields);
|
|
18
|
+
if (found) {
|
|
19
|
+
return found;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (field.type === 'group' && 'fields' in field) {
|
|
24
|
+
const found = searchFields(field.fields);
|
|
25
|
+
if (found) {
|
|
26
|
+
return found;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
};
|
|
32
|
+
return searchFields(block.fields);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extract provider options fields for a given provider and use case.
|
|
36
|
+
* Returns the inner fields of the {useCase}ProviderOptions group.
|
|
37
|
+
*/ export function getProviderOptionsFields(providerSlug, useCase) {
|
|
38
|
+
const block = allProviderBlocks.find((b)=>b.slug === providerSlug);
|
|
39
|
+
if (!block) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
const groupName = getOptionsGroupName(useCase);
|
|
43
|
+
const optionsGroup = findFieldInBlock(block, groupName);
|
|
44
|
+
if (optionsGroup && optionsGroup.type === 'group' && 'fields' in optionsGroup) {
|
|
45
|
+
return optionsGroup.fields;
|
|
46
|
+
}
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the default values from provider options fields
|
|
51
|
+
*/ export function getProviderOptionsDefaults(providerSlug, useCase) {
|
|
52
|
+
const fields = getProviderOptionsFields(providerSlug, useCase);
|
|
53
|
+
const defaults = {};
|
|
54
|
+
for (const field of fields){
|
|
55
|
+
if ('name' in field && 'defaultValue' in field && field.defaultValue !== undefined) {
|
|
56
|
+
defaults[field.name] = field.defaultValue;
|
|
57
|
+
}
|
|
58
|
+
// Handle nested groups (like voice_settings in ElevenLabs)
|
|
59
|
+
if (field.type === 'group' && 'fields' in field && 'name' in field) {
|
|
60
|
+
const nestedDefaults = {};
|
|
61
|
+
for (const nestedField of field.fields){
|
|
62
|
+
if ('name' in nestedField && 'defaultValue' in nestedField && nestedField.defaultValue !== undefined) {
|
|
63
|
+
nestedDefaults[nestedField.name] = nestedField.defaultValue;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (Object.keys(nestedDefaults).length > 0) {
|
|
67
|
+
defaults[field.name] = nestedDefaults;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return defaults;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if a provider supports a given use case
|
|
75
|
+
*/ export function providerSupportsUseCase(providerSlug, useCase) {
|
|
76
|
+
const fields = getProviderOptionsFields(providerSlug, useCase);
|
|
77
|
+
return fields.length > 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=getProviderOptionsFields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getProviderOptionsFields.ts"],"sourcesContent":["import type { Block, ClientField, Field } from 'payload'\n\nimport { allProviderBlocks } from '../ai/providers/blocks/index.js'\n\ntype UseCase = 'image' | 'text' | 'tts' | 'video'\n\n/**\n * Get the provider options field group name for a given use case\n */\nfunction getOptionsGroupName(useCase: UseCase): string {\n return `${useCase}ProviderOptions`\n}\n\n/**\n * Find a field by name within a block's fields, searching through tabs\n */\nfunction findFieldInBlock(block: Block, fieldName: string): Field | undefined {\n const searchFields = (fields: Field[]): Field | undefined => {\n for (const field of fields) {\n if ('name' in field && field.name === fieldName) {\n return field\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n const found = searchFields(tab.fields)\n if (found) {return found}\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n const found = searchFields(field.fields)\n if (found) {return found}\n }\n }\n return undefined\n }\n \n return searchFields(block.fields)\n}\n\n/**\n * Extract provider options fields for a given provider and use case.\n * Returns the inner fields of the {useCase}ProviderOptions group.\n */\nexport function getProviderOptionsFields(\n providerSlug: string,\n useCase: UseCase\n): Field[] {\n const block = allProviderBlocks.find((b) => b.slug === providerSlug)\n if (!block) {\n return []\n }\n\n const groupName = getOptionsGroupName(useCase)\n const optionsGroup = findFieldInBlock(block, groupName)\n\n if (optionsGroup && optionsGroup.type === 'group' && 'fields' in optionsGroup) {\n return optionsGroup.fields\n }\n\n return []\n}\n\n/**\n * Get the default values from provider options fields\n */\nexport function getProviderOptionsDefaults(\n providerSlug: string,\n useCase: UseCase\n): Record<string, unknown> {\n const fields = getProviderOptionsFields(providerSlug, useCase)\n const defaults: Record<string, unknown> = {}\n\n for (const field of fields) {\n if ('name' in field && 'defaultValue' in field && field.defaultValue !== undefined) {\n defaults[field.name] = field.defaultValue\n }\n // Handle nested groups (like voice_settings in ElevenLabs)\n if (field.type === 'group' && 'fields' in field && 'name' in field) {\n const nestedDefaults: Record<string, unknown> = {}\n for (const nestedField of field.fields) {\n if ('name' in nestedField && 'defaultValue' in nestedField && nestedField.defaultValue !== undefined) {\n nestedDefaults[nestedField.name] = nestedField.defaultValue\n }\n }\n if (Object.keys(nestedDefaults).length > 0) {\n defaults[field.name] = nestedDefaults\n }\n }\n }\n\n return defaults\n}\n\n/**\n * Check if a provider supports a given use case\n */\nexport function providerSupportsUseCase(providerSlug: string, useCase: UseCase): boolean {\n const fields = getProviderOptionsFields(providerSlug, useCase)\n return fields.length > 0\n}\n"],"names":["allProviderBlocks","getOptionsGroupName","useCase","findFieldInBlock","block","fieldName","searchFields","fields","field","name","type","tab","tabs","found","undefined","getProviderOptionsFields","providerSlug","find","b","slug","groupName","optionsGroup","getProviderOptionsDefaults","defaults","defaultValue","nestedDefaults","nestedField","Object","keys","length","providerSupportsUseCase"],"mappings":"AAEA,SAASA,iBAAiB,QAAQ,kCAAiC;AAInE;;CAEC,GACD,SAASC,oBAAoBC,OAAgB;IAC3C,OAAO,CAAC,EAAEA,QAAQ,eAAe,CAAC;AACpC;AAEA;;CAEC,GACD,SAASC,iBAAiBC,KAAY,EAAEC,SAAiB;IACvD,MAAMC,eAAe,CAACC;QACpB,KAAK,MAAMC,SAASD,OAAQ;YAC1B,IAAI,UAAUC,SAASA,MAAMC,IAAI,KAAKJ,WAAW;gBAC/C,OAAOG;YACT;YACA,IAAIA,MAAME,IAAI,KAAK,UAAU,UAAUF,OAAO;gBAC5C,KAAK,MAAMG,OAAOH,MAAMI,IAAI,CAAE;oBAC5B,MAAMC,QAAQP,aAAaK,IAAIJ,MAAM;oBACrC,IAAIM,OAAO;wBAAC,OAAOA;oBAAK;gBAC1B;YACF;YACA,IAAIL,MAAME,IAAI,KAAK,WAAW,YAAYF,OAAO;gBAC/C,MAAMK,QAAQP,aAAaE,MAAMD,MAAM;gBACvC,IAAIM,OAAO;oBAAC,OAAOA;gBAAK;YAC1B;QACF;QACA,OAAOC;IACT;IAEA,OAAOR,aAAaF,MAAMG,MAAM;AAClC;AAEA;;;CAGC,GACD,OAAO,SAASQ,yBACdC,YAAoB,EACpBd,OAAgB;IAEhB,MAAME,QAAQJ,kBAAkBiB,IAAI,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKH;IACvD,IAAI,CAACZ,OAAO;QACV,OAAO,EAAE;IACX;IAEA,MAAMgB,YAAYnB,oBAAoBC;IACtC,MAAMmB,eAAelB,iBAAiBC,OAAOgB;IAE7C,IAAIC,gBAAgBA,aAAaX,IAAI,KAAK,WAAW,YAAYW,cAAc;QAC7E,OAAOA,aAAad,MAAM;IAC5B;IAEA,OAAO,EAAE;AACX;AAEA;;CAEC,GACD,OAAO,SAASe,2BACdN,YAAoB,EACpBd,OAAgB;IAEhB,MAAMK,SAASQ,yBAAyBC,cAAcd;IACtD,MAAMqB,WAAoC,CAAC;IAE3C,KAAK,MAAMf,SAASD,OAAQ;QAC1B,IAAI,UAAUC,SAAS,kBAAkBA,SAASA,MAAMgB,YAAY,KAAKV,WAAW;YAClFS,QAAQ,CAACf,MAAMC,IAAI,CAAC,GAAGD,MAAMgB,YAAY;QAC3C;QACA,2DAA2D;QAC3D,IAAIhB,MAAME,IAAI,KAAK,WAAW,YAAYF,SAAS,UAAUA,OAAO;YAClE,MAAMiB,iBAA0C,CAAC;YACjD,KAAK,MAAMC,eAAelB,MAAMD,MAAM,CAAE;gBACtC,IAAI,UAAUmB,eAAe,kBAAkBA,eAAeA,YAAYF,YAAY,KAAKV,WAAW;oBACpGW,cAAc,CAACC,YAAYjB,IAAI,CAAC,GAAGiB,YAAYF,YAAY;gBAC7D;YACF;YACA,IAAIG,OAAOC,IAAI,CAACH,gBAAgBI,MAAM,GAAG,GAAG;gBAC1CN,QAAQ,CAACf,MAAMC,IAAI,CAAC,GAAGgB;YACzB;QACF;IACF;IAEA,OAAOF;AACT;AAEA;;CAEC,GACD,OAAO,SAASO,wBAAwBd,YAAoB,EAAEd,OAAgB;IAC5E,MAAMK,SAASQ,yBAAyBC,cAAcd;IACtD,OAAOK,OAAOsB,MAAM,GAAG;AACzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/isPluginActivated.ts"],"sourcesContent":["import type { PluginConfig } from '../types.js'\n\
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/isPluginActivated.ts"],"sourcesContent":["import type { PluginConfig } from '../types.js'\n\nexport const isPluginActivated = (pluginConfig: PluginConfig) => {\n return !!pluginConfig\n}\n"],"names":["isPluginActivated","pluginConfig"],"mappings":"AAEA,OAAO,MAAMA,oBAAoB,CAACC;IAChC,OAAO,CAAC,CAACA;AACX,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/lexicalToHTML.ts"],"sourcesContent":["import type { SerializedEditorState } from 'lexical'\n\nimport {\n
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/lexicalToHTML.ts"],"sourcesContent":["import type { SerializedEditorState } from 'lexical'\n\nimport {\n consolidateHTMLConverters,\n convertLexicalToHTML,\n type SanitizedServerEditorConfig,\n} from '@payloadcms/richtext-lexical'\n\nexport async function lexicalToHTML(\n editorData: SerializedEditorState,\n editorConfig: SanitizedServerEditorConfig,\n) {\n return await convertLexicalToHTML({\n converters: consolidateHTMLConverters({ editorConfig }),\n data: editorData,\n })\n}\n"],"names":["consolidateHTMLConverters","convertLexicalToHTML","lexicalToHTML","editorData","editorConfig","converters","data"],"mappings":"AAEA,SACEA,yBAAyB,EACzBC,oBAAoB,QAEf,+BAA8B;AAErC,OAAO,eAAeC,cACpBC,UAAiC,EACjCC,YAAyC;IAEzC,OAAO,MAAMH,qBAAqB;QAChCI,YAAYL,0BAA0B;YAAEI;QAAa;QACrDE,MAAMH;IACR;AACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PayloadRequest } from 'payload';
|
|
2
|
+
export interface ResolvedImage {
|
|
3
|
+
image: {
|
|
4
|
+
mimeType?: string;
|
|
5
|
+
name: string;
|
|
6
|
+
thumbnailURL?: string;
|
|
7
|
+
type: string;
|
|
8
|
+
url: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
interface ResolveImageReferencesResult {
|
|
12
|
+
images: ResolvedImage[];
|
|
13
|
+
processedPrompt: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parses and resolves image references in prompts.
|
|
17
|
+
*
|
|
18
|
+
* Supports two formats:
|
|
19
|
+
* - @fieldName - for single upload fields
|
|
20
|
+
* - @collection.fieldName - schema path format (collection prefix is stripped)
|
|
21
|
+
* - @fieldName:filename.jpg - for specific images in hasMany fields
|
|
22
|
+
*
|
|
23
|
+
* @param prompt - The prompt text containing @field references
|
|
24
|
+
* @param contextData - The document data to resolve field values from
|
|
25
|
+
* @param req - Payload request object for fetching media
|
|
26
|
+
* @param collectionSlug - Optional collection slug to strip from schema path references
|
|
27
|
+
* @returns Processed prompt with references removed and array of resolved images
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveImageReferences(prompt: string, contextData: Record<string, unknown>, req: PayloadRequest, collectionSlug?: string): Promise<ResolveImageReferencesResult>;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrieves a nested value from an object using dot-notation path.
|
|
3
|
+
* For example, getNestedValue(obj, 'a.b.c') returns obj.a.b.c
|
|
4
|
+
*/ function getNestedValue(obj, path) {
|
|
5
|
+
return path.split('.').reduce((current, key)=>{
|
|
6
|
+
if (current && typeof current === 'object' && key in current) {
|
|
7
|
+
return current[key];
|
|
8
|
+
}
|
|
9
|
+
return undefined;
|
|
10
|
+
}, obj);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parses and resolves image references in prompts.
|
|
14
|
+
*
|
|
15
|
+
* Supports two formats:
|
|
16
|
+
* - @fieldName - for single upload fields
|
|
17
|
+
* - @collection.fieldName - schema path format (collection prefix is stripped)
|
|
18
|
+
* - @fieldName:filename.jpg - for specific images in hasMany fields
|
|
19
|
+
*
|
|
20
|
+
* @param prompt - The prompt text containing @field references
|
|
21
|
+
* @param contextData - The document data to resolve field values from
|
|
22
|
+
* @param req - Payload request object for fetching media
|
|
23
|
+
* @param collectionSlug - Optional collection slug to strip from schema path references
|
|
24
|
+
* @returns Processed prompt with references removed and array of resolved images
|
|
25
|
+
*/ export async function resolveImageReferences(prompt, contextData, req, collectionSlug) {
|
|
26
|
+
// Pattern matches: @fieldName or @fieldName:filename.ext (filename can have spaces)
|
|
27
|
+
// The filename part matches everything up to and including an image extension
|
|
28
|
+
const pattern = /@([\w.]+)(?::(.+?\.(?:png|jpe?g|webp|gif)))?/gi;
|
|
29
|
+
const references = [];
|
|
30
|
+
let match;
|
|
31
|
+
// Extract all image references
|
|
32
|
+
while((match = pattern.exec(prompt)) !== null){
|
|
33
|
+
references.push({
|
|
34
|
+
fieldName: match[1],
|
|
35
|
+
filename: match[2],
|
|
36
|
+
fullMatch: match[0]
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (references.length === 0) {
|
|
40
|
+
return {
|
|
41
|
+
images: [],
|
|
42
|
+
processedPrompt: prompt
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const resolvedImages = [];
|
|
46
|
+
let processedPrompt = prompt;
|
|
47
|
+
// Resolve each reference
|
|
48
|
+
for (const ref of references){
|
|
49
|
+
try {
|
|
50
|
+
// Strip collection prefix from schema path if it matches the current collection
|
|
51
|
+
// e.g., "characters.ortho3d.frame" becomes "ortho3d.frame" when collectionSlug is "characters"
|
|
52
|
+
let fieldPath = ref.fieldName;
|
|
53
|
+
if (collectionSlug && fieldPath.startsWith(`${collectionSlug}.`)) {
|
|
54
|
+
fieldPath = fieldPath.slice(collectionSlug.length + 1);
|
|
55
|
+
}
|
|
56
|
+
const fieldValue = getNestedValue(contextData, fieldPath);
|
|
57
|
+
if (!fieldValue) {
|
|
58
|
+
req.payload.logger.warn(`Image reference @${ref.fieldName} not found in document context`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
// Handle single upload field (value is an ID or object)
|
|
62
|
+
if (!ref.filename) {
|
|
63
|
+
const mediaDoc = await resolveMediaDocument(fieldValue, req);
|
|
64
|
+
if (mediaDoc) {
|
|
65
|
+
resolvedImages.push(formatImageData(mediaDoc));
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
const mediaDoc = await resolveMediaFromArray(fieldValue, ref.filename, req);
|
|
69
|
+
if (mediaDoc) {
|
|
70
|
+
resolvedImages.push(formatImageData(mediaDoc));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Remove the reference from the prompt
|
|
74
|
+
processedPrompt = processedPrompt.replace(ref.fullMatch, '');
|
|
75
|
+
} catch (error) {
|
|
76
|
+
req.payload.logger.error(error, `Error resolving image reference: ${ref.fullMatch}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Clean up extra whitespace from removed references
|
|
80
|
+
processedPrompt = processedPrompt.replace(/\s+/g, ' ').trim();
|
|
81
|
+
return {
|
|
82
|
+
images: resolvedImages,
|
|
83
|
+
processedPrompt
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Resolves a single media document from an ID or populated object
|
|
88
|
+
*/ async function resolveMediaDocument(value, req) {
|
|
89
|
+
// If it's already a populated object with required fields
|
|
90
|
+
if (typeof value === 'object' && value !== null && 'url' in value) {
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
// If it's an ID string, fetch the media document
|
|
94
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
95
|
+
try {
|
|
96
|
+
// Try to find which collection this media belongs to
|
|
97
|
+
// First, check the common 'media' collection
|
|
98
|
+
const collections = [
|
|
99
|
+
'media',
|
|
100
|
+
'uploads'
|
|
101
|
+
];
|
|
102
|
+
for (const collectionSlug of collections){
|
|
103
|
+
try {
|
|
104
|
+
const mediaDoc = await req.payload.findByID({
|
|
105
|
+
id: value,
|
|
106
|
+
collection: collectionSlug,
|
|
107
|
+
req
|
|
108
|
+
});
|
|
109
|
+
if (mediaDoc) {
|
|
110
|
+
return mediaDoc;
|
|
111
|
+
}
|
|
112
|
+
} catch (_ignore) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
req.payload.logger.error(error, 'Error fetching media document');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Resolves a specific media document from an array by matching filename
|
|
124
|
+
*/ async function resolveMediaFromArray(arrayValue, filename, req) {
|
|
125
|
+
if (!Array.isArray(arrayValue)) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
// Search through array for matching filename
|
|
129
|
+
for (const item of arrayValue){
|
|
130
|
+
const mediaDoc = await resolveMediaDocument(item, req);
|
|
131
|
+
if (mediaDoc && matchesFilename(mediaDoc, filename)) {
|
|
132
|
+
return mediaDoc;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Checks if a media document matches the given filename
|
|
139
|
+
*/ function matchesFilename(mediaDoc, filename) {
|
|
140
|
+
const docFilename = mediaDoc.filename || mediaDoc.name;
|
|
141
|
+
if (!docFilename) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
// Case-insensitive match
|
|
145
|
+
return docFilename.toLowerCase() === filename.toLowerCase();
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Formats media document into the expected image data structure
|
|
149
|
+
*/ function formatImageData(mediaDoc) {
|
|
150
|
+
return {
|
|
151
|
+
image: {
|
|
152
|
+
name: mediaDoc.filename || mediaDoc.name || 'unknown',
|
|
153
|
+
type: extractFileExtension(mediaDoc.filename || mediaDoc.name || ''),
|
|
154
|
+
mimeType: mediaDoc.mimeType || mediaDoc.mimetype,
|
|
155
|
+
thumbnailURL: mediaDoc.thumbnailURL,
|
|
156
|
+
url: mediaDoc.url
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Extracts file extension from filename
|
|
162
|
+
*/ function extractFileExtension(filename) {
|
|
163
|
+
const match = filename.match(/\.([^.]+)$/);
|
|
164
|
+
return match ? match[1].toLowerCase() : 'unknown';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=resolveImageReferences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/resolveImageReferences.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\ninterface ImageReference {\n fieldName: string\n filename?: string\n fullMatch: string\n}\n\nexport interface ResolvedImage {\n image: {\n mimeType?: string\n name: string\n thumbnailURL?: string\n type: string\n url: string\n }\n}\n\ninterface ResolveImageReferencesResult {\n images: ResolvedImage[]\n processedPrompt: string\n}\n\n/**\n * Retrieves a nested value from an object using dot-notation path.\n * For example, getNestedValue(obj, 'a.b.c') returns obj.a.b.c\n */\nfunction getNestedValue(obj: Record<string, unknown>, path: string): unknown {\n return path.split('.').reduce((current, key) => {\n if (current && typeof current === 'object' && key in current) {\n return (current as Record<string, unknown>)[key]\n }\n return undefined\n }, obj as unknown)\n}\n\n/**\n * Parses and resolves image references in prompts.\n * \n * Supports two formats:\n * - @fieldName - for single upload fields\n * - @collection.fieldName - schema path format (collection prefix is stripped)\n * - @fieldName:filename.jpg - for specific images in hasMany fields\n * \n * @param prompt - The prompt text containing @field references\n * @param contextData - The document data to resolve field values from\n * @param req - Payload request object for fetching media\n * @param collectionSlug - Optional collection slug to strip from schema path references\n * @returns Processed prompt with references removed and array of resolved images\n */\nexport async function resolveImageReferences(\n prompt: string,\n contextData: Record<string, unknown>,\n req: PayloadRequest,\n collectionSlug?: string,\n): Promise<ResolveImageReferencesResult> {\n // Pattern matches: @fieldName or @fieldName:filename.ext (filename can have spaces)\n // The filename part matches everything up to and including an image extension\n const pattern = /@([\\w.]+)(?::(.+?\\.(?:png|jpe?g|webp|gif)))?/gi\n const references: ImageReference[] = []\n let match: null | RegExpExecArray\n\n // Extract all image references\n while ((match = pattern.exec(prompt)) !== null) {\n references.push({\n fieldName: match[1],\n filename: match[2],\n fullMatch: match[0],\n })\n }\n\n if (references.length === 0) {\n return { images: [], processedPrompt: prompt }\n }\n\n const resolvedImages: ResolvedImage[] = []\n let processedPrompt = prompt\n\n // Resolve each reference\n for (const ref of references) {\n try {\n // Strip collection prefix from schema path if it matches the current collection\n // e.g., \"characters.ortho3d.frame\" becomes \"ortho3d.frame\" when collectionSlug is \"characters\"\n let fieldPath = ref.fieldName\n if (collectionSlug && fieldPath.startsWith(`${collectionSlug}.`)) {\n fieldPath = fieldPath.slice(collectionSlug.length + 1)\n }\n\n const fieldValue = getNestedValue(contextData, fieldPath)\n\n if (!fieldValue) {\n req.payload.logger.warn(\n `Image reference @${ref.fieldName} not found in document context`,\n )\n continue\n }\n\n // Handle single upload field (value is an ID or object)\n if (!ref.filename) {\n const mediaDoc = await resolveMediaDocument(fieldValue, req)\n if (mediaDoc) {\n resolvedImages.push(formatImageData(mediaDoc))\n }\n }\n // Handle hasMany field with filename\n else {\n const mediaDoc = await resolveMediaFromArray(fieldValue, ref.filename, req)\n if (mediaDoc) {\n resolvedImages.push(formatImageData(mediaDoc))\n }\n }\n\n // Remove the reference from the prompt\n processedPrompt = processedPrompt.replace(ref.fullMatch, '')\n } catch (error) {\n req.payload.logger.error(\n error,\n `Error resolving image reference: ${ref.fullMatch}`,\n )\n }\n }\n\n // Clean up extra whitespace from removed references\n processedPrompt = processedPrompt.replace(/\\s+/g, ' ').trim()\n\n return {\n images: resolvedImages,\n processedPrompt,\n }\n}\n\n/**\n * Resolves a single media document from an ID or populated object\n */\nasync function resolveMediaDocument(\n value: unknown,\n req: PayloadRequest,\n): Promise<null | Record<string, unknown>> {\n // If it's already a populated object with required fields\n if (typeof value === 'object' && value !== null && 'url' in value) {\n return value as Record<string, unknown>\n }\n\n // If it's an ID string, fetch the media document\n if (typeof value === 'string' || typeof value === 'number') {\n try {\n // Try to find which collection this media belongs to\n // First, check the common 'media' collection\n const collections = ['media', 'uploads']\n\n for (const collectionSlug of collections) {\n try {\n const mediaDoc = await req.payload.findByID({\n id: value,\n collection: collectionSlug,\n req,\n })\n if (mediaDoc) {\n return mediaDoc as Record<string, unknown>\n }\n } catch (_ignore) {\n // Continue to next collection\n continue\n }\n }\n } catch (error) {\n req.payload.logger.error(error, 'Error fetching media document')\n }\n }\n\n return null\n}\n\n/**\n * Resolves a specific media document from an array by matching filename\n */\nasync function resolveMediaFromArray(\n arrayValue: unknown,\n filename: string,\n req: PayloadRequest,\n): Promise<null | Record<string, unknown>> {\n if (!Array.isArray(arrayValue)) {\n return null\n }\n\n // Search through array for matching filename\n for (const item of arrayValue) {\n const mediaDoc = await resolveMediaDocument(item, req)\n\n if (mediaDoc && matchesFilename(mediaDoc, filename)) {\n return mediaDoc\n }\n }\n\n return null\n}\n\n/**\n * Checks if a media document matches the given filename\n */\nfunction matchesFilename(mediaDoc: Record<string, unknown>, filename: string): boolean {\n const docFilename = mediaDoc.filename || mediaDoc.name\n\n if (!docFilename) {\n return false\n }\n\n // Case-insensitive match\n return (docFilename as string).toLowerCase() === filename.toLowerCase()\n}\n\n/**\n * Formats media document into the expected image data structure\n */\nfunction formatImageData(mediaDoc: Record<string, unknown>): ResolvedImage {\n return {\n image: {\n name: (mediaDoc.filename || mediaDoc.name || 'unknown') as string,\n type: extractFileExtension((mediaDoc.filename || mediaDoc.name || '') as string),\n mimeType: (mediaDoc.mimeType || mediaDoc.mimetype) as string | undefined,\n thumbnailURL: mediaDoc.thumbnailURL as string | undefined,\n url: mediaDoc.url as string,\n },\n }\n}\n\n/**\n * Extracts file extension from filename\n */\nfunction extractFileExtension(filename: string): string {\n const match = filename.match(/\\.([^.]+)$/)\n return match ? match[1].toLowerCase() : 'unknown'\n}\n"],"names":["getNestedValue","obj","path","split","reduce","current","key","undefined","resolveImageReferences","prompt","contextData","req","collectionSlug","pattern","references","match","exec","push","fieldName","filename","fullMatch","length","images","processedPrompt","resolvedImages","ref","fieldPath","startsWith","slice","fieldValue","payload","logger","warn","mediaDoc","resolveMediaDocument","formatImageData","resolveMediaFromArray","replace","error","trim","value","collections","findByID","id","collection","_ignore","arrayValue","Array","isArray","item","matchesFilename","docFilename","name","toLowerCase","image","type","extractFileExtension","mimeType","mimetype","thumbnailURL","url"],"mappings":"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"}
|