@ai-stack/payloadcms 3.2.24-beta → 3.68.0

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 (284) 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 +95 -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 +57 -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 +222 -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 +448 -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 +311 -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 +622 -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 +307 -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 +599 -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 +246 -0
  86. package/dist/ai/providers/blocks/xai.js.map +1 -0
  87. package/dist/ai/providers/index.d.ts +2 -0
  88. package/dist/ai/providers/index.js +6 -0
  89. package/dist/ai/providers/index.js.map +1 -0
  90. package/dist/ai/providers/registry.d.ts +40 -0
  91. package/dist/ai/providers/registry.js +256 -0
  92. package/dist/ai/providers/registry.js.map +1 -0
  93. package/dist/ai/providers/types.d.ts +115 -0
  94. package/dist/ai/providers/types.js +4 -0
  95. package/dist/ai/providers/types.js.map +1 -0
  96. package/dist/ai/utils/systemGenerate.d.ts +1 -1
  97. package/dist/ai/utils/systemGenerate.js +19 -19
  98. package/dist/ai/utils/systemGenerate.js.map +1 -1
  99. package/dist/collections/AIJobs.d.ts +2 -0
  100. package/dist/collections/AIJobs.js +81 -0
  101. package/dist/collections/AIJobs.js.map +1 -0
  102. package/dist/collections/AISettings.d.ts +2 -0
  103. package/dist/collections/AISettings.js +279 -0
  104. package/dist/collections/AISettings.js.map +1 -0
  105. package/dist/collections/Instructions.js +185 -37
  106. package/dist/collections/Instructions.js.map +1 -1
  107. package/dist/defaults.d.ts +3 -0
  108. package/dist/defaults.js +3 -0
  109. package/dist/defaults.js.map +1 -1
  110. package/dist/endpoints/buildPromptUtils.d.ts +19 -0
  111. package/dist/endpoints/buildPromptUtils.js +114 -0
  112. package/dist/endpoints/buildPromptUtils.js.map +1 -0
  113. package/dist/endpoints/chat.d.js +3 -0
  114. package/dist/endpoints/chat.d.js.map +1 -0
  115. package/dist/endpoints/fetchVoices.d.ts +2 -0
  116. package/dist/endpoints/fetchVoices.js +79 -0
  117. package/dist/endpoints/fetchVoices.js.map +1 -0
  118. package/dist/endpoints/index.js +253 -214
  119. package/dist/endpoints/index.js.map +1 -1
  120. package/dist/exports/client.d.ts +9 -0
  121. package/dist/exports/client.js +9 -0
  122. package/dist/exports/client.js.map +1 -1
  123. package/dist/fields/ComposeField/ComposeField.js +2 -2
  124. package/dist/fields/ComposeField/ComposeField.js.map +1 -1
  125. package/dist/fields/ComposeField/ComposeField.jsx +2 -2
  126. package/dist/fields/PromptEditorField/PromptEditorField.js +155 -14
  127. package/dist/fields/PromptEditorField/PromptEditorField.js.map +1 -1
  128. package/dist/fields/PromptEditorField/PromptEditorField.jsx +118 -3
  129. package/dist/index.d.ts +1 -0
  130. package/dist/index.js.map +1 -1
  131. package/dist/init.js +35 -13
  132. package/dist/init.js.map +1 -1
  133. package/dist/payload-ai.d.js +3 -0
  134. package/dist/payload-ai.d.js.map +1 -0
  135. package/dist/plugin.js +80 -9
  136. package/dist/plugin.js.map +1 -1
  137. package/dist/providers/InstructionsProvider/InstructionsProvider.js +35 -7
  138. package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
  139. package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +27 -4
  140. package/dist/providers/InstructionsProvider/context.d.ts +1 -0
  141. package/dist/providers/InstructionsProvider/context.js +1 -0
  142. package/dist/providers/InstructionsProvider/context.js.map +1 -1
  143. package/dist/providers/InstructionsProvider/useInstructions.js +13 -6
  144. package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
  145. package/dist/types.d.ts +7 -7
  146. package/dist/types.js.map +1 -1
  147. package/dist/ui/AIConfigDashboard/index.d.ts +2 -0
  148. package/dist/ui/AIConfigDashboard/index.js +46 -0
  149. package/dist/ui/AIConfigDashboard/index.js.map +1 -0
  150. package/dist/ui/AIConfigDashboard/index.jsx +24 -0
  151. package/dist/ui/ApiKeyStatusIndicator/index.d.ts +6 -0
  152. package/dist/ui/ApiKeyStatusIndicator/index.js +39 -0
  153. package/dist/ui/ApiKeyStatusIndicator/index.js.map +1 -0
  154. package/dist/ui/ApiKeyStatusIndicator/index.jsx +29 -0
  155. package/dist/ui/Compose/Compose.d.ts +1 -2
  156. package/dist/ui/Compose/Compose.js +116 -90
  157. package/dist/ui/Compose/Compose.js.map +1 -1
  158. package/dist/ui/Compose/Compose.jsx +111 -101
  159. package/dist/ui/Compose/ComposePlaceholder.d.ts +7 -0
  160. package/dist/ui/Compose/ComposePlaceholder.js +78 -0
  161. package/dist/ui/Compose/ComposePlaceholder.js.map +1 -0
  162. package/dist/ui/Compose/ComposePlaceholder.jsx +66 -0
  163. package/dist/ui/Compose/UndoRedoActions.js +3 -1
  164. package/dist/ui/Compose/UndoRedoActions.js.map +1 -1
  165. package/dist/ui/Compose/UndoRedoActions.jsx +2 -1
  166. package/dist/ui/Compose/compose.module.css +1 -1
  167. package/dist/ui/Compose/hooks/menu/itemsMap.js +1 -1
  168. package/dist/ui/Compose/hooks/menu/itemsMap.js.map +1 -1
  169. package/dist/ui/Compose/hooks/menu/useMenu.d.ts +2 -1
  170. package/dist/ui/Compose/hooks/menu/useMenu.js +2 -2
  171. package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
  172. package/dist/ui/Compose/hooks/menu/useMenu.jsx +2 -2
  173. package/dist/ui/Compose/hooks/useActiveFieldTracking.js +69 -10
  174. package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
  175. package/dist/ui/Compose/hooks/useGenerate.d.ts +3 -0
  176. package/dist/ui/Compose/hooks/useGenerate.js +71 -11
  177. package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
  178. package/dist/ui/Compose/hooks/useHistory.js +52 -5
  179. package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
  180. package/dist/ui/DynamicModelSelect/index.d.ts +7 -0
  181. package/dist/ui/DynamicModelSelect/index.js +231 -0
  182. package/dist/ui/DynamicModelSelect/index.js.map +1 -0
  183. package/dist/ui/DynamicModelSelect/index.jsx +207 -0
  184. package/dist/ui/DynamicProviderSelect/index.d.ts +7 -0
  185. package/dist/ui/DynamicProviderSelect/index.js +101 -0
  186. package/dist/ui/DynamicProviderSelect/index.js.map +1 -0
  187. package/dist/ui/DynamicProviderSelect/index.jsx +90 -0
  188. package/dist/ui/DynamicVoiceSelect/index.d.ts +7 -0
  189. package/dist/ui/DynamicVoiceSelect/index.js +104 -0
  190. package/dist/ui/DynamicVoiceSelect/index.js.map +1 -0
  191. package/dist/ui/DynamicVoiceSelect/index.jsx +69 -0
  192. package/dist/ui/EncryptedTextField/index.d.ts +8 -0
  193. package/dist/ui/EncryptedTextField/index.js +74 -0
  194. package/dist/ui/EncryptedTextField/index.js.map +1 -0
  195. package/dist/ui/EncryptedTextField/index.jsx +35 -0
  196. package/dist/ui/Icons/LottieAnimation.js +3 -1
  197. package/dist/ui/Icons/LottieAnimation.js.map +1 -1
  198. package/dist/ui/Icons/LottieAnimation.jsx +2 -1
  199. package/dist/ui/ModelRowLabel/index.d.ts +6 -0
  200. package/dist/ui/ModelRowLabel/index.js +41 -0
  201. package/dist/ui/ModelRowLabel/index.js.map +1 -0
  202. package/dist/ui/ModelRowLabel/index.jsx +26 -0
  203. package/dist/ui/ProviderOptionsEditor/index.d.ts +7 -0
  204. package/dist/ui/ProviderOptionsEditor/index.js +291 -0
  205. package/dist/ui/ProviderOptionsEditor/index.js.map +1 -0
  206. package/dist/ui/ProviderOptionsEditor/index.jsx +210 -0
  207. package/dist/ui/VoicesFetcher/index.d.ts +7 -0
  208. package/dist/ui/VoicesFetcher/index.js +72 -0
  209. package/dist/ui/VoicesFetcher/index.js.map +1 -0
  210. package/dist/ui/VoicesFetcher/index.jsx +56 -0
  211. package/dist/utilities/encryption.d.ts +2 -0
  212. package/dist/utilities/encryption.js +47 -0
  213. package/dist/utilities/encryption.js.map +1 -0
  214. package/dist/utilities/extractImageData.d.ts +9 -0
  215. package/dist/utilities/extractImageData.js +12 -2
  216. package/dist/utilities/extractImageData.js.map +1 -1
  217. package/dist/utilities/fetchImages.d.ts +14 -0
  218. package/dist/utilities/fetchImages.js +38 -0
  219. package/dist/utilities/fetchImages.js.map +1 -0
  220. package/dist/utilities/fieldToJsonSchema.d.ts +2 -1
  221. package/dist/utilities/fieldToJsonSchema.js +66 -3
  222. package/dist/utilities/fieldToJsonSchema.js.map +1 -1
  223. package/dist/utilities/getFieldBySchemaPath.js +15 -0
  224. package/dist/utilities/getFieldBySchemaPath.js.map +1 -1
  225. package/dist/utilities/getProviderOptionsFields.d.ts +16 -0
  226. package/dist/utilities/getProviderOptionsFields.js +80 -0
  227. package/dist/utilities/getProviderOptionsFields.js.map +1 -0
  228. package/dist/utilities/isPluginActivated.js +1 -2
  229. package/dist/utilities/isPluginActivated.js.map +1 -1
  230. package/dist/utilities/lexicalToHTML.js.map +1 -1
  231. package/dist/utilities/resolveImageReferences.d.ts +28 -0
  232. package/dist/utilities/resolveImageReferences.js +148 -0
  233. package/dist/utilities/resolveImageReferences.js.map +1 -0
  234. package/dist/utilities/schemaConverter.d.ts +3 -0
  235. package/dist/utilities/schemaConverter.js +93 -0
  236. package/dist/utilities/schemaConverter.js.map +1 -0
  237. package/dist/utilities/setSafeLexicalState.d.ts +1 -3
  238. package/dist/utilities/setSafeLexicalState.js +1 -1
  239. package/dist/utilities/setSafeLexicalState.js.map +1 -1
  240. package/package.json +19 -21
  241. package/dist/ai/models/anthropic/index.d.ts +0 -2
  242. package/dist/ai/models/anthropic/index.js +0 -129
  243. package/dist/ai/models/anthropic/index.js.map +0 -1
  244. package/dist/ai/models/elevenLabs/generateVoice.d.ts +0 -8
  245. package/dist/ai/models/elevenLabs/generateVoice.js +0 -20
  246. package/dist/ai/models/elevenLabs/generateVoice.js.map +0 -1
  247. package/dist/ai/models/elevenLabs/index.d.ts +0 -2
  248. package/dist/ai/models/elevenLabs/index.js +0 -133
  249. package/dist/ai/models/elevenLabs/index.js.map +0 -1
  250. package/dist/ai/models/elevenLabs/voices.d.ts +0 -8
  251. package/dist/ai/models/elevenLabs/voices.js +0 -24
  252. package/dist/ai/models/elevenLabs/voices.js.map +0 -1
  253. package/dist/ai/models/generateObject.d.ts +0 -11
  254. package/dist/ai/models/generateObject.js +0 -22
  255. package/dist/ai/models/generateObject.js.map +0 -1
  256. package/dist/ai/models/google/generateImage.d.ts +0 -9
  257. package/dist/ai/models/google/generateImage.js +0 -27
  258. package/dist/ai/models/google/generateImage.js.map +0 -1
  259. package/dist/ai/models/google/index.d.ts +0 -2
  260. package/dist/ai/models/google/index.js +0 -201
  261. package/dist/ai/models/google/index.js.map +0 -1
  262. package/dist/ai/models/index.d.ts +0 -2
  263. package/dist/ai/models/index.js +0 -13
  264. package/dist/ai/models/index.js.map +0 -1
  265. package/dist/ai/models/openai/generateImage.d.ts +0 -5
  266. package/dist/ai/models/openai/generateImage.js +0 -31
  267. package/dist/ai/models/openai/generateImage.js.map +0 -1
  268. package/dist/ai/models/openai/generateVoice.d.ts +0 -6
  269. package/dist/ai/models/openai/generateVoice.js +0 -19
  270. package/dist/ai/models/openai/generateVoice.js.map +0 -1
  271. package/dist/ai/models/openai/index.d.ts +0 -2
  272. package/dist/ai/models/openai/index.js +0 -428
  273. package/dist/ai/models/openai/index.js.map +0 -1
  274. package/dist/ai/models/openai/openai.d.ts +0 -1
  275. package/dist/ai/models/openai/openai.js +0 -8
  276. package/dist/ai/models/openai/openai.js.map +0 -1
  277. package/dist/ai/utils/editImagesWithOpenAI.d.ts +0 -10
  278. package/dist/ai/utils/editImagesWithOpenAI.js +0 -37
  279. package/dist/ai/utils/editImagesWithOpenAI.js.map +0 -1
  280. package/dist/types.d.js +0 -3
  281. package/dist/types.d.js.map +0 -1
  282. package/dist/utilities/getGenerationModels.d.ts +0 -2
  283. package/dist/utilities/getGenerationModels.js +0 -10
  284. package/dist/utilities/getGenerationModels.js.map +0 -1
