@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
@@ -0,0 +1,118 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button, useForm, useFormFields } 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
+ // Get the current voices array to know how many rows to remove
18
+ const voicesField = useFormFields(([fields])=>fields[voicesPath]);
19
+ const currentRowCount = voicesField && 'rows' in voicesField && Array.isArray(voicesField.rows) ? voicesField.rows.length : 0;
20
+ const fetchVoices = useCallback(async ()=>{
21
+ setLoading(true);
22
+ try {
23
+ // Call server endpoint - it will read the API key from the database
24
+ const response = await fetch(`/api${PLUGIN_API_ENDPOINT_FETCH_VOICES}`, {
25
+ headers: {
26
+ 'Content-Type': 'application/json'
27
+ },
28
+ method: 'POST'
29
+ });
30
+ if (!response.ok) {
31
+ const error = await response.json();
32
+ throw new Error(error.message || 'Failed to fetch voices');
33
+ }
34
+ const data = await response.json();
35
+ const voices = data.voices || [];
36
+ // Remove existing rows first (in reverse order to maintain indices)
37
+ for(let i = currentRowCount - 1; i >= 0; i--){
38
+ dispatchFields({
39
+ type: 'REMOVE_ROW',
40
+ path: voicesPath,
41
+ rowIndex: i
42
+ });
43
+ }
44
+ // Add new rows for each voice using ADD_ROW action
45
+ for (const voice of voices){
46
+ dispatchFields({
47
+ type: 'ADD_ROW',
48
+ path: voicesPath,
49
+ subFieldState: {
50
+ id: {
51
+ initialValue: voice.id,
52
+ valid: true,
53
+ value: voice.id
54
+ },
55
+ name: {
56
+ initialValue: voice.name,
57
+ valid: true,
58
+ value: voice.name
59
+ },
60
+ category: {
61
+ initialValue: voice.category || 'premade',
62
+ valid: true,
63
+ value: voice.category || 'premade'
64
+ },
65
+ enabled: {
66
+ initialValue: voice.enabled !== false,
67
+ valid: true,
68
+ value: voice.enabled !== false
69
+ },
70
+ labels: {
71
+ initialValue: voice.labels || {},
72
+ valid: true,
73
+ value: voice.labels || {}
74
+ },
75
+ preview_url: {
76
+ initialValue: voice.preview_url || '',
77
+ valid: true,
78
+ value: voice.preview_url || ''
79
+ }
80
+ }
81
+ });
82
+ }
83
+ alert(`Successfully fetched ${voices.length} voices!`);
84
+ } catch (error) {
85
+ alert(`Error: ${error instanceof Error ? error.message : 'Failed to fetch voices'}`);
86
+ } finally{
87
+ setLoading(false);
88
+ }
89
+ }, [
90
+ currentRowCount,
91
+ dispatchFields,
92
+ voicesPath
93
+ ]);
94
+ return /*#__PURE__*/ _jsxs("div", {
95
+ style: {
96
+ marginBottom: '20px'
97
+ },
98
+ children: [
99
+ /*#__PURE__*/ _jsx(Button, {
100
+ buttonStyle: "secondary",
101
+ disabled: loading,
102
+ onClick: fetchVoices,
103
+ size: "medium",
104
+ children: loading ? 'Fetching Voices...' : 'Fetch Voices from ElevenLabs'
105
+ }),
106
+ /*#__PURE__*/ _jsx("p", {
107
+ style: {
108
+ color: 'var(--theme-elevation-600)',
109
+ fontSize: '13px',
110
+ marginTop: '8px'
111
+ },
112
+ children: "This will fetch all available voices from your ElevenLabs account. Make sure you have saved your API key in the Setup tab first."
113
+ })
114
+ ]
115
+ });
116
+ };
117
+
118
+ //# 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, useFormFields } from '@payloadcms/ui'\nimport React, { useCallback, useState } from 'react'\n\nimport { PLUGIN_API_ENDPOINT_FETCH_VOICES } from '../../defaults.js'\n\ninterface Voice {\n category?: string\n enabled?: boolean\n id: string\n labels?: Record<string, unknown>\n name: string\n preview_url?: string\n}\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 // Get the current voices array to know how many rows to remove\n const voicesField = useFormFields(([fields]) => fields[voicesPath])\n const currentRowCount =\n voicesField && 'rows' in voicesField && Array.isArray(voicesField.rows)\n ? voicesField.rows.length\n : 0\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 const voices: Voice[] = data.voices || []\n\n // Remove existing rows first (in reverse order to maintain indices)\n for (let i = currentRowCount - 1; i >= 0; i--) {\n dispatchFields({\n type: 'REMOVE_ROW',\n path: voicesPath,\n rowIndex: i,\n })\n }\n\n // Add new rows for each voice using ADD_ROW action\n for (const voice of voices) {\n dispatchFields({\n type: 'ADD_ROW',\n path: voicesPath,\n subFieldState: {\n id: { initialValue: voice.id, valid: true, value: voice.id },\n name: { initialValue: voice.name, valid: true, value: voice.name },\n category: { initialValue: voice.category || 'premade', valid: true, value: voice.category || 'premade' },\n enabled: { initialValue: voice.enabled !== false, valid: true, value: voice.enabled !== false },\n labels: { initialValue: voice.labels || {}, valid: true, value: voice.labels || {} },\n preview_url: { initialValue: voice.preview_url || '', valid: true, value: voice.preview_url || '' },\n },\n })\n }\n\n alert(`Successfully fetched ${voices.length} voices!`)\n } catch (error) {\n alert(`Error: ${error instanceof Error ? error.message : 'Failed to fetch voices'}`)\n } finally {\n setLoading(false)\n }\n }, [currentRowCount, 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\n\n\n"],"names":["Button","useForm","useFormFields","React","useCallback","useState","PLUGIN_API_ENDPOINT_FETCH_VOICES","VoicesFetcher","path","loading","setLoading","dispatchFields","fieldPath","blockPath","split","slice","join","voicesPath","voicesField","fields","currentRowCount","Array","isArray","rows","length","fetchVoices","response","fetch","headers","method","ok","error","json","Error","message","data","voices","i","type","rowIndex","voice","subFieldState","id","initialValue","valid","value","name","category","enabled","labels","preview_url","alert","div","style","marginBottom","buttonStyle","disabled","onClick","size","p","color","fontSize","marginTop"],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ 'use client';
2
+ import { Button, useForm, useFormFields } 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
+ // Get the current voices array to know how many rows to remove
18
+ const voicesField = useFormFields(([fields]) => fields[voicesPath]);
19
+ const currentRowCount = voicesField && 'rows' in voicesField && Array.isArray(voicesField.rows)
20
+ ? voicesField.rows.length
21
+ : 0;
22
+ const fetchVoices = useCallback(async () => {
23
+ setLoading(true);
24
+ try {
25
+ // Call server endpoint - it will read the API key from the database
26
+ const response = await fetch(`/api${PLUGIN_API_ENDPOINT_FETCH_VOICES}`, {
27
+ headers: {
28
+ 'Content-Type': 'application/json',
29
+ },
30
+ method: 'POST',
31
+ });
32
+ if (!response.ok) {
33
+ const error = await response.json();
34
+ throw new Error(error.message || 'Failed to fetch voices');
35
+ }
36
+ const data = await response.json();
37
+ const voices = data.voices || [];
38
+ // Remove existing rows first (in reverse order to maintain indices)
39
+ for (let i = currentRowCount - 1; i >= 0; i--) {
40
+ dispatchFields({
41
+ type: 'REMOVE_ROW',
42
+ path: voicesPath,
43
+ rowIndex: i,
44
+ });
45
+ }
46
+ // Add new rows for each voice using ADD_ROW action
47
+ for (const voice of voices) {
48
+ dispatchFields({
49
+ type: 'ADD_ROW',
50
+ path: voicesPath,
51
+ subFieldState: {
52
+ id: { initialValue: voice.id, valid: true, value: voice.id },
53
+ name: { initialValue: voice.name, valid: true, value: voice.name },
54
+ category: { initialValue: voice.category || 'premade', valid: true, value: voice.category || 'premade' },
55
+ enabled: { initialValue: voice.enabled !== false, valid: true, value: voice.enabled !== false },
56
+ labels: { initialValue: voice.labels || {}, valid: true, value: voice.labels || {} },
57
+ preview_url: { initialValue: voice.preview_url || '', valid: true, value: voice.preview_url || '' },
58
+ },
59
+ });
60
+ }
61
+ alert(`Successfully fetched ${voices.length} voices!`);
62
+ }
63
+ catch (error) {
64
+ alert(`Error: ${error instanceof Error ? error.message : 'Failed to fetch voices'}`);
65
+ }
66
+ finally {
67
+ setLoading(false);
68
+ }
69
+ }, [currentRowCount, dispatchFields, voicesPath]);
70
+ return (<div style={{ marginBottom: '20px' }}>
71
+ <Button buttonStyle="secondary" disabled={loading} onClick={fetchVoices} size="medium">
72
+ {loading ? 'Fetching Voices...' : 'Fetch Voices from ElevenLabs'}
73
+ </Button>
74
+ <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', marginTop: '8px' }}>
75
+ This will fetch all available voices from your ElevenLabs account. Make sure you have saved
76
+ your API key in the Setup tab first.
77
+ </p>
78
+ </div>);
79
+ };
@@ -0,0 +1,22 @@
1
+ import type { Payload } from 'payload';
2
+ export interface SmartPromptContext {
3
+ /** The document data for template interpolation */
4
+ documentData?: Record<string, unknown>;
5
+ /** The Payload instance to access collection config */
6
+ payload: Payload;
7
+ /** The schema path like 'array-test-cases.teamMembers.contact.email' */
8
+ schemaPath: string;
9
+ }
10
+ /**
11
+ * Build a smart contextual prompt based on field metadata.
12
+ * This is used as a fallback when the user hasn't set a custom prompt.
13
+ *
14
+ * @param context - The context containing schema path and document data
15
+ * @returns A contextual prompt string that can be used for AI generation
16
+ */
17
+ export declare const buildSmartPrompt: (context: SmartPromptContext) => string;
18
+ /**
19
+ * Check if a prompt template is empty and should be replaced with a smart prompt.
20
+ * Only triggers when the prompt is completely empty or whitespace-only.
21
+ */
22
+ export declare const isGenericPrompt: (template: null | string | undefined) => boolean;
@@ -0,0 +1,143 @@
1
+ 'use strict';
2
+ import { getFieldBySchemaPath } from './getFieldBySchemaPath.js';
3
+ /**
4
+ * Extract field information from a schema path
5
+ */ const getFieldInfo = (schemaPath, payload)=>{
6
+ const parts = schemaPath.split('.');
7
+ const collectionSlug = parts[0];
8
+ const fieldPath = parts.slice(1);
9
+ const fieldName = fieldPath[fieldPath.length - 1] || '';
10
+ // Get parent context (e.g., 'teamMembers' for 'teamMembers.name')
11
+ let parentContext = null;
12
+ if (fieldPath.length > 1) {
13
+ parentContext = fieldPath[fieldPath.length - 2];
14
+ }
15
+ // Try to get the actual field configuration from the collection
16
+ let field = null;
17
+ const collection = payload.config.collections.find((c)=>c.slug === collectionSlug);
18
+ if (collection) {
19
+ field = getFieldBySchemaPath(collection, schemaPath);
20
+ }
21
+ return {
22
+ name: fieldName,
23
+ type: field?.type || 'text',
24
+ field,
25
+ label: field?.label || fieldName,
26
+ parentContext
27
+ };
28
+ };
29
+ /**
30
+ * Humanize a camelCase or snake_case field name
31
+ * e.g., 'teamMembers' -> 'team members', 'first_name' -> 'first name'
32
+ */ const humanize = (str)=>{
33
+ return str.replace(/([a-z])([A-Z])/g, '$1 $2') // camelCase to spaces
34
+ .replace(/[_-]/g, ' ') // underscores/dashes to spaces
35
+ .toLowerCase().trim();
36
+ };
37
+ /**
38
+ * Get a description snippet from field admin config
39
+ */ const getFieldDescription = (field)=>{
40
+ if (!field) {
41
+ return null;
42
+ }
43
+ const admin = field.admin;
44
+ if (admin?.description && typeof admin.description === 'string') {
45
+ return admin.description;
46
+ }
47
+ return null;
48
+ };
49
+ /**
50
+ * Build type-specific prompt guidance
51
+ */ const getTypeGuidance = (type, fieldName)=>{
52
+ const nameHint = humanize(fieldName);
53
+ switch(type){
54
+ case 'code':
55
+ return `Generate code for ${nameHint}`;
56
+ case 'date':
57
+ return `Generate an appropriate date for ${nameHint}`;
58
+ case 'email':
59
+ return `Generate a valid professional email address`;
60
+ case 'json':
61
+ return `Generate valid JSON data for ${nameHint}`;
62
+ case 'number':
63
+ return `Generate an appropriate numeric value for ${nameHint}`;
64
+ case 'select':
65
+ return `Select an appropriate option for ${nameHint}`;
66
+ case 'text':
67
+ return `Generate appropriate text for ${nameHint}`;
68
+ case 'textarea':
69
+ return `Write detailed content for ${nameHint}`;
70
+ case 'upload':
71
+ // Explicit image generation instruction for multimodal models
72
+ return `Generate an image of ${nameHint}`;
73
+ default:
74
+ return `Generate content for ${nameHint}`;
75
+ }
76
+ };
77
+ /**
78
+ * Build context from parent field name using generic humanization.
79
+ * Works universally for any collection structure.
80
+ */ const getParentContextPhrase = (parentContext)=>{
81
+ if (!parentContext) {
82
+ return '';
83
+ }
84
+ const humanized = humanize(parentContext);
85
+ // Use singular form if the name ends with 's' (common for arrays)
86
+ // e.g., "teamMembers" → "team member", "products" → "product"
87
+ if (humanized.endsWith('s') && humanized.length > 2) {
88
+ return `for a ${humanized.slice(0, -1)} entry`;
89
+ }
90
+ return `for ${humanized}`;
91
+ };
92
+ /**
93
+ * Build a smart contextual prompt based on field metadata.
94
+ * This is used as a fallback when the user hasn't set a custom prompt.
95
+ *
96
+ * @param context - The context containing schema path and document data
97
+ * @returns A contextual prompt string that can be used for AI generation
98
+ */ export const buildSmartPrompt = (context)=>{
99
+ const { documentData, payload, schemaPath } = context;
100
+ const fieldInfo = getFieldInfo(schemaPath, payload);
101
+ const { name, type, field, label, parentContext } = fieldInfo;
102
+ // Start with the field's own description if available
103
+ const description = getFieldDescription(field);
104
+ // Build the prompt components
105
+ const parts = [];
106
+ // Use description as primary guidance if available
107
+ if (description) {
108
+ parts.push(description);
109
+ } else {
110
+ // Fall back to type-based guidance, prefer label over name for better context
111
+ parts.push(getTypeGuidance(type, label || name));
112
+ }
113
+ // Add parent context if nested
114
+ const parentPhrase = getParentContextPhrase(parentContext);
115
+ if (parentPhrase) {
116
+ parts.push(parentPhrase);
117
+ }
118
+ // Add document title context if available
119
+ const title = documentData?.title;
120
+ if (title && typeof title === 'string') {
121
+ parts.push(`in the context of "${title}"`);
122
+ }
123
+ // Build the final prompt
124
+ let prompt = parts.join(' ');
125
+ // Ensure first letter is capitalized
126
+ prompt = prompt.charAt(0).toUpperCase() + prompt.slice(1);
127
+ // Add instruction suffix for clarity
128
+ if (!prompt.endsWith('.')) {
129
+ prompt += '.';
130
+ }
131
+ return prompt;
132
+ };
133
+ /**
134
+ * Check if a prompt template is empty and should be replaced with a smart prompt.
135
+ * Only triggers when the prompt is completely empty or whitespace-only.
136
+ */ export const isGenericPrompt = (template)=>{
137
+ if (!template) {
138
+ return true;
139
+ }
140
+ return template.trim() === '';
141
+ };
142
+
143
+ //# sourceMappingURL=buildSmartPrompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/buildSmartPrompt.ts"],"sourcesContent":["'use strict'\n\nimport type { Field, Payload } from 'payload'\n\nimport { getFieldBySchemaPath } from './getFieldBySchemaPath.js'\n\nexport interface SmartPromptContext {\n /** The document data for template interpolation */\n documentData?: Record<string, unknown>\n /** The Payload instance to access collection config */\n payload: Payload\n /** The schema path like 'array-test-cases.teamMembers.contact.email' */\n schemaPath: string\n}\n\ninterface FieldInfo {\n /** The field configuration */\n field: Field | null\n /** Human-readable field label */\n label: string\n /** Field name from the path */\n name: string\n /** Parent field name if nested (e.g., 'teamMembers' for 'teamMembers.name') */\n parentContext: null | string\n /** The field type */\n type: string\n}\n\n/**\n * Extract field information from a schema path\n */\nconst getFieldInfo = (schemaPath: string, payload: Payload): FieldInfo => {\n const parts = schemaPath.split('.')\n const collectionSlug = parts[0]\n const fieldPath = parts.slice(1)\n const fieldName = fieldPath[fieldPath.length - 1] || ''\n \n // Get parent context (e.g., 'teamMembers' for 'teamMembers.name')\n let parentContext: null | string = null\n if (fieldPath.length > 1) {\n parentContext = fieldPath[fieldPath.length - 2]\n }\n \n // Try to get the actual field configuration from the collection\n let field: Field | null = null\n const collection = payload.config.collections.find(c => c.slug === collectionSlug)\n if (collection) {\n field = getFieldBySchemaPath(collection, schemaPath)\n }\n \n return {\n name: fieldName,\n type: field?.type || 'text',\n field,\n label: (field as { label?: string })?.label || fieldName,\n parentContext,\n }\n}\n\n/**\n * Humanize a camelCase or snake_case field name\n * e.g., 'teamMembers' -> 'team members', 'first_name' -> 'first name'\n */\nconst humanize = (str: string): string => {\n return str\n .replace(/([a-z])([A-Z])/g, '$1 $2') // camelCase to spaces\n .replace(/[_-]/g, ' ') // underscores/dashes to spaces\n .toLowerCase()\n .trim()\n}\n\n/**\n * Get a description snippet from field admin config\n */\nconst getFieldDescription = (field: Field | null): null | string => {\n if (!field) {return null}\n const admin = (field as { admin?: { description?: string } }).admin\n if (admin?.description && typeof admin.description === 'string') {\n return admin.description\n }\n return null\n}\n\n/**\n * Build type-specific prompt guidance\n */\nconst getTypeGuidance = (type: string, fieldName: string): string => {\n const nameHint = humanize(fieldName)\n \n switch (type) {\n case 'code':\n return `Generate code for ${nameHint}`\n case 'date':\n return `Generate an appropriate date for ${nameHint}`\n case 'email':\n return `Generate a valid professional email address`\n case 'json':\n return `Generate valid JSON data for ${nameHint}`\n case 'number':\n return `Generate an appropriate numeric value for ${nameHint}`\n case 'select':\n return `Select an appropriate option for ${nameHint}`\n case 'text':\n return `Generate appropriate text for ${nameHint}`\n case 'textarea':\n return `Write detailed content for ${nameHint}`\n case 'upload':\n // Explicit image generation instruction for multimodal models\n return `Generate an image of ${nameHint}`\n default:\n return `Generate content for ${nameHint}`\n }\n}\n\n/**\n * Build context from parent field name using generic humanization.\n * Works universally for any collection structure.\n */\nconst getParentContextPhrase = (parentContext: null | string): string => {\n if (!parentContext) {\n return ''\n }\n \n const humanized = humanize(parentContext)\n \n // Use singular form if the name ends with 's' (common for arrays)\n // e.g., \"teamMembers\" → \"team member\", \"products\" → \"product\"\n if (humanized.endsWith('s') && humanized.length > 2) {\n return `for a ${humanized.slice(0, -1)} entry`\n }\n \n return `for ${humanized}`\n}\n\n/**\n * Build a smart contextual prompt based on field metadata.\n * This is used as a fallback when the user hasn't set a custom prompt.\n * \n * @param context - The context containing schema path and document data\n * @returns A contextual prompt string that can be used for AI generation\n */\nexport const buildSmartPrompt = (context: SmartPromptContext): string => {\n const { documentData, payload, schemaPath } = context\n \n const fieldInfo = getFieldInfo(schemaPath, payload)\n const { name, type, field, label, parentContext } = fieldInfo\n \n // Start with the field's own description if available\n const description = getFieldDescription(field)\n \n // Build the prompt components\n const parts: string[] = []\n \n // Use description as primary guidance if available\n if (description) {\n parts.push(description)\n } else {\n // Fall back to type-based guidance, prefer label over name for better context\n parts.push(getTypeGuidance(type, label || name))\n }\n \n // Add parent context if nested\n const parentPhrase = getParentContextPhrase(parentContext)\n if (parentPhrase) {\n parts.push(parentPhrase)\n }\n \n // Add document title context if available\n const title = documentData?.title\n if (title && typeof title === 'string') {\n parts.push(`in the context of \"${title}\"`)\n }\n \n // Build the final prompt\n let prompt = parts.join(' ')\n \n // Ensure first letter is capitalized\n prompt = prompt.charAt(0).toUpperCase() + prompt.slice(1)\n \n // Add instruction suffix for clarity\n if (!prompt.endsWith('.')) {\n prompt += '.'\n }\n \n return prompt\n}\n\n/**\n * Check if a prompt template is empty and should be replaced with a smart prompt.\n * Only triggers when the prompt is completely empty or whitespace-only.\n */\nexport const isGenericPrompt = (template: null | string | undefined): boolean => {\n if (!template) {\n return true\n }\n return template.trim() === ''\n}\n"],"names":["getFieldBySchemaPath","getFieldInfo","schemaPath","payload","parts","split","collectionSlug","fieldPath","slice","fieldName","length","parentContext","field","collection","config","collections","find","c","slug","name","type","label","humanize","str","replace","toLowerCase","trim","getFieldDescription","admin","description","getTypeGuidance","nameHint","getParentContextPhrase","humanized","endsWith","buildSmartPrompt","context","documentData","fieldInfo","push","parentPhrase","title","prompt","join","charAt","toUpperCase","isGenericPrompt","template"],"mappings":"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"}
@@ -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;