@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.
Files changed (313) hide show
  1. package/{LICENSE.md → LICENSE} +1 -1
  2. package/README.md +218 -229
  3. package/dist/access/checkAccess.d.ts +4 -0
  4. package/dist/access/checkAccess.js +20 -0
  5. package/dist/access/checkAccess.js.map +1 -0
  6. package/dist/ai/core/generateObject.d.ts +7 -0
  7. package/dist/ai/core/generateObject.js +35 -0
  8. package/dist/ai/core/generateObject.js.map +1 -0
  9. package/dist/ai/core/generateText.d.ts +7 -0
  10. package/dist/ai/core/generateText.js +31 -0
  11. package/dist/ai/core/generateText.js.map +1 -0
  12. package/dist/ai/core/index.d.ts +11 -0
  13. package/dist/ai/core/index.js +10 -0
  14. package/dist/ai/core/index.js.map +1 -0
  15. package/dist/ai/core/media/generateMedia.d.ts +7 -0
  16. package/dist/ai/core/media/generateMedia.js +50 -0
  17. package/dist/ai/core/media/generateMedia.js.map +1 -0
  18. package/dist/ai/core/media/image/generateImage.d.ts +6 -0
  19. package/dist/ai/core/media/image/generateImage.js +41 -0
  20. package/dist/ai/core/media/image/generateImage.js.map +1 -0
  21. package/dist/ai/core/media/image/handlers/multimodal.d.ts +7 -0
  22. package/dist/ai/core/media/image/handlers/multimodal.js +100 -0
  23. package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -0
  24. package/dist/ai/core/media/image/handlers/standard.d.ts +7 -0
  25. package/dist/ai/core/media/image/handlers/standard.js +28 -0
  26. package/dist/ai/core/media/image/handlers/standard.js.map +1 -0
  27. package/dist/ai/core/media/image/index.d.ts +2 -0
  28. package/dist/ai/core/media/image/index.js +3 -0
  29. package/dist/ai/core/media/image/index.js.map +1 -0
  30. package/dist/ai/core/media/index.d.ts +2 -0
  31. package/dist/ai/core/media/index.js +3 -0
  32. package/dist/ai/core/media/index.js.map +1 -0
  33. package/dist/ai/core/media/speech/generateSpeech.d.ts +5 -0
  34. package/dist/ai/core/media/speech/generateSpeech.js +55 -0
  35. package/dist/ai/core/media/speech/generateSpeech.js.map +1 -0
  36. package/dist/ai/core/media/speech/index.d.ts +2 -0
  37. package/dist/ai/core/media/speech/index.js +3 -0
  38. package/dist/ai/core/media/speech/index.js.map +1 -0
  39. package/dist/ai/core/media/types.d.ts +74 -0
  40. package/dist/ai/core/media/types.js +5 -0
  41. package/dist/ai/core/media/types.js.map +1 -0
  42. package/dist/ai/core/media/utils.d.ts +11 -0
  43. package/dist/ai/core/media/utils.js +34 -0
  44. package/dist/ai/core/media/utils.js.map +1 -0
  45. package/dist/ai/core/media/video/generateVideo.d.ts +6 -0
  46. package/dist/ai/core/media/video/generateVideo.js +32 -0
  47. package/dist/ai/core/media/video/generateVideo.js.map +1 -0
  48. package/dist/ai/core/media/video/index.d.ts +2 -0
  49. package/dist/ai/core/media/video/index.js +3 -0
  50. package/dist/ai/core/media/video/index.js.map +1 -0
  51. package/dist/ai/core/streamObject.d.ts +7 -0
  52. package/dist/ai/core/streamObject.js +54 -0
  53. package/dist/ai/core/streamObject.js.map +1 -0
  54. package/dist/ai/core/streamText.d.ts +7 -0
  55. package/dist/ai/core/streamText.js +30 -0
  56. package/dist/ai/core/streamText.js.map +1 -0
  57. package/dist/ai/core/types.d.ts +85 -0
  58. package/dist/ai/core/types.js +5 -0
  59. package/dist/ai/core/types.js.map +1 -0
  60. package/dist/ai/index.d.ts +11 -0
  61. package/dist/ai/index.js +25 -0
  62. package/dist/ai/index.js.map +1 -0
  63. package/dist/ai/providers/blocks/anthropic.d.ts +2 -0
  64. package/dist/ai/providers/blocks/anthropic.js +223 -0
  65. package/dist/ai/providers/blocks/anthropic.js.map +1 -0
  66. package/dist/ai/providers/blocks/elevenlabs.d.ts +2 -0
  67. package/dist/ai/providers/blocks/elevenlabs.js +449 -0
  68. package/dist/ai/providers/blocks/elevenlabs.js.map +1 -0
  69. package/dist/ai/providers/blocks/fal.d.ts +2 -0
  70. package/dist/ai/providers/blocks/fal.js +312 -0
  71. package/dist/ai/providers/blocks/fal.js.map +1 -0
  72. package/dist/ai/providers/blocks/google.d.ts +2 -0
  73. package/dist/ai/providers/blocks/google.js +623 -0
  74. package/dist/ai/providers/blocks/google.js.map +1 -0
  75. package/dist/ai/providers/blocks/index.d.ts +2 -0
  76. package/dist/ai/providers/blocks/index.js +18 -0
  77. package/dist/ai/providers/blocks/index.js.map +1 -0
  78. package/dist/ai/providers/blocks/openai-compatible.d.ts +2 -0
  79. package/dist/ai/providers/blocks/openai-compatible.js +308 -0
  80. package/dist/ai/providers/blocks/openai-compatible.js.map +1 -0
  81. package/dist/ai/providers/blocks/openai.d.ts +2 -0
  82. package/dist/ai/providers/blocks/openai.js +600 -0
  83. package/dist/ai/providers/blocks/openai.js.map +1 -0
  84. package/dist/ai/providers/blocks/xai.d.ts +2 -0
  85. package/dist/ai/providers/blocks/xai.js +247 -0
  86. package/dist/ai/providers/blocks/xai.js.map +1 -0
  87. package/dist/ai/providers/icons.d.ts +7 -0
  88. package/dist/ai/providers/icons.js +9 -0
  89. package/dist/ai/providers/icons.js.map +1 -0
  90. package/dist/ai/providers/index.d.ts +2 -0
  91. package/dist/ai/providers/index.js +6 -0
  92. package/dist/ai/providers/index.js.map +1 -0
  93. package/dist/ai/providers/registry.d.ts +40 -0
  94. package/dist/ai/providers/registry.js +267 -0
  95. package/dist/ai/providers/registry.js.map +1 -0
  96. package/dist/ai/providers/types.d.ts +115 -0
  97. package/dist/ai/providers/types.js +4 -0
  98. package/dist/ai/providers/types.js.map +1 -0
  99. package/dist/ai/utils/systemGenerate.d.ts +1 -1
  100. package/dist/ai/utils/systemGenerate.js +19 -19
  101. package/dist/ai/utils/systemGenerate.js.map +1 -1
  102. package/dist/collections/AIJobs.d.ts +2 -0
  103. package/dist/collections/AIJobs.js +81 -0
  104. package/dist/collections/AIJobs.js.map +1 -0
  105. package/dist/collections/AISettings.d.ts +2 -0
  106. package/dist/collections/AISettings.js +279 -0
  107. package/dist/collections/AISettings.js.map +1 -0
  108. package/dist/collections/Instructions.js +224 -50
  109. package/dist/collections/Instructions.js.map +1 -1
  110. package/dist/defaults.d.ts +3 -0
  111. package/dist/defaults.js +3 -0
  112. package/dist/defaults.js.map +1 -1
  113. package/dist/endpoints/buildPromptUtils.d.ts +19 -0
  114. package/dist/endpoints/buildPromptUtils.js +114 -0
  115. package/dist/endpoints/buildPromptUtils.js.map +1 -0
  116. package/dist/endpoints/chat.d.ts +4 -0
  117. package/dist/endpoints/fetchFields.js +0 -7
  118. package/dist/endpoints/fetchFields.js.map +1 -1
  119. package/dist/endpoints/fetchVoices.d.ts +2 -0
  120. package/dist/endpoints/fetchVoices.js +79 -0
  121. package/dist/endpoints/fetchVoices.js.map +1 -0
  122. package/dist/endpoints/index.js +339 -232
  123. package/dist/endpoints/index.js.map +1 -1
  124. package/dist/exports/client.d.ts +9 -0
  125. package/dist/exports/client.js +9 -0
  126. package/dist/exports/client.js.map +1 -1
  127. package/dist/exports/fields.d.ts +1 -0
  128. package/dist/exports/fields.js +1 -0
  129. package/dist/exports/fields.js.map +1 -1
  130. package/dist/fields/ArrayComposeField/ArrayComposeField.d.ts +15 -0
  131. package/dist/fields/ArrayComposeField/ArrayComposeField.js +87 -0
  132. package/dist/fields/ArrayComposeField/ArrayComposeField.js.map +1 -0
  133. package/dist/fields/ArrayComposeField/ArrayComposeField.jsx +73 -0
  134. package/dist/fields/ComposeField/ComposeField.js +2 -2
  135. package/dist/fields/ComposeField/ComposeField.js.map +1 -1
  136. package/dist/fields/ComposeField/ComposeField.jsx +2 -2
  137. package/dist/fields/PromptEditorField/PromptEditorField.js +162 -16
  138. package/dist/fields/PromptEditorField/PromptEditorField.js.map +1 -1
  139. package/dist/fields/PromptEditorField/PromptEditorField.jsx +123 -5
  140. package/dist/index.d.ts +3 -0
  141. package/dist/index.js +1 -0
  142. package/dist/index.js.map +1 -1
  143. package/dist/init.js +63 -65
  144. package/dist/init.js.map +1 -1
  145. package/dist/payload-ai.d.ts +149 -0
  146. package/dist/plugin.js +94 -46
  147. package/dist/plugin.js.map +1 -1
  148. package/dist/providers/InstructionsProvider/InstructionsProvider.js +38 -7
  149. package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
  150. package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +30 -4
  151. package/dist/providers/InstructionsProvider/context.d.ts +1 -0
  152. package/dist/providers/InstructionsProvider/context.js +1 -0
  153. package/dist/providers/InstructionsProvider/context.js.map +1 -1
  154. package/dist/providers/InstructionsProvider/useInstructions.js +30 -10
  155. package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
  156. package/dist/styles.d.ts +11 -0
  157. package/dist/types/handlebars-async-helpers.d.ts +1 -0
  158. package/dist/types/handlebars-dist-handlebars.d.ts +1 -0
  159. package/dist/types/react-mentions.d.ts +1 -0
  160. package/dist/types.d.ts +6 -16
  161. package/dist/types.js.map +1 -1
  162. package/dist/ui/AIConfigDashboard/index.d.ts +2 -0
  163. package/dist/ui/AIConfigDashboard/index.js +46 -0
  164. package/dist/ui/AIConfigDashboard/index.js.map +1 -0
  165. package/dist/ui/AIConfigDashboard/index.jsx +24 -0
  166. package/dist/ui/ApiKeyStatusIndicator/index.d.ts +6 -0
  167. package/dist/ui/ApiKeyStatusIndicator/index.js +39 -0
  168. package/dist/ui/ApiKeyStatusIndicator/index.js.map +1 -0
  169. package/dist/ui/ApiKeyStatusIndicator/index.jsx +29 -0
  170. package/dist/ui/Compose/Compose.d.ts +2 -2
  171. package/dist/ui/Compose/Compose.js +118 -92
  172. package/dist/ui/Compose/Compose.js.map +1 -1
  173. package/dist/ui/Compose/Compose.jsx +113 -103
  174. package/dist/ui/Compose/ComposePlaceholder.d.ts +7 -0
  175. package/dist/ui/Compose/ComposePlaceholder.js +78 -0
  176. package/dist/ui/Compose/ComposePlaceholder.js.map +1 -0
  177. package/dist/ui/Compose/ComposePlaceholder.jsx +66 -0
  178. package/dist/ui/Compose/UndoRedoActions.d.ts +2 -2
  179. package/dist/ui/Compose/UndoRedoActions.js +11 -6
  180. package/dist/ui/Compose/UndoRedoActions.js.map +1 -1
  181. package/dist/ui/Compose/UndoRedoActions.jsx +8 -6
  182. package/dist/ui/Compose/compose.module.css +57 -17
  183. package/dist/ui/Compose/hooks/menu/itemsMap.js +13 -7
  184. package/dist/ui/Compose/hooks/menu/itemsMap.js.map +1 -1
  185. package/dist/ui/Compose/hooks/menu/useMenu.d.ts +2 -1
  186. package/dist/ui/Compose/hooks/menu/useMenu.js +28 -17
  187. package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
  188. package/dist/ui/Compose/hooks/menu/useMenu.jsx +27 -14
  189. package/dist/ui/Compose/hooks/useActiveFieldTracking.js +69 -10
  190. package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
  191. package/dist/ui/Compose/hooks/useGenerate.d.ts +3 -0
  192. package/dist/ui/Compose/hooks/useGenerate.js +71 -11
  193. package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
  194. package/dist/ui/Compose/hooks/useHistory.d.ts +0 -1
  195. package/dist/ui/Compose/hooks/useHistory.js +113 -26
  196. package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
  197. package/dist/ui/DynamicModelSelect/index.d.ts +7 -0
  198. package/dist/ui/DynamicModelSelect/index.js +231 -0
  199. package/dist/ui/DynamicModelSelect/index.js.map +1 -0
  200. package/dist/ui/DynamicModelSelect/index.jsx +207 -0
  201. package/dist/ui/DynamicProviderSelect/index.d.ts +7 -0
  202. package/dist/ui/DynamicProviderSelect/index.js +101 -0
  203. package/dist/ui/DynamicProviderSelect/index.js.map +1 -0
  204. package/dist/ui/DynamicProviderSelect/index.jsx +90 -0
  205. package/dist/ui/DynamicVoiceSelect/index.d.ts +7 -0
  206. package/dist/ui/DynamicVoiceSelect/index.js +156 -0
  207. package/dist/ui/DynamicVoiceSelect/index.js.map +1 -0
  208. package/dist/ui/DynamicVoiceSelect/index.jsx +102 -0
  209. package/dist/ui/EncryptedTextField/index.d.ts +8 -0
  210. package/dist/ui/EncryptedTextField/index.js +74 -0
  211. package/dist/ui/EncryptedTextField/index.js.map +1 -0
  212. package/dist/ui/EncryptedTextField/index.jsx +35 -0
  213. package/dist/ui/Icons/LottieAnimation.js +3 -1
  214. package/dist/ui/Icons/LottieAnimation.js.map +1 -1
  215. package/dist/ui/Icons/LottieAnimation.jsx +2 -1
  216. package/dist/ui/ModelRowLabel/index.d.ts +6 -0
  217. package/dist/ui/ModelRowLabel/index.js +41 -0
  218. package/dist/ui/ModelRowLabel/index.js.map +1 -0
  219. package/dist/ui/ModelRowLabel/index.jsx +26 -0
  220. package/dist/ui/ProviderOptionsEditor/index.d.ts +7 -0
  221. package/dist/ui/ProviderOptionsEditor/index.js +291 -0
  222. package/dist/ui/ProviderOptionsEditor/index.js.map +1 -0
  223. package/dist/ui/ProviderOptionsEditor/index.jsx +210 -0
  224. package/dist/ui/VoicesFetcher/index.d.ts +7 -0
  225. package/dist/ui/VoicesFetcher/index.js +118 -0
  226. package/dist/ui/VoicesFetcher/index.js.map +1 -0
  227. package/dist/ui/VoicesFetcher/index.jsx +79 -0
  228. package/dist/utilities/buildSmartPrompt.d.ts +22 -0
  229. package/dist/utilities/buildSmartPrompt.js +143 -0
  230. package/dist/utilities/buildSmartPrompt.js.map +1 -0
  231. package/dist/utilities/encryption.d.ts +2 -0
  232. package/dist/utilities/encryption.js +47 -0
  233. package/dist/utilities/encryption.js.map +1 -0
  234. package/dist/utilities/extractImageData.d.ts +9 -0
  235. package/dist/utilities/extractImageData.js +12 -2
  236. package/dist/utilities/extractImageData.js.map +1 -1
  237. package/dist/utilities/fetchImages.d.ts +14 -0
  238. package/dist/utilities/fetchImages.js +38 -0
  239. package/dist/utilities/fetchImages.js.map +1 -0
  240. package/dist/utilities/fieldToJsonSchema.d.ts +2 -1
  241. package/dist/utilities/fieldToJsonSchema.js +66 -3
  242. package/dist/utilities/fieldToJsonSchema.js.map +1 -1
  243. package/dist/utilities/getFieldBySchemaPath.d.ts +2 -2
  244. package/dist/utilities/getFieldBySchemaPath.js +15 -0
  245. package/dist/utilities/getFieldBySchemaPath.js.map +1 -1
  246. package/dist/utilities/getProviderOptionsFields.d.ts +16 -0
  247. package/dist/utilities/getProviderOptionsFields.js +80 -0
  248. package/dist/utilities/getProviderOptionsFields.js.map +1 -0
  249. package/dist/utilities/isPluginActivated.js +1 -2
  250. package/dist/utilities/isPluginActivated.js.map +1 -1
  251. package/dist/utilities/lexicalToHTML.js.map +1 -1
  252. package/dist/utilities/resolveImageReferences.d.ts +30 -0
  253. package/dist/utilities/resolveImageReferences.js +167 -0
  254. package/dist/utilities/resolveImageReferences.js.map +1 -0
  255. package/dist/utilities/schemaConverter.d.ts +3 -0
  256. package/dist/utilities/schemaConverter.js +93 -0
  257. package/dist/utilities/schemaConverter.js.map +1 -0
  258. package/dist/utilities/setSafeLexicalState.d.ts +1 -3
  259. package/dist/utilities/setSafeLexicalState.js +1 -1
  260. package/dist/utilities/setSafeLexicalState.js.map +1 -1
  261. package/dist/utilities/updateFieldsConfig.js +27 -43
  262. package/dist/utilities/updateFieldsConfig.js.map +1 -1
  263. package/package.json +23 -24
  264. package/dist/ai/models/anthropic/index.d.ts +0 -2
  265. package/dist/ai/models/anthropic/index.js +0 -129
  266. package/dist/ai/models/anthropic/index.js.map +0 -1
  267. package/dist/ai/models/elevenLabs/generateVoice.d.ts +0 -8
  268. package/dist/ai/models/elevenLabs/generateVoice.js +0 -20
  269. package/dist/ai/models/elevenLabs/generateVoice.js.map +0 -1
  270. package/dist/ai/models/elevenLabs/index.d.ts +0 -2
  271. package/dist/ai/models/elevenLabs/index.js +0 -133
  272. package/dist/ai/models/elevenLabs/index.js.map +0 -1
  273. package/dist/ai/models/elevenLabs/voices.d.ts +0 -8
  274. package/dist/ai/models/elevenLabs/voices.js +0 -24
  275. package/dist/ai/models/elevenLabs/voices.js.map +0 -1
  276. package/dist/ai/models/generateObject.d.ts +0 -11
  277. package/dist/ai/models/generateObject.js +0 -22
  278. package/dist/ai/models/generateObject.js.map +0 -1
  279. package/dist/ai/models/google/generateImage.d.ts +0 -9
  280. package/dist/ai/models/google/generateImage.js +0 -27
  281. package/dist/ai/models/google/generateImage.js.map +0 -1
  282. package/dist/ai/models/google/index.d.ts +0 -2
  283. package/dist/ai/models/google/index.js +0 -201
  284. package/dist/ai/models/google/index.js.map +0 -1
  285. package/dist/ai/models/index.d.ts +0 -2
  286. package/dist/ai/models/index.js +0 -13
  287. package/dist/ai/models/index.js.map +0 -1
  288. package/dist/ai/models/openai/generateImage.d.ts +0 -5
  289. package/dist/ai/models/openai/generateImage.js +0 -31
  290. package/dist/ai/models/openai/generateImage.js.map +0 -1
  291. package/dist/ai/models/openai/generateVoice.d.ts +0 -6
  292. package/dist/ai/models/openai/generateVoice.js +0 -19
  293. package/dist/ai/models/openai/generateVoice.js.map +0 -1
  294. package/dist/ai/models/openai/index.d.ts +0 -2
  295. package/dist/ai/models/openai/index.js +0 -428
  296. package/dist/ai/models/openai/index.js.map +0 -1
  297. package/dist/ai/models/openai/openai.d.ts +0 -1
  298. package/dist/ai/models/openai/openai.js +0 -8
  299. package/dist/ai/models/openai/openai.js.map +0 -1
  300. package/dist/ai/utils/editImagesWithOpenAI.d.ts +0 -10
  301. package/dist/ai/utils/editImagesWithOpenAI.js +0 -37
  302. package/dist/ai/utils/editImagesWithOpenAI.js.map +0 -1
  303. package/dist/styles.d.js +0 -2
  304. package/dist/styles.d.js.map +0 -1
  305. package/dist/types/handlebars-async-helpers.d.js +0 -2
  306. package/dist/types/handlebars-async-helpers.d.js.map +0 -1
  307. package/dist/types/handlebars-dist-handlebars.d.js +0 -2
  308. package/dist/types/handlebars-dist-handlebars.d.js.map +0 -1
  309. package/dist/types/react-mentions.d.js +0 -2
  310. package/dist/types/react-mentions.d.js.map +0 -1
  311. package/dist/utilities/getGenerationModels.d.ts +0 -2
  312. package/dist/utilities/getGenerationModels.js +0 -10
  313. 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 { Field, GlobalConfig, CollectionConfig, ClientGlobalConfig, ClientCollectionConfig } from 'payload';