@@ -0,0 +1,210 @@
1
+ 'use client';
2
+ import { RenderFields, useField, useFormFields } from '@payloadcms/ui';
3
+ import React, { useEffect, useMemo, useState } from 'react';
4
+ import { allProviderBlocks } from '../../ai/providers/blocks/index.js';
5
+ /**
6
+ * Find a field by name within a block's fields, searching through tabs
7
+ */
8
+ function findFieldInBlock(block, fieldName) {
9
+ const searchFields = (fields) => {
10
+ for (const field of fields) {
11
+ if ('name' in field && field.name === fieldName) {
12
+ return field;
13
+ }
14
+ if (field.type === 'tabs' && 'tabs' in field) {
15
+ for (const tab of field.tabs) {
16
+ const found = searchFields(tab.fields);
17
+ if (found) {
18
+ return found;
19
+ }
20
+ }
21
+ }
22
+ if (field.type === 'group' && 'fields' in field) {
23
+ const found = searchFields(field.fields);
24
+ if (found) {
25
+ return found;
26
+ }
27
+ }
28
+ }
29
+ return undefined;
30
+ };
31
+ return searchFields(block.fields);
32
+ }
33
+ /**
34
+ * Get provider options fields for a given provider and use case
35
+ */
36
+ function getProviderOptionsFields(providerSlug, useCase) {
37
+ const block = allProviderBlocks.find((b) => b.slug === providerSlug);
38
+ if (!block) {
39
+ return [];
40
+ }
41
+ const groupName = `${useCase}ProviderOptions`;
42
+ const optionsGroup = findFieldInBlock(block, groupName);
43
+ if (optionsGroup && optionsGroup.type === 'group' && 'fields' in optionsGroup) {
44
+ return optionsGroup.fields;
45
+ }
46
+ return [];
47
+ }
48
+ export const ProviderOptionsEditor = (props) => {
49
+ const { path } = props;
50
+ // Get parent path to find sibling provider field
51
+ const parentPath = path.split('.').slice(0, -1).join('.');
52
+ const providerField = useFormFields(([fields]) => fields[`${parentPath}.provider`]);
53
+ const provider = providerField?.value;
54
+ // Infer use case from path
55
+ // Handles:
56
+ // - AISettings: 'defaults.text.options' -> useCase is 'text'
57
+ // - Instructions: 'text-settings.providerOptions' -> useCase is 'text'
58
+ const useCase = useMemo(() => {
59
+ // Check for AISettings paths first (e.g., 'defaults.text.options')
60
+ const pathParts = path.split('.');
61
+ const parentName = pathParts[pathParts.length - 2];
62
+ if (['image', 'text', 'tts', 'video'].includes(parentName)) {
63
+ return parentName;
64
+ }
65
+ // Check for Instructions paths
66
+ if (path.includes('tts-settings')) {
67
+ return 'tts';
68
+ }
69
+ if (path.includes('image-settings')) {
70
+ return 'image';
71
+ }
72
+ if (path.includes('video-settings')) {
73
+ return 'video';
74
+ }
75
+ return 'text';
76
+ }, [path]);
77
+ const { setValue, value } = useField({ path });
78
+ const [aiSettings, setAiSettings] = useState(null);
79
+ // Fetch AI Settings to get current provider defaults
80
+ useEffect(() => {
81
+ fetch('/api/globals/ai-settings?depth=1')
82
+ .then((res) => res.json())
83
+ .then((data) => setAiSettings(data))
84
+ .catch((err) => console.error('Error fetching AI settings:', err));
85
+ }, []);
86
+ // Get the configured default options from AI Settings for this provider
87
+ const configuredDefaults = useMemo(() => {
88
+ if (!provider || !aiSettings) {
89
+ return null;
90
+ }
91
+ const providerBlock = aiSettings.providers?.find((p) => p.blockType === provider && p.enabled);
92
+ if (!providerBlock) {
93
+ return null;
94
+ }
95
+ // Get provider options by use case
96
+ const optionsKey = `${useCase}ProviderOptions`;
97
+ return providerBlock[optionsKey] || null;
98
+ }, [provider, useCase, aiSettings]);
99
+ // Get field definitions from provider block
100
+ const fields = useMemo(() => {
101
+ if (!provider) {
102
+ return [];
103
+ }
104
+ return getProviderOptionsFields(provider, useCase);
105
+ }, [provider, useCase]);
106
+ // Check if there are any overrides set
107
+ const hasOverrides = useMemo(() => {
108
+ return value && Object.keys(value).length > 0;
109
+ }, [value]);
110
+ if (!provider) {
111
+ return (<div className="field-type" style={{ padding: '12px 0' }}>
112
+ <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', margin: 0 }}>
113
+ Please select a provider first to configure options.
114
+ </p>
115
+ </div>);
116
+ }
117
+ if (fields.length === 0) {
118
+ return (<div className="field-type" style={{ padding: '12px 0' }}>
119
+ <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', margin: 0 }}>
120
+ No configurable options available for {provider} ({useCase}).
121
+ </p>
122
+ </div>);
123
+ }
124
+ return (<div className="field-type provider-options-editor">
125
+ <div style={{ marginBottom: '16px' }}>
126
+ <label className="field-label" style={{ display: 'block', marginBottom: '8px' }}>
127
+ Provider Options
128
+ </label>
129
+
130
+ {configuredDefaults && (<div style={{
131
+ background: 'var(--theme-elevation-50)',
132
+ border: '1px solid var(--theme-elevation-100)',
133
+ borderRadius: '4px',
134
+ fontSize: '12px',
135
+ marginBottom: '12px',
136
+ padding: '12px',
137
+ }}>
138
+ <div style={{
139
+ alignItems: 'center',
140
+ display: 'flex',
141
+ justifyContent: 'space-between',
142
+ marginBottom: '8px',
143
+ }}>
144
+ <strong style={{ color: 'var(--theme-elevation-800)' }}>
145
+ Defaults from AI Settings
146
+ </strong>
147
+ <span style={{
148
+ background: 'var(--theme-elevation-100)',
149
+ borderRadius: '10px',
150
+ color: 'var(--theme-elevation-500)',
151
+ fontSize: '11px',
152
+ padding: '2px 8px',
153
+ }}>
154
+ Inherited
155
+ </span>
156
+ </div>
157
+ <div style={{
158
+ color: 'var(--theme-elevation-600)',
159
+ display: 'flex',
160
+ flexWrap: 'wrap',
161
+ gap: '8px',
162
+ }}>
163
+ {Object.entries(configuredDefaults).map(([key, val]) => {
164
+ // Skip nested objects for display
165
+ if (typeof val === 'object' && val !== null) {
166
+ return null;
167
+ }
168
+ return (<span key={key} style={{
169
+ background: 'var(--theme-elevation-100)',
170
+ borderRadius: '3px',
171
+ fontSize: '11px',
172
+ padding: '2px 6px',
173
+ }}>
174
+ {key}: <strong>{String(val)}</strong>
175
+ </span>);
176
+ })}
177
+ </div>
178
+ </div>)}
179
+
180
+ <p style={{
181
+ color: 'var(--theme-elevation-500)',
182
+ fontSize: '12px',
183
+ fontStyle: 'italic',
184
+ marginBottom: '12px',
185
+ }}>
186
+ Override defaults for this specific field. Empty values inherit from AI Settings.
187
+ </p>
188
+ </div>
189
+
190
+ <RenderFields fields={fields} forceRender margins="small" parentIndexPath="" parentPath={path} parentSchemaPath={path} permissions={true}/>
191
+
192
+ {hasOverrides && (<button onClick={() => setValue({})} onMouseEnter={(e) => {
193
+ e.currentTarget.style.background = 'var(--theme-elevation-100)';
194
+ }} onMouseLeave={(e) => {
195
+ e.currentTarget.style.background = 'transparent';
196
+ }} style={{
197
+ background: 'transparent',
198
+ border: '1px solid var(--theme-elevation-200)',
199
+ borderRadius: '4px',
200
+ color: 'var(--theme-text)',
201
+ cursor: 'pointer',
202
+ fontSize: '13px',
203
+ marginTop: '12px',
204
+ padding: '8px 16px',
205
+ transition: 'all 0.15s ease',
206
+ }} type="button">
207
+ Reset to Defaults
208
+ </button>)}
209
+ </div>);
210
+ };
@@ -0,0 +1,7 @@
1
+ import type { FieldClientComponent } from 'payload';
2
+ /**
3
+ * VoicesFetcher Component
4
+ * Fetches voices from ElevenLabs API (server-side) and populates the voices array field
5
+ * SECURE: API key is never exposed to the client
6
+ */
7
+ export declare const VoicesFetcher: FieldClientComponent;
@@ -0,0 +1,72 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button, useForm } from '@payloadcms/ui';
4
+ import React, { useCallback, useState } from 'react';
5
+ import { PLUGIN_API_ENDPOINT_FETCH_VOICES } from '../../defaults.js';
6
+ /**
7
+ * VoicesFetcher Component
8
+ * Fetches voices from ElevenLabs API (server-side) and populates the voices array field
9
+ * SECURE: API key is never exposed to the client
10
+ */ export const VoicesFetcher = ({ path })=>{
11
+ const [loading, setLoading] = useState(false);
12
+ const { dispatchFields } = useForm();
13
+ // Get the parent path (the block path)
14
+ const fieldPath = path || '';
15
+ const blockPath = fieldPath.split('.').slice(0, -1).join('.');
16
+ const voicesPath = `${blockPath}.voices`;
17
+ const fetchVoices = useCallback(async ()=>{
18
+ setLoading(true);
19
+ try {
20
+ // Call server endpoint - it will read the API key from the database
21
+ const response = await fetch(`/api${PLUGIN_API_ENDPOINT_FETCH_VOICES}`, {
22
+ headers: {
23
+ 'Content-Type': 'application/json'
24
+ },
25
+ method: 'POST'
26
+ });
27
+ if (!response.ok) {
28
+ const error = await response.json();
29
+ throw new Error(error.message || 'Failed to fetch voices');
30
+ }
31
+ const data = await response.json();
32
+ // Update the voices field with fetched voices
33
+ dispatchFields({
34
+ type: 'UPDATE',
35
+ path: voicesPath,
36
+ value: data.voices || []
37
+ });
38
+ alert(`Successfully fetched ${data.voices?.length || 0} voices!`);
39
+ } catch (error) {
40
+ alert(`Error: ${error instanceof Error ? error.message : 'Failed to fetch voices'}`);
41
+ } finally{
42
+ setLoading(false);
43
+ }
44
+ }, [
45
+ dispatchFields,
46
+ voicesPath
47
+ ]);
48
+ return /*#__PURE__*/ _jsxs("div", {
49
+ style: {
50
+ marginBottom: '20px'
51
+ },
52
+ children: [
53
+ /*#__PURE__*/ _jsx(Button, {
54
+ buttonStyle: "secondary",
55
+ disabled: loading,
56
+ onClick: fetchVoices,
57
+ size: "medium",
58
+ children: loading ? 'Fetching Voices...' : 'Fetch Voices from ElevenLabs'
59
+ }),
60
+ /*#__PURE__*/ _jsx("p", {
61
+ style: {
62
+ color: 'var(--theme-elevation-600)',
63
+ fontSize: '13px',
64
+ marginTop: '8px'
65
+ },
66
+ children: "This will fetch all available voices from your ElevenLabs account. Make sure you have saved your API key in the Setup tab first."
67
+ })
68
+ ]
69
+ });
70
+ };
71
+
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/ui/VoicesFetcher/index.tsx"],"sourcesContent":["'use client'\n\nimport type { FieldClientComponent } from 'payload'\n\nimport { Button, useForm } from '@payloadcms/ui'\nimport React, { useCallback, useState } from 'react'\n\nimport { PLUGIN_API_ENDPOINT_FETCH_VOICES } from '../../defaults.js'\n\n/**\n * VoicesFetcher Component\n * Fetches voices from ElevenLabs API (server-side) and populates the voices array field\n * SECURE: API key is never exposed to the client\n */\nexport const VoicesFetcher: FieldClientComponent = ({ path }) => {\n const [loading, setLoading] = useState(false)\n const { dispatchFields } = useForm()\n\n // Get the parent path (the block path)\n const fieldPath = (path as string) || ''\n const blockPath = fieldPath.split('.').slice(0, -1).join('.')\n const voicesPath = `${blockPath}.voices`\n\n const fetchVoices = useCallback(async () => {\n setLoading(true)\n\n try {\n // Call server endpoint - it will read the API key from the database\n const response = await fetch(`/api${PLUGIN_API_ENDPOINT_FETCH_VOICES}`, {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n const error = await response.json()\n throw new Error(error.message || 'Failed to fetch voices')\n }\n\n const data = await response.json()\n\n // Update the voices field with fetched voices\n dispatchFields({\n type: 'UPDATE',\n path: voicesPath,\n value: data.voices || [],\n })\n\n alert(`Successfully fetched ${data.voices?.length || 0} voices!`)\n } catch (error) {\n alert(`Error: ${error instanceof Error ? error.message : 'Failed to fetch voices'}`)\n } finally {\n setLoading(false)\n }\n }, [dispatchFields, voicesPath])\n\n return (\n <div style={{ marginBottom: '20px' }}>\n <Button buttonStyle=\"secondary\" disabled={loading} onClick={fetchVoices} size=\"medium\">\n {loading ? 'Fetching Voices...' : 'Fetch Voices from ElevenLabs'}\n </Button>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', marginTop: '8px' }}>\n This will fetch all available voices from your ElevenLabs account. Make sure you have saved\n your API key in the Setup tab first.\n </p>\n </div>\n )\n}\n"],"names":["Button","useForm","React","useCallback","useState","PLUGIN_API_ENDPOINT_FETCH_VOICES","VoicesFetcher","path","loading","setLoading","dispatchFields","fieldPath","blockPath","split","slice","join","voicesPath","fetchVoices","response","fetch","headers","method","ok","error","json","Error","message","data","type","value","voices","alert","length","div","style","marginBottom","buttonStyle","disabled","onClick","size","p","color","fontSize","marginTop"],"mappings":"AAAA;;AAIA,SAASA,MAAM,EAAEC,OAAO,QAAQ,iBAAgB;AAChD,OAAOC,SAASC,WAAW,EAAEC,QAAQ,QAAQ,QAAO;AAEpD,SAASC,gCAAgC,QAAQ,oBAAmB;AAEpE;;;;CAIC,GACD,OAAO,MAAMC,gBAAsC,CAAC,EAAEC,IAAI,EAAE;IAC1D,MAAM,CAACC,SAASC,WAAW,GAAGL,SAAS;IACvC,MAAM,EAAEM,cAAc,EAAE,GAAGT;IAE3B,uCAAuC;IACvC,MAAMU,YAAY,AAACJ,QAAmB;IACtC,MAAMK,YAAYD,UAAUE,KAAK,CAAC,KAAKC,KAAK,CAAC,GAAG,CAAC,GAAGC,IAAI,CAAC;IACzD,MAAMC,aAAa,CAAC,EAAEJ,UAAU,OAAO,CAAC;IAExC,MAAMK,cAAcd,YAAY;QAC9BM,WAAW;QAEX,IAAI;YACF,oEAAoE;YACpE,MAAMS,WAAW,MAAMC,MAAM,CAAC,IAAI,EAAEd,iCAAiC,CAAC,EAAE;gBACtEe,SAAS;oBACP,gBAAgB;gBAClB;gBACAC,QAAQ;YACV;YAEA,IAAI,CAACH,SAASI,EAAE,EAAE;gBAChB,MAAMC,QAAQ,MAAML,SAASM,IAAI;gBACjC,MAAM,IAAIC,MAAMF,MAAMG,OAAO,IAAI;YACnC;YAEA,MAAMC,OAAO,MAAMT,SAASM,IAAI;YAEhC,8CAA8C;YAC9Cd,eAAe;gBACbkB,MAAM;gBACNrB,MAAMS;gBACNa,OAAOF,KAAKG,MAAM,IAAI,EAAE;YAC1B;YAEAC,MAAM,CAAC,qBAAqB,EAAEJ,KAAKG,MAAM,EAAEE,UAAU,EAAE,QAAQ,CAAC;QAClE,EAAE,OAAOT,OAAO;YACdQ,MAAM,CAAC,OAAO,EAAER,iBAAiBE,QAAQF,MAAMG,OAAO,GAAG,yBAAyB,CAAC;QACrF,SAAU;YACRjB,WAAW;QACb;IACF,GAAG;QAACC;QAAgBM;KAAW;IAE/B,qBACE,MAACiB;QAAIC,OAAO;YAAEC,cAAc;QAAO;;0BACjC,KAACnC;gBAAOoC,aAAY;gBAAYC,UAAU7B;gBAAS8B,SAASrB;gBAAasB,MAAK;0BAC3E/B,UAAU,uBAAuB;;0BAEpC,KAACgC;gBAAEN,OAAO;oBAAEO,OAAO;oBAA8BC,UAAU;oBAAQC,WAAW;gBAAM;0BAAG;;;;AAM7F,EAAC"}
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+ import { Button, useForm } from '@payloadcms/ui';
3
+ import React, { useCallback, useState } from 'react';
4
+ import { PLUGIN_API_ENDPOINT_FETCH_VOICES } from '../../defaults.js';
5
+ /**
6
+ * VoicesFetcher Component
7
+ * Fetches voices from ElevenLabs API (server-side) and populates the voices array field
8
+ * SECURE: API key is never exposed to the client
9
+ */
10
+ export const VoicesFetcher = ({ path }) => {
11
+ const [loading, setLoading] = useState(false);
12
+ const { dispatchFields } = useForm();
13
+ // Get the parent path (the block path)
14
+ const fieldPath = path || '';
15
+ const blockPath = fieldPath.split('.').slice(0, -1).join('.');
16
+ const voicesPath = `${blockPath}.voices`;
17
+ const fetchVoices = useCallback(async () => {
18
+ setLoading(true);
19
+ try {
20
+ // Call server endpoint - it will read the API key from the database
21
+ const response = await fetch(`/api${PLUGIN_API_ENDPOINT_FETCH_VOICES}`, {
22
+ headers: {
23
+ 'Content-Type': 'application/json',
24
+ },
25
+ method: 'POST',
26
+ });
27
+ if (!response.ok) {
28
+ const error = await response.json();
29
+ throw new Error(error.message || 'Failed to fetch voices');
30
+ }
31
+ const data = await response.json();
32
+ // Update the voices field with fetched voices
33
+ dispatchFields({
34
+ type: 'UPDATE',
35
+ path: voicesPath,
36
+ value: data.voices || [],
37
+ });
38
+ alert(`Successfully fetched ${data.voices?.length || 0} voices!`);
39
+ }
40
+ catch (error) {
41
+ alert(`Error: ${error instanceof Error ? error.message : 'Failed to fetch voices'}`);
42
+ }
43
+ finally {
44
+ setLoading(false);
45
+ }
46
+ }, [dispatchFields, voicesPath]);
47
+ return (<div style={{ marginBottom: '20px' }}>
48
+ <Button buttonStyle="secondary" disabled={loading} onClick={fetchVoices} size="medium">
49
+ {loading ? 'Fetching Voices...' : 'Fetch Voices from ElevenLabs'}
50
+ </Button>
51
+ <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', marginTop: '8px' }}>
52
+ This will fetch all available voices from your ElevenLabs account. Make sure you have saved
53
+ your API key in the Setup tab first.
54
+ </p>
55
+ </div>);
56
+ };
@@ -0,0 +1,2 @@
1
+ export declare function encrypt(text: string, secret: string): string;
2
+ export declare function decrypt(text: string, secret: string): string;
@@ -0,0 +1,47 @@
1
+ import crypto from 'crypto';
2
+ const algorithm = 'aes-256-cbc';
3
+ const ivLength = 16;
4
+ export function encrypt(text, secret) {
5
+ if (!text) {
6
+ return text;
7
+ }
8
+ if (!secret) {
9
+ throw new Error('No secret provided for encryption');
10
+ }
11
+ // Ensure secret is 32 bytes
12
+ const key = crypto.createHash('sha256').update(secret).digest();
13
+ const iv = crypto.randomBytes(ivLength);
14
+ const cipher = crypto.createCipheriv(algorithm, key, iv);
15
+ let encrypted = cipher.update(text);
16
+ encrypted = Buffer.concat([
17
+ encrypted,
18
+ cipher.final()
19
+ ]);
20
+ return iv.toString('hex') + ':' + encrypted.toString('hex');
21
+ }
22
+ export function decrypt(text, secret) {
23
+ if (!text) {
24
+ return text;
25
+ }
26
+ if (!secret) {
27
+ throw new Error('No secret provided for decryption');
28
+ }
29
+ try {
30
+ const textParts = text.split(':');
31
+ const iv = Buffer.from(textParts.shift(), 'hex');
32
+ const encryptedText = Buffer.from(textParts.join(':'), 'hex');
33
+ const key = crypto.createHash('sha256').update(secret).digest();
34
+ const decipher = crypto.createDecipheriv(algorithm, key, iv);
35
+ let decrypted = decipher.update(encryptedText);
36
+ decrypted = Buffer.concat([
37
+ decrypted,
38
+ decipher.final()
39
+ ]);
40
+ return decrypted.toString();
41
+ } catch (e) {
42
+ // If decryption fails, return original text (might be already plain or invalid)
43
+ return text;
44
+ }
45
+ }
46
+
47
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/encryption.ts"],"sourcesContent":["import crypto from 'crypto'\n\nconst algorithm = 'aes-256-cbc'\nconst ivLength = 16\n\nexport function encrypt(text: string, secret: string): string {\n if (!text) {return text}\n if (!secret) {throw new Error('No secret provided for encryption')}\n\n // Ensure secret is 32 bytes\n const key = crypto.createHash('sha256').update(secret).digest()\n const iv = crypto.randomBytes(ivLength)\n const cipher = crypto.createCipheriv(algorithm, key, iv)\n let encrypted = cipher.update(text)\n encrypted = Buffer.concat([encrypted, cipher.final()])\n return iv.toString('hex') + ':' + encrypted.toString('hex')\n}\n\nexport function decrypt(text: string, secret: string): string {\n if (!text) {return text}\n if (!secret) {throw new Error('No secret provided for decryption')}\n\n try {\n const textParts = text.split(':')\n const iv = Buffer.from(textParts.shift()!, 'hex')\n const encryptedText = Buffer.from(textParts.join(':'), 'hex')\n const key = crypto.createHash('sha256').update(secret).digest()\n const decipher = crypto.createDecipheriv(algorithm, key, iv)\n let decrypted = decipher.update(encryptedText)\n decrypted = Buffer.concat([decrypted, decipher.final()])\n return decrypted.toString()\n } catch (e) {\n // If decryption fails, return original text (might be already plain or invalid)\n return text\n }\n}\n"],"names":["crypto","algorithm","ivLength","encrypt","text","secret","Error","key","createHash","update","digest","iv","randomBytes","cipher","createCipheriv","encrypted","Buffer","concat","final","toString","decrypt","textParts","split","from","shift","encryptedText","join","decipher","createDecipheriv","decrypted","e"],"mappings":"AAAA,OAAOA,YAAY,SAAQ;AAE3B,MAAMC,YAAY;AAClB,MAAMC,WAAW;AAEjB,OAAO,SAASC,QAAQC,IAAY,EAAEC,MAAc;IAClD,IAAI,CAACD,MAAM;QAAC,OAAOA;IAAI;IACvB,IAAI,CAACC,QAAQ;QAAC,MAAM,IAAIC,MAAM;IAAoC;IAElE,4BAA4B;IAC5B,MAAMC,MAAMP,OAAOQ,UAAU,CAAC,UAAUC,MAAM,CAACJ,QAAQK,MAAM;IAC7D,MAAMC,KAAKX,OAAOY,WAAW,CAACV;IAC9B,MAAMW,SAASb,OAAOc,cAAc,CAACb,WAAWM,KAAKI;IACrD,IAAII,YAAYF,OAAOJ,MAAM,CAACL;IAC9BW,YAAYC,OAAOC,MAAM,CAAC;QAACF;QAAWF,OAAOK,KAAK;KAAG;IACrD,OAAOP,GAAGQ,QAAQ,CAAC,SAAS,MAAMJ,UAAUI,QAAQ,CAAC;AACvD;AAEA,OAAO,SAASC,QAAQhB,IAAY,EAAEC,MAAc;IAClD,IAAI,CAACD,MAAM;QAAC,OAAOA;IAAI;IACvB,IAAI,CAACC,QAAQ;QAAC,MAAM,IAAIC,MAAM;IAAoC;IAElE,IAAI;QACF,MAAMe,YAAYjB,KAAKkB,KAAK,CAAC;QAC7B,MAAMX,KAAKK,OAAOO,IAAI,CAACF,UAAUG,KAAK,IAAK;QAC3C,MAAMC,gBAAgBT,OAAOO,IAAI,CAACF,UAAUK,IAAI,CAAC,MAAM;QACvD,MAAMnB,MAAMP,OAAOQ,UAAU,CAAC,UAAUC,MAAM,CAACJ,QAAQK,MAAM;QAC7D,MAAMiB,WAAW3B,OAAO4B,gBAAgB,CAAC3B,WAAWM,KAAKI;QACzD,IAAIkB,YAAYF,SAASlB,MAAM,CAACgB;QAChCI,YAAYb,OAAOC,MAAM,CAAC;YAACY;YAAWF,SAAST,KAAK;SAAG;QACvD,OAAOW,UAAUV,QAAQ;IAC3B,EAAE,OAAOW,GAAG;QACV,gFAAgF;QAChF,OAAO1B;IACT;AACF"}
@@ -5,5 +5,14 @@ type ImageData = {
5
5
  url: string;
6
6
  };
7
7
  }[];
8
+ /**
9
+ * Extracts hardcoded image URLs from text using regex.
10
+ *
11
+ * NOTE: This only handles direct URLs in the text.
12
+ * For @field references, use resolveImageReferences utility instead.
13
+ *
14
+ * @param input - Text containing image URLs
15
+ * @returns Array of extracted image data
16
+ */
8
17
  export declare function extractImageData(input: string): ImageData;
9
18
  export {};
@@ -1,7 +1,17 @@
1
- export function extractImageData(input) {
1
+ /**
2
+ * Extracts hardcoded image URLs from text using regex.
3
+ *
4
+ * NOTE: This only handles direct URLs in the text.
5
+ * For @field references, use resolveImageReferences utility instead.
6
+ *
7
+ * @param input - Text containing image URLs
8
+ * @returns Array of extracted image data
9
+ */ export function extractImageData(input) {
2
10
  const regex = /(?:https?:)?\/[\w%\-.,/]+\.(png|jpe?g|webp)/gi;
3
11
  const matches = input.match(regex);
4
- if (!matches) return [];
12
+ if (!matches) {
13
+ return [];
14
+ }
5
15
  return matches.map((url)=>{
6
16
  const decodedUrl = decodeURIComponent(url);
7
17
  const parts = decodedUrl.split('/');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/extractImageData.ts"],"sourcesContent":["type ImageData = {\n image: { name: string; type: string; url: string }\n}[]\n\nexport function extractImageData(input: string): ImageData {\n const regex = /(?:https?:)?\\/[\\w%\\-.,/]+\\.(png|jpe?g|webp)/gi\n const matches = input.match(regex)\n\n if (!matches) return []\n\n return matches.map((url) => {\n const decodedUrl = decodeURIComponent(url)\n const parts = decodedUrl.split('/')\n const filename = parts[parts.length - 1]\n const name = filename.replace(/\\.(png|jpe?g|webp)$/i, '')\n const typeMatch = filename.match(/\\.(png|jpe?g|webp)$/i)\n const type = typeMatch ? typeMatch[1].toLowerCase() : 'unknown'\n\n return {\n image: {\n name,\n type,\n url,\n },\n }\n })\n}\n"],"names":["extractImageData","input","regex","matches","match","map","url","decodedUrl","decodeURIComponent","parts","split","filename","length","name","replace","typeMatch","type","toLowerCase","image"],"mappings":"AAIA,OAAO,SAASA,iBAAiBC,KAAa;IAC5C,MAAMC,QAAQ;IACd,MAAMC,UAAUF,MAAMG,KAAK,CAACF;IAE5B,IAAI,CAACC,SAAS,OAAO,EAAE;IAEvB,OAAOA,QAAQE,GAAG,CAAC,CAACC;QAClB,MAAMC,aAAaC,mBAAmBF;QACtC,MAAMG,QAAQF,WAAWG,KAAK,CAAC;QAC/B,MAAMC,WAAWF,KAAK,CAACA,MAAMG,MAAM,GAAG,EAAE;QACxC,MAAMC,OAAOF,SAASG,OAAO,CAAC,wBAAwB;QACtD,MAAMC,YAAYJ,SAASP,KAAK,CAAC;QACjC,MAAMY,OAAOD,YAAYA,SAAS,CAAC,EAAE,CAACE,WAAW,KAAK;QAEtD,OAAO;YACLC,OAAO;gBACLL;gBACAG;gBACAV;YACF;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/utilities/extractImageData.ts"],"sourcesContent":["type ImageData = {\n image: { name: string; type: string; url: string }\n}[]\n\n/**\n * Extracts hardcoded image URLs from text using regex.\n * \n * NOTE: This only handles direct URLs in the text.\n * For @field references, use resolveImageReferences utility instead.\n * \n * @param input - Text containing image URLs\n * @returns Array of extracted image data\n */\nexport function extractImageData(input: string): ImageData {\n const regex = /(?:https?:)?\\/[\\w%\\-.,/]+\\.(png|jpe?g|webp)/gi\n const matches = input.match(regex)\n\n if (!matches) {return []}\n\n return matches.map((url) => {\n const decodedUrl = decodeURIComponent(url)\n const parts = decodedUrl.split('/')\n const filename = parts[parts.length - 1]\n const name = filename.replace(/\\.(png|jpe?g|webp)$/i, '')\n const typeMatch = filename.match(/\\.(png|jpe?g|webp)$/i)\n const type = typeMatch ? typeMatch[1].toLowerCase() : 'unknown'\n\n return {\n image: {\n name,\n type,\n url,\n },\n }\n })\n}\n"],"names":["extractImageData","input","regex","matches","match","map","url","decodedUrl","decodeURIComponent","parts","split","filename","length","name","replace","typeMatch","type","toLowerCase","image"],"mappings":"AAIA;;;;;;;;CAQC,GACD,OAAO,SAASA,iBAAiBC,KAAa;IAC5C,MAAMC,QAAQ;IACd,MAAMC,UAAUF,MAAMG,KAAK,CAACF;IAE5B,IAAI,CAACC,SAAS;QAAC,OAAO,EAAE;IAAA;IAExB,OAAOA,QAAQE,GAAG,CAAC,CAACC;QAClB,MAAMC,aAAaC,mBAAmBF;QACtC,MAAMG,QAAQF,WAAWG,KAAK,CAAC;QAC/B,MAAMC,WAAWF,KAAK,CAACA,MAAMG,MAAM,GAAG,EAAE;QACxC,MAAMC,OAAOF,SAASG,OAAO,CAAC,wBAAwB;QACtD,MAAMC,YAAYJ,SAASP,KAAK,CAAC;QACjC,MAAMY,OAAOD,YAAYA,SAAS,CAAC,EAAE,CAACE,WAAW,KAAK;QAEtD,OAAO;YACLC,OAAO;gBACLL;gBACAG;gBACAV;YACF;QACF;IACF;AACF"}
@@ -0,0 +1,14 @@
1
+ import type { ImagePart } from 'ai';
2
+ import type { PayloadRequest } from 'payload';
3
+ export interface FetchableImage {
4
+ image: {
5
+ mimeType?: string;
6
+ thumbnailURL?: string;
7
+ url: string;
8
+ };
9
+ }
10
+ /**
11
+ * Fetches images from a list of objects containing URLs (and optional thumbnails/mimetypes)
12
+ * and converts them to AI SDK compatible ImageParts.
13
+ */
14
+ export declare function fetchImages(req: PayloadRequest, images: FetchableImage[]): Promise<ImagePart[]>;
@@ -0,0 +1,38 @@
1
+ import * as process from 'node:process';
2
+ /**
3
+ * Fetches images from a list of objects containing URLs (and optional thumbnails/mimetypes)
4
+ * and converts them to AI SDK compatible ImageParts.
5
+ */ export async function fetchImages(req, images) {
6
+ const imageParts = [];
7
+ for (const img of images){
8
+ const serverURL = req.payload.config?.serverURL || process.env.SERVER_URL || process.env.NEXT_PUBLIC_SERVER_URL;
9
+ let url = img.image.thumbnailURL || img.image.url;
10
+ if (!url.startsWith('http')) {
11
+ url = `${String(serverURL)}${String(url)}`;
12
+ }
13
+ try {
14
+ const response = await fetch(url, {
15
+ headers: {
16
+ Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`
17
+ },
18
+ method: 'GET'
19
+ });
20
+ if (!response.ok) {
21
+ throw new Error(`Failed to fetch image: ${response.statusText}`);
22
+ }
23
+ const blob = await response.blob();
24
+ const arrayBuffer = await blob.arrayBuffer();
25
+ imageParts.push({
26
+ type: 'image',
27
+ image: arrayBuffer,
28
+ mediaType: img.image.mimeType || blob.type || 'image/png'
29
+ });
30
+ } catch (e) {
31
+ req.payload.logger.error(e, `Error fetching reference image ${url}`);
32
+ throw new Error("We couldn't fetch the images. Please ensure the images are accessible and hosted publicly.");
33
+ }
34
+ }
35
+ return imageParts;
36
+ }
37
+
38
+ //# sourceMappingURL=fetchImages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/fetchImages.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { PayloadRequest } from 'payload'\n\nimport * as process from 'node:process'\n\nexport interface FetchableImage {\n image: {\n mimeType?: string\n thumbnailURL?: string\n url: string\n }\n}\n\n/**\n * Fetches images from a list of objects containing URLs (and optional thumbnails/mimetypes)\n * and converts them to AI SDK compatible ImageParts.\n */\nexport async function fetchImages(\n req: PayloadRequest,\n images: FetchableImage[],\n): Promise<ImagePart[]> {\n const imageParts: ImagePart[] = []\n\n for (const img of images) {\n const serverURL =\n req.payload.config?.serverURL ||\n process.env.SERVER_URL ||\n process.env.NEXT_PUBLIC_SERVER_URL\n\n let url = img.image.thumbnailURL || img.image.url\n if (!url.startsWith('http')) {\n url = `${String(serverURL)}${String(url)}`\n }\n\n try {\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`,\n },\n method: 'GET',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch image: ${response.statusText}`)\n }\n\n const blob = await response.blob()\n const arrayBuffer = await blob.arrayBuffer()\n\n imageParts.push({\n type: 'image',\n image: arrayBuffer,\n mediaType: img.image.mimeType || blob.type || 'image/png',\n })\n } catch (e) {\n req.payload.logger.error(e, `Error fetching reference image ${url}`)\n throw new Error(\n \"We couldn't fetch the images. Please ensure the images are accessible and hosted publicly.\",\n )\n }\n }\n\n return imageParts\n}\n"],"names":["process","fetchImages","req","images","imageParts","img","serverURL","payload","config","env","SERVER_URL","NEXT_PUBLIC_SERVER_URL","url","image","thumbnailURL","startsWith","String","response","fetch","headers","Authorization","get","split","method","ok","Error","statusText","blob","arrayBuffer","push","type","mediaType","mimeType","e","logger","error"],"mappings":"AAGA,YAAYA,aAAa,eAAc;AAUvC;;;CAGC,GACD,OAAO,eAAeC,YACpBC,GAAmB,EACnBC,MAAwB;IAExB,MAAMC,aAA0B,EAAE;IAElC,KAAK,MAAMC,OAAOF,OAAQ;QACxB,MAAMG,YACJJ,IAAIK,OAAO,CAACC,MAAM,EAAEF,aACpBN,QAAQS,GAAG,CAACC,UAAU,IACtBV,QAAQS,GAAG,CAACE,sBAAsB;QAEpC,IAAIC,MAAMP,IAAIQ,KAAK,CAACC,YAAY,IAAIT,IAAIQ,KAAK,CAACD,GAAG;QACjD,IAAI,CAACA,IAAIG,UAAU,CAAC,SAAS;YAC3BH,MAAM,CAAC,EAAEI,OAAOV,WAAW,EAAEU,OAAOJ,KAAK,CAAC;QAC5C;QAEA,IAAI;YACF,MAAMK,WAAW,MAAMC,MAAMN,KAAK;gBAChCO,SAAS;oBACPC,eAAe,CAAC,OAAO,EAAElB,IAAIiB,OAAO,CAACE,GAAG,CAAC,kBAAkBC,MAAM,UAAU,CAAC,EAAE,IAAI,GAAG,CAAC;gBACxF;gBACAC,QAAQ;YACV;YAEA,IAAI,CAACN,SAASO,EAAE,EAAE;gBAChB,MAAM,IAAIC,MAAM,CAAC,uBAAuB,EAAER,SAASS,UAAU,CAAC,CAAC;YACjE;YAEA,MAAMC,OAAO,MAAMV,SAASU,IAAI;YAChC,MAAMC,cAAc,MAAMD,KAAKC,WAAW;YAE1CxB,WAAWyB,IAAI,CAAC;gBACdC,MAAM;gBACNjB,OAAOe;gBACPG,WAAW1B,IAAIQ,KAAK,CAACmB,QAAQ,IAAIL,KAAKG,IAAI,IAAI;YAChD;QACF,EAAE,OAAOG,GAAG;YACV/B,IAAIK,OAAO,CAAC2B,MAAM,CAACC,KAAK,CAACF,GAAG,CAAC,+BAA+B,EAAErB,IAAI,CAAC;YACnE,MAAM,IAAIa,MACR;QAEJ;IACF;IAEA,OAAOrB;AACT"}
@@ -8,6 +8,7 @@
8
8
  * Arrays are emitted only when field.hasMany is true and the field type supports hasMany
9
9
  * (text, textarea, select; for others only if your config truly sets hasMany).
10
10
  */
11
+ import type { Field } from 'payload';
11
12
  export type JsonSchema = Record<string, any>;
12
13
  type BaseField = {
13
14
  admin?: {
@@ -30,7 +31,7 @@ type BaseField = {
30
31
  type?: string;
31
32
  typescriptSchema?: unknown;
32
33
  };
33
- export declare function fieldToJsonSchema(fieldInput: BaseField, opts?: {
34
+ export declare function fieldToJsonSchema(fieldInput: BaseField & Field, opts?: {
34
35
  nameOverride?: string;
35
36
  wrapObject?: boolean;
36
37
  }): JsonSchema;
@@ -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 = {