2
- type AnyCollectionConfig = GlobalConfig | CollectionConfig | ClientGlobalConfig | ClientCollectionConfig;
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 {\n Field,\n GlobalConfig,\n CollectionConfig,\n ClientGlobalConfig,\n ClientCollectionConfig,\n} from 'payload'\n\ntype AnyCollectionConfig =\n | GlobalConfig\n | CollectionConfig\n | ClientGlobalConfig\n | ClientCollectionConfig\n\n/**\n * Resolve a Payload field definition by a full schemaPath like:\n * \"{collectionSlug}.fieldA.subFieldB.blockSlug.innerField\"\n *\n * Notes:\n * - Tabs are a UI construct and are not part of schemaPath (fields inside tabs are at the same level).\n * - Blocks include the block slug as part of the path (we must consume it between the block field and its inner fields).\n * - Rows are skipped by this plugin&#39;s schema path mapping; support added defensively.\n */\nexport const getFieldBySchemaPath = (\n collectionConfig: AnyCollectionConfig,\n schemaPath: string,\n): Field | null => {\n if (!collectionConfig || !schemaPath) {\n return null\n }\n\n const parts = schemaPath.split('.')\n if (!parts.length) {\n return null\n }\n\n // Strip the collection slug prefix if present\n const [collectionSlug, ...rest] = parts\n const pathParts =\n collectionSlug === collectionConfig.slug ? rest.filter(Boolean) : parts.filter(Boolean)\n\n if (!pathParts.length) {\n return null\n }\n\n const findInFields = (fields: Field[], segments: string[]): Field | null => {\n if (!segments.length) {\n return null\n }\n\n const [current, ...remaining] = segments\n\n // First, try to match a field by name\n for (const field of fields) {\n // Tabs do not contribute to path segments; search inside all tabs with the same segments\n if ((field as any).tabs) {\n const tabs = (field as any).tabs as Array<{ fields?: Field[] }>\n for (const tab of tabs) {\n const foundInTab =\n tab.fields && tab.fields.length ? findInFields(tab.fields, segments) : null\n if (foundInTab) {\n return foundInTab\n }\n }\n }\n\n if ((field as any).name === current) {\n // If this is the last segment, we found the target field\n if (remaining.length === 0) {\n return field\n }\n\n // Recurse into composite field types\n if ((field as any).fields && Array.isArray((field as any).fields)) {\n const found = findInFields((field as any).fields, remaining)\n if (found) {\n return found\n }\n }\n\n if ((field as any).blocks && Array.isArray((field as any).blocks)) {\n // Next segment should be a block slug, then continue into block fields\n if (!remaining.length) {\n return field\n } // path stops at block container (unlikely for our mapping)\n const [blockSlug, ...afterBlock] = remaining\n const blocks = (field as any).blocks as Array<{ fields: Field[]; slug: string }>\n const block = blocks.find((b) => b.slug === blockSlug)\n if (block) {\n const found = findInFields(block.fields, afterBlock)\n if (found) {\n return found\n }\n }\n }\n }\n }\n\n // Not found at this level\n return null\n }\n\n const rootFields = (collectionConfig as any).fields as Field[] | undefined\n if (!rootFields || !Array.isArray(rootFields)) {\n return null\n }\n\n return findInFields(rootFields, pathParts)\n}\n"],"names":["getFieldBySchemaPath","collectionConfig","schemaPath","parts","split","length","collectionSlug","rest","pathParts","slug","filter","Boolean","findInFields","fields","segments","current","remaining","field","tabs","tab","foundInTab","name","Array","isArray","found","blocks","blockSlug","afterBlock","block","find","b","rootFields"],"mappings":"AAcA;;;;;;;;CAQC,GACD,OAAO,MAAMA,uBAAuB,CAClCC,kBACAC;IAEA,IAAI,CAACD,oBAAoB,CAACC,YAAY;QACpC,OAAO;IACT;IAEA,MAAMC,QAAQD,WAAWE,KAAK,CAAC;IAC/B,IAAI,CAACD,MAAME,MAAM,EAAE;QACjB,OAAO;IACT;IAEA,8CAA8C;IAC9C,MAAM,CAACC,gBAAgB,GAAGC,KAAK,GAAGJ;IAClC,MAAMK,YACJF,mBAAmBL,iBAAiBQ,IAAI,GAAGF,KAAKG,MAAM,CAACC,WAAWR,MAAMO,MAAM,CAACC;IAEjF,IAAI,CAACH,UAAUH,MAAM,EAAE;QACrB,OAAO;IACT;IAEA,MAAMO,eAAe,CAACC,QAAiBC;QACrC,IAAI,CAACA,SAAST,MAAM,EAAE;YACpB,OAAO;QACT;QAEA,MAAM,CAACU,SAAS,GAAGC,UAAU,GAAGF;QAEhC,sCAAsC;QACtC,KAAK,MAAMG,SAASJ,OAAQ;YAC1B,yFAAyF;YACzF,IAAI,AAACI,MAAcC,IAAI,EAAE;gBACvB,MAAMA,OAAO,AAACD,MAAcC,IAAI;gBAChC,KAAK,MAAMC,OAAOD,KAAM;oBACtB,MAAME,aACJD,IAAIN,MAAM,IAAIM,IAAIN,MAAM,CAACR,MAAM,GAAGO,aAAaO,IAAIN,MAAM,EAAEC,YAAY;oBACzE,IAAIM,YAAY;wBACd,OAAOA;oBACT;gBACF;YACF;YAEA,IAAI,AAACH,MAAcI,IAAI,KAAKN,SAAS;gBACnC,yDAAyD;gBACzD,IAAIC,UAAUX,MAAM,KAAK,GAAG;oBAC1B,OAAOY;gBACT;gBAEA,qCAAqC;gBACrC,IAAI,AAACA,MAAcJ,MAAM,IAAIS,MAAMC,OAAO,CAAC,AAACN,MAAcJ,MAAM,GAAG;oBACjE,MAAMW,QAAQZ,aAAa,AAACK,MAAcJ,MAAM,EAAEG;oBAClD,IAAIQ,OAAO;wBACT,OAAOA;oBACT;gBACF;gBAEA,IAAI,AAACP,MAAcQ,MAAM,IAAIH,MAAMC,OAAO,CAAC,AAACN,MAAcQ,MAAM,GAAG;oBACjE,uEAAuE;oBACvE,IAAI,CAACT,UAAUX,MAAM,EAAE;wBACrB,OAAOY;oBACT,EAAE,2DAA2D;oBAC7D,MAAM,CAACS,WAAW,GAAGC,WAAW,GAAGX;oBACnC,MAAMS,SAAS,AAACR,MAAcQ,MAAM;oBACpC,MAAMG,QAAQH,OAAOI,IAAI,CAAC,CAACC,IAAMA,EAAErB,IAAI,KAAKiB;oBAC5C,IAAIE,OAAO;wBACT,MAAMJ,QAAQZ,aAAagB,MAAMf,MAAM,EAAEc;wBACzC,IAAIH,OAAO;4BACT,OAAOA;wBACT;oBACF;gBACF;YACF;QACF;QAEA,0BAA0B;QAC1B,OAAO;IACT;IAEA,MAAMO,aAAa,AAAC9B,iBAAyBY,MAAM;IACnD,IAAI,CAACkB,cAAc,CAACT,MAAMC,OAAO,CAACQ,aAAa;QAC7C,OAAO;IACT;IAEA,OAAOnB,aAAamB,YAAYvB;AAClC,EAAC"}
1
+ {"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&#39;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,6 +1,5 @@
1
- import { getGenerationModels } from './getGenerationModels.js';
2
1
  export const isPluginActivated = (pluginConfig)=>{
3
- return (getGenerationModels(pluginConfig) ?? []).length > 0;
2
+ return !!pluginConfig;
4
3
  };
5
4
 
6
5
  //# sourceMappingURL=isPluginActivated.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/isPluginActivated.ts"],"sourcesContent":["import type { PluginConfig } from '../types.js'\n\nimport { getGenerationModels } from './getGenerationModels.js'\n\nexport const isPluginActivated = (pluginConfig: PluginConfig) => {\n return (getGenerationModels(pluginConfig) ?? []).length > 0\n}\n"],"names":["getGenerationModels","isPluginActivated","pluginConfig","length"],"mappings":"AAEA,SAASA,mBAAmB,QAAQ,2BAA0B;AAE9D,OAAO,MAAMC,oBAAoB,CAACC;IAChC,OAAO,AAACF,CAAAA,oBAAoBE,iBAAiB,EAAE,AAAD,EAAGC,MAAM,GAAG;AAC5D,EAAC"}
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 type SanitizedServerEditorConfig,\n consolidateHTMLConverters,\n convertLexicalToHTML,\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,SAEEA,yBAAyB,EACzBC,oBAAoB,QACf,+BAA8B;AAErC,OAAO,eAAeC,cACpBC,UAAiC,EACjCC,YAAyC;IAEzC,OAAO,MAAMH,qBAAqB;QAChCI,YAAYL,0BAA0B;YAAEI;QAAa;QACrDE,MAAMH;IACR;AACF"}
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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"}
@@ -0,0 +1,3 @@
1
+ import type { Field } from 'payload';
2
+ import { z } from 'zod';
3
+ export declare function convertPayloadSchemaToZod(fields: Field[]): z.ZodObject<any>;