@ai-stack/payloadcms 3.68.0 → 3.76.0-beta.1

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 (187) hide show
  1. package/dist/ai/core/media/image/generateImage.js +2 -6
  2. package/dist/ai/core/media/image/generateImage.js.map +1 -1
  3. package/dist/ai/core/media/image/handlers/multimodal.js +13 -28
  4. package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -1
  5. package/dist/ai/core/media/image/handlers/standard.js +10 -7
  6. package/dist/ai/core/media/image/handlers/standard.js.map +1 -1
  7. package/dist/ai/core/media/speech/generateSpeech.js +8 -8
  8. package/dist/ai/core/media/speech/generateSpeech.js.map +1 -1
  9. package/dist/ai/core/media/types.d.ts +1 -1
  10. package/dist/ai/core/media/types.js.map +1 -1
  11. package/dist/ai/core/streamObject.js +3 -3
  12. package/dist/ai/core/streamObject.js.map +1 -1
  13. package/dist/ai/core/types.d.ts +3 -0
  14. package/dist/ai/core/types.js.map +1 -1
  15. package/dist/ai/prompts.d.ts +1 -2
  16. package/dist/ai/prompts.js +0 -110
  17. package/dist/ai/prompts.js.map +1 -1
  18. package/dist/ai/providers/blocks/anthropic.js +2 -1
  19. package/dist/ai/providers/blocks/anthropic.js.map +1 -1
  20. package/dist/ai/providers/blocks/elevenlabs.js +3 -2
  21. package/dist/ai/providers/blocks/elevenlabs.js.map +1 -1
  22. package/dist/ai/providers/blocks/fal.js +2 -1
  23. package/dist/ai/providers/blocks/fal.js.map +1 -1
  24. package/dist/ai/providers/blocks/google.js +12 -6
  25. package/dist/ai/providers/blocks/google.js.map +1 -1
  26. package/dist/ai/providers/blocks/openai-compatible.js +2 -1
  27. package/dist/ai/providers/blocks/openai-compatible.js.map +1 -1
  28. package/dist/ai/providers/blocks/openai.js +3 -2
  29. package/dist/ai/providers/blocks/openai.js.map +1 -1
  30. package/dist/ai/providers/blocks/xai.js +2 -1
  31. package/dist/ai/providers/blocks/xai.js.map +1 -1
  32. package/dist/ai/providers/icons.d.ts +7 -0
  33. package/dist/ai/providers/icons.js +9 -0
  34. package/dist/ai/providers/icons.js.map +1 -0
  35. package/dist/ai/providers/registry.js +36 -26
  36. package/dist/ai/providers/registry.js.map +1 -1
  37. package/dist/ai/utils/filterEditorSchemaByNodes.d.ts +9 -0
  38. package/dist/ai/utils/filterEditorSchemaByNodes.js +30 -3
  39. package/dist/ai/utils/filterEditorSchemaByNodes.js.map +1 -1
  40. package/dist/ai/utils/nodeToSchemaMap.d.ts +22 -0
  41. package/dist/ai/utils/nodeToSchemaMap.js +72 -0
  42. package/dist/ai/utils/nodeToSchemaMap.js.map +1 -0
  43. package/dist/collections/AIJobs.js +1 -1
  44. package/dist/collections/AIJobs.js.map +1 -1
  45. package/dist/collections/AIProviders.d.ts +2 -0
  46. package/dist/collections/{AISettings.js → AIProviders.js} +53 -25
  47. package/dist/collections/AIProviders.js.map +1 -0
  48. package/dist/collections/Instructions.js +45 -4
  49. package/dist/collections/Instructions.js.map +1 -1
  50. package/dist/defaults.d.ts +1 -0
  51. package/dist/defaults.js +8 -0
  52. package/dist/defaults.js.map +1 -1
  53. package/dist/endpoints/chat.d.ts +4 -0
  54. package/dist/endpoints/fetchFields.js +10 -0
  55. package/dist/endpoints/fetchFields.js.map +1 -1
  56. package/dist/endpoints/fetchVoices.js +42 -25
  57. package/dist/endpoints/fetchVoices.js.map +1 -1
  58. package/dist/endpoints/index.js +248 -35
  59. package/dist/endpoints/index.js.map +1 -1
  60. package/dist/exports/client.d.ts +1 -1
  61. package/dist/exports/client.js +1 -1
  62. package/dist/exports/client.js.map +1 -1
  63. package/dist/exports/fields.d.ts +1 -0
  64. package/dist/exports/fields.js +1 -0
  65. package/dist/exports/fields.js.map +1 -1
  66. package/dist/fields/ArrayComposeField/ArrayComposeField.d.ts +15 -0
  67. package/dist/fields/ArrayComposeField/ArrayComposeField.js +87 -0
  68. package/dist/fields/ArrayComposeField/ArrayComposeField.js.map +1 -0
  69. package/dist/fields/ArrayComposeField/ArrayComposeField.jsx +73 -0
  70. package/dist/fields/PromptEditorField/PromptEditorField.js +7 -2
  71. package/dist/fields/PromptEditorField/PromptEditorField.js.map +1 -1
  72. package/dist/fields/PromptEditorField/PromptEditorField.jsx +5 -2
  73. package/dist/index.d.ts +3 -1
  74. package/dist/index.js +2 -1
  75. package/dist/index.js.map +1 -1
  76. package/dist/payload-ai.d.ts +152 -0
  77. package/dist/plugin.js +18 -34
  78. package/dist/plugin.js.map +1 -1
  79. package/dist/providers/InstructionsProvider/InstructionsProvider.js +47 -15
  80. package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
  81. package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +39 -16
  82. package/dist/providers/InstructionsProvider/context.d.ts +3 -0
  83. package/dist/providers/InstructionsProvider/context.js +2 -0
  84. package/dist/providers/InstructionsProvider/context.js.map +1 -1
  85. package/dist/providers/InstructionsProvider/useInstructions.js +22 -3
  86. package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
  87. package/dist/styles.d.ts +11 -0
  88. package/dist/types/handlebars-async-helpers.d.ts +1 -0
  89. package/dist/types/handlebars-dist-handlebars.d.ts +1 -0
  90. package/dist/types/react-mentions.d.ts +1 -0
  91. package/dist/types.d.ts +36 -7
  92. package/dist/types.js +1 -0
  93. package/dist/types.js.map +1 -1
  94. package/dist/ui/AIConfigDashboard/index.d.ts +1 -1
  95. package/dist/ui/AIConfigDashboard/index.js +201 -23
  96. package/dist/ui/AIConfigDashboard/index.js.map +1 -1
  97. package/dist/ui/AIConfigDashboard/index.jsx +166 -15
  98. package/dist/ui/Compose/Compose.d.ts +1 -0
  99. package/dist/ui/Compose/Compose.js +23 -4
  100. package/dist/ui/Compose/Compose.js.map +1 -1
  101. package/dist/ui/Compose/Compose.jsx +23 -4
  102. package/dist/ui/Compose/UndoRedoActions.d.ts +2 -2
  103. package/dist/ui/Compose/UndoRedoActions.js +8 -5
  104. package/dist/ui/Compose/UndoRedoActions.js.map +1 -1
  105. package/dist/ui/Compose/UndoRedoActions.jsx +6 -5
  106. package/dist/ui/Compose/compose.module.css +56 -16
  107. package/dist/ui/Compose/hooks/menu/TranslateMenu.d.ts +5 -0
  108. package/dist/ui/Compose/hooks/menu/TranslateMenu.js +45 -4
  109. package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
  110. package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +41 -5
  111. package/dist/ui/Compose/hooks/menu/itemsMap.js +12 -6
  112. package/dist/ui/Compose/hooks/menu/itemsMap.js.map +1 -1
  113. package/dist/ui/Compose/hooks/menu/menu.module.scss +4 -1
  114. package/dist/ui/Compose/hooks/menu/useMenu.js +26 -15
  115. package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
  116. package/dist/ui/Compose/hooks/menu/useMenu.jsx +25 -12
  117. package/dist/ui/Compose/hooks/useActiveFieldTracking.js +34 -0
  118. package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
  119. package/dist/ui/Compose/hooks/useGenerate.js +26 -174
  120. package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
  121. package/dist/ui/Compose/hooks/useGenerateUpload.d.ts +11 -0
  122. package/dist/ui/Compose/hooks/useGenerateUpload.js +156 -0
  123. package/dist/ui/Compose/hooks/useGenerateUpload.js.map +1 -0
  124. package/dist/ui/Compose/hooks/useHistory.d.ts +0 -1
  125. package/dist/ui/Compose/hooks/useHistory.js +65 -25
  126. package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
  127. package/dist/ui/Compose/hooks/useStreamingUpdate.d.ts +8 -0
  128. package/dist/ui/Compose/hooks/useStreamingUpdate.js +48 -0
  129. package/dist/ui/Compose/hooks/useStreamingUpdate.js.map +1 -0
  130. package/dist/ui/ConfigDashboard/index.d.ts +2 -0
  131. package/dist/ui/ConfigDashboard/index.js +224 -0
  132. package/dist/ui/ConfigDashboard/index.js.map +1 -0
  133. package/dist/ui/ConfigDashboard/index.jsx +175 -0
  134. package/dist/ui/DynamicModelSelect/index.js +1 -1
  135. package/dist/ui/DynamicModelSelect/index.js.map +1 -1
  136. package/dist/ui/DynamicModelSelect/index.jsx +1 -1
  137. package/dist/ui/DynamicProviderSelect/index.js +1 -1
  138. package/dist/ui/DynamicProviderSelect/index.js.map +1 -1
  139. package/dist/ui/DynamicProviderSelect/index.jsx +1 -1
  140. package/dist/ui/DynamicVoiceSelect/index.js +63 -11
  141. package/dist/ui/DynamicVoiceSelect/index.js.map +1 -1
  142. package/dist/ui/DynamicVoiceSelect/index.jsx +47 -14
  143. package/dist/ui/EncryptedTextField/index.js +4 -4
  144. package/dist/ui/EncryptedTextField/index.js.map +1 -1
  145. package/dist/ui/EncryptedTextField/index.jsx +4 -4
  146. package/dist/ui/ProviderOptionsEditor/index.js +1 -1
  147. package/dist/ui/ProviderOptionsEditor/index.js.map +1 -1
  148. package/dist/ui/ProviderOptionsEditor/index.jsx +1 -1
  149. package/dist/ui/VoicesFetcher/index.js +34 -16
  150. package/dist/ui/VoicesFetcher/index.js.map +1 -1
  151. package/dist/ui/VoicesFetcher/index.jsx +32 -15
  152. package/dist/utilities/buildSmartPrompt.d.ts +22 -0
  153. package/dist/utilities/buildSmartPrompt.js +141 -0
  154. package/dist/utilities/buildSmartPrompt.js.map +1 -0
  155. package/dist/utilities/encryption.js +2 -1
  156. package/dist/utilities/encryption.js.map +1 -1
  157. package/dist/utilities/fieldToJsonSchema.js +32 -3
  158. package/dist/utilities/fieldToJsonSchema.js.map +1 -1
  159. package/dist/utilities/resolveImageReferences.d.ts +3 -1
  160. package/dist/utilities/resolveImageReferences.js +21 -2
  161. package/dist/utilities/resolveImageReferences.js.map +1 -1
  162. package/dist/utilities/seedProperties.d.ts +7 -0
  163. package/dist/utilities/seedProperties.js +100 -0
  164. package/dist/utilities/seedProperties.js.map +1 -0
  165. package/dist/utilities/setSafeLexicalState.js +79 -6
  166. package/dist/utilities/setSafeLexicalState.js.map +1 -1
  167. package/dist/utilities/updateFieldsConfig.d.ts +1 -1
  168. package/dist/utilities/updateFieldsConfig.js +9 -2
  169. package/dist/utilities/updateFieldsConfig.js.map +1 -1
  170. package/package.json +35 -33
  171. package/dist/collections/AISettings.d.ts +0 -2
  172. package/dist/collections/AISettings.js.map +0 -1
  173. package/dist/endpoints/chat.d.js +0 -3
  174. package/dist/endpoints/chat.d.js.map +0 -1
  175. package/dist/init.d.ts +0 -7
  176. package/dist/init.js +0 -135
  177. package/dist/init.js.map +0 -1
  178. package/dist/payload-ai.d.js +0 -3
  179. package/dist/payload-ai.d.js.map +0 -1
  180. package/dist/styles.d.js +0 -2
  181. package/dist/styles.d.js.map +0 -1
  182. package/dist/types/handlebars-async-helpers.d.js +0 -2
  183. package/dist/types/handlebars-async-helpers.d.js.map +0 -1
  184. package/dist/types/handlebars-dist-handlebars.d.js +0 -2
  185. package/dist/types/handlebars-dist-handlebars.d.js.map +0 -1
  186. package/dist/types/react-mentions.d.js +0 -2
  187. package/dist/types/react-mentions.d.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/fieldToJsonSchema.ts"],"sourcesContent":["/**\n * fieldToJsonSchema\n * Convert a Payload Field (server or client) into a minimal JSON Schema object,\n * wrapped as { type: 'object', properties: { [name]: valueSchema }, required: [...] }\n *\n * Supported types:\n * - text, textarea, select, number, date, code, email, json\n * Arrays are emitted only when field.hasMany is true and the field type supports hasMany\n * (text, textarea, select; for others only if your config truly sets hasMany).\n */\nimport type { Field } from 'payload'\n\nexport type JsonSchema = Record<string, any>;\n\n// Narrowed minimal typing to avoid anywhere possible without pulling the full payload types at runtime.\n// In a Payload project, you can import type { Field, ClientField } from 'payload' and use those instead.\ntype BaseField = {\n admin?: {\n description?: unknown;\n language?: unknown;\n };\n hasMany?: boolean;\n // json\n jsonSchema?: unknown;\n max?: number;\n maxRows?: number;\n // number\n min?: number;\n // text/textarea\n minRows?: number;\n name?: string;\n // select\n options?: Array<\n | {\n label?: unknown;\n value: number | string;\n }\n | number\n | string\n >;\n required?: boolean;\n schema?: unknown;\n type?: string;\n typescriptSchema?: unknown;\n};\n\nfunction isString(s: unknown): s is string {\n return typeof s === 'string';\n}\n\nfunction isPlainObject(o: unknown): o is Record<string, unknown> {\n return !!o && typeof o === 'object' && !Array.isArray(o);\n}\n\nfunction getDescription(field: BaseField): string | undefined {\n const d = field?.admin?.description;\n return typeof d === 'string' ? d : undefined;\n}\n\nfunction stringWithDescription(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction numberWithBounds(field: BaseField) {\n const out: Record<string, any> = { type: 'number' };\n if (typeof field.min === 'number') {out.minimum = field.min;}\n if (typeof field.max === 'number') {out.maximum = field.max;}\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction dateSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'date-time' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction codeSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n let description = getDescription(field);\n const lang = field?.admin?.language;\n if (typeof lang === 'string' && lang.trim()) {\n description = description ? `${description} (language: ${lang})` : `language: ${lang}`;\n }\n if (description) {out.description = description;}\n return out;\n}\n\nfunction emailSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'email' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction jsonValueSchema(field: BaseField) {\n // Prefer a provided JSON Schema object\n if (isPlainObject(field.jsonSchema)) {return field.jsonSchema as object;}\n if (isPlainObject(field.schema)) {return field.schema as object;}\n\n // typescriptSchema cannot be executed here; default to object\n return { type: 'object' };\n}\n\nfunction normalizeSelectOptions(field: BaseField): { values: Array<number | string>; valueType: 'number' | 'string' } {\n const raw = field.options || [];\n const values: Array<number | string> = [];\n\n for (const opt of raw) {\n if (typeof opt === 'string' || typeof opt === 'number') {\n values.push(opt);\n } else if (isPlainObject(opt) && ('value' in opt)) {\n const v = (opt as any).value;\n if (typeof v === 'string' || typeof v === 'number') {\n values.push(v);\n }\n }\n }\n\n // Infer primitive type\n const allNumbers = values.length > 0 && values.every((v) => typeof v === 'number');\n const valueType: 'number' | 'string' = allNumbers ? 'number' : 'string';\n return { values, valueType };\n}\n\nfunction supportsHasMany(fieldType: string | undefined): boolean {\n // Out of the box: text, textarea, select support hasMany\n // Others can be arrays only if your config truly sets hasMany; we return boolean based on type here.\n return fieldType === 'text' || fieldType === 'textarea' || fieldType === 'select';\n}\n\nexport function fieldToJsonSchema(\n fieldInput: BaseField & Field,\n opts?: { nameOverride?: string; wrapObject?: boolean },\n): JsonSchema {\n const field = fieldInput || {};\n const name = isString(opts?.nameOverride) && opts?.nameOverride.length ? opts.nameOverride : (field.name || 'value');\n const type = field.type;\n\n let valueSchema: null | Record<string, any> = null;\n\n switch (type) {\n case 'array':\n case 'group': {\n if ('fields' in field && Array.isArray(field.fields)) {\n const properties: Record<string, any> = {}\n const required: string[] = []\n \n const processFields = (fields: any[]) => {\n for (const subField of fields) {\n if (subField.type === 'row' || subField.type === 'collapsible') {\n if (subField.fields) {processFields(subField.fields)}\n continue\n }\n if (!subField.name) {continue}\n\n const subSchema = fieldToJsonSchema(subField, { wrapObject: false })\n if (subSchema && Object.keys(subSchema).length > 0) {\n properties[subField.name] = subSchema\n if (subField.required) {required.push(subField.name)}\n }\n }\n }\n \n processFields(field.fields)\n\n const objSchema = {\n type: 'object',\n additionalProperties: false,\n properties,\n required: required.length ? required : undefined\n }\n\n if (type === 'array') {\n valueSchema = {\n type: 'array',\n items: objSchema\n }\n } else {\n valueSchema = objSchema\n }\n \n const description = getDescription(field);\n if (description) {valueSchema.description = description;}\n }\n break;\n }\n\n case 'checkbox': {\n valueSchema = { type: 'boolean' };\n const description = getDescription(field);\n if (description) {valueSchema.description = description;}\n break;\n }\n\n case 'code': {\n const base = codeSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'date': {\n const base = dateSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'email': {\n const base = emailSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'json': {\n const base = jsonValueSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base as Record<string, any>;\n }\n break;\n }\n\n case 'number': {\n const base = numberWithBounds(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n case 'select': {\n const { values, valueType } = normalizeSelectOptions(field);\n const baseSingle: Record<string, any> = { type: valueType, enum: values };\n const description = getDescription(field);\n if (description) {baseSingle.description = description;}\n\n if (field.hasMany && supportsHasMany(type)) {\n valueSchema = {\n type: 'array',\n items: { type: valueType, enum: values },\n ...(description ? { description } : {}),\n };\n } else {\n valueSchema = baseSingle;\n }\n break;\n }\n\n case 'text':\n case 'textarea': {\n const base = stringWithDescription(field);\n if (field.hasMany && supportsHasMany(type)) {\n const arr: Record<string, any> = {\n type: 'array',\n items: { type: 'string' },\n };\n if (typeof field.minRows === 'number') {arr.minItems = field.minRows;}\n if (typeof field.maxRows === 'number') {arr.maxItems = field.maxRows;}\n if (base.description) {arr.description = base.description;}\n valueSchema = arr;\n } else {\n valueSchema = base;\n }\n break;\n }\n \n // Explicitly handle organizational types to avoid default breakage if passed directly\n // though usually they are handled by parent recursion in group/array case above.\n // If passed as root, we can't really return a meaningful single-value schema without a wrapper?\n // But let's leave default for them or handle if necessary. \n // For now, if someone passes a 'row' as root, it will fall to default (null).\n\n default: {\n valueSchema = null;\n break;\n }\n }\n\n const wrap = opts?.wrapObject !== false;\n\n if (!wrap) {\n return (valueSchema || {}) as JsonSchema;\n }\n\n if (!valueSchema) {\n return {} as JsonSchema;\n }\n\n const schema: JsonSchema = {\n type: 'object',\n additionalProperties: false,\n properties: {\n [name]: valueSchema,\n },\n required: [name]\n };\n\n return schema;\n}\n"],"names":["isString","s","isPlainObject","o","Array","isArray","getDescription","field","d","admin","description","undefined","stringWithDescription","out","type","numberWithBounds","min","minimum","max","maximum","dateSchema","format","codeSchema","lang","language","trim","emailSchema","jsonValueSchema","jsonSchema","schema","normalizeSelectOptions","raw","options","values","opt","push","v","value","allNumbers","length","every","valueType","supportsHasMany","fieldType","fieldToJsonSchema","fieldInput","opts","name","nameOverride","valueSchema","fields","properties","required","processFields","subField","subSchema","wrapObject","Object","keys","objSchema","additionalProperties","items","base","hasMany","baseSingle","enum","arr","minRows","minItems","maxRows","maxItems","wrap"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/fieldToJsonSchema.ts"],"sourcesContent":["/**\n * fieldToJsonSchema\n * Convert a Payload Field (server or client) into a minimal JSON Schema object,\n * wrapped as { type: 'object', properties: { [name]: valueSchema }, required: [...] }\n *\n * Supported types:\n * - text, textarea, select, number, date, code, email, json\n * Arrays are emitted only when field.hasMany is true and the field type supports hasMany\n * (text, textarea, select; for others only if your config truly sets hasMany).\n */\nimport type { Field } from 'payload'\n\nexport type JsonSchema = Record<string, any>;\n\n// Narrowed minimal typing to avoid anywhere possible without pulling the full payload types at runtime.\n// In a Payload project, you can import type { Field, ClientField } from 'payload' and use those instead.\ntype BaseField = {\n admin?: {\n description?: unknown;\n language?: unknown;\n };\n hasMany?: boolean;\n // json\n jsonSchema?: unknown;\n max?: number;\n maxRows?: number;\n // number\n min?: number;\n // text/textarea\n minRows?: number;\n name?: string;\n // select\n options?: Array<\n | {\n label?: unknown;\n value: number | string;\n }\n | number\n | string\n >;\n required?: boolean;\n schema?: unknown;\n type?: string;\n typescriptSchema?: unknown;\n};\n\nfunction isString(s: unknown): s is string {\n return typeof s === 'string';\n}\n\nfunction isPlainObject(o: unknown): o is Record<string, unknown> {\n return !!o && typeof o === 'object' && !Array.isArray(o);\n}\n\nfunction getDescription(field: BaseField): string | undefined {\n const d = field?.admin?.description;\n return typeof d === 'string' ? d : undefined;\n}\n\nfunction stringWithDescription(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction numberWithBounds(field: BaseField) {\n const out: Record<string, any> = { type: 'number' };\n if (typeof field.min === 'number') {out.minimum = field.min;}\n if (typeof field.max === 'number') {out.maximum = field.max;}\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction dateSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'date-time' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction codeSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string' };\n let description = getDescription(field);\n const lang = field?.admin?.language;\n if (typeof lang === 'string' && lang.trim()) {\n description = description ? `${description} (language: ${lang})` : `language: ${lang}`;\n }\n if (description) {out.description = description;}\n return out;\n}\n\nfunction emailSchema(field: BaseField) {\n const out: Record<string, any> = { type: 'string', format: 'email' };\n const description = getDescription(field);\n if (description) {out.description = description;}\n return out;\n}\n\nfunction jsonValueSchema(field: BaseField) {\n // Prefer a provided JSON Schema object\n if (isPlainObject(field.jsonSchema)) {return field.jsonSchema as object;}\n if (isPlainObject(field.schema)) {return field.schema as object;}\n\n // typescriptSchema cannot be executed here; default to object\n return { type: 'object' };\n}\n\nfunction normalizeSelectOptions(field: BaseField): { values: Array<number | string>; valueType: 'number' | 'string' } {\n const raw = field.options || [];\n const values: Array<number | string> = [];\n\n for (const opt of raw) {\n if (typeof opt === 'string' || typeof opt === 'number') {\n values.push(opt);\n } else if (isPlainObject(opt) && ('value' in opt)) {\n const v = (opt as any).value;\n if (typeof v === 'string' || typeof v === 'number') {\n values.push(v);\n }\n }\n }\n\n // Infer primitive type\n const allNumbers = values.length > 0 && values.every((v) => typeof v === 'number');\n const valueType: 'number' | 'string' = allNumbers ? 'number' : 'string';\n return { values, valueType };\n}\n\nfunction supportsHasMany(fieldType: string | undefined): boolean {\n // Out of the box: text, textarea, select support hasMany\n // Others can be arrays only if your config truly sets hasMany; we return boolean based on type here.\n return fieldType === 'text' || fieldType === 'textarea' || fieldType === 'select';\n}\n\nexport function fieldToJsonSchema(\n fieldInput: BaseField & Field,\n opts?: { nameOverride?: string; wrapObject?: boolean },\n): JsonSchema {\n const field = fieldInput || {};\n const name = isString(opts?.nameOverride) && opts?.nameOverride.length ? opts.nameOverride : (field.name || 'value');\n const type = field.type;\n\n let valueSchema: null | Record<string, any> = null;\n\n switch (type) {\n case 'array':\n case 'group': {\n if ('fields' in field && Array.isArray(field.fields)) {\n const properties: Record<string, any> = {}\n const required: string[] = []\n \n const processFields = (fields: any[]) => {\n for (const subField of fields) {\n if (subField.type === 'row' || subField.type === 'collapsible') {\n if (subField.fields) {processFields(subField.fields)}\n continue\n }\n if (!subField.name || subField.name === 'id') {continue}\n\n const subSchema = fieldToJsonSchema(subField, { wrapObject: false })\n if (subSchema && Object.keys(subSchema).length > 0) {\n properties[subField.name] = subSchema\n // OpenAI Strict Mode: All fields must be required\n required.push(subField.name)\n \n // If field is optional in Payload, allow null in schema\n if (!subField.required) {\n // Arrays usually default to empty array [], so we don't make them nullable\n // Groups and other types can be null\n if (subSchema.type !== 'array') {\n if (Array.isArray(subSchema.type)) {\n if (!subSchema.type.includes('null')) {\n subSchema.type.push('null')\n }\n } else if (typeof subSchema.type === 'string' && subSchema.type !== 'null') {\n subSchema.type = [subSchema.type, 'null']\n }\n \n // If enum is present, we must allow null in enum or use anyOf? \n // OpenAI strict mode: \"enum values must be consistent with type\". \n // If type is [string, null], null is a valid value for the type, but if enum is [\"a\"], null is not in enum.\n // valid: { type: [\"string\", \"null\"], enum: [\"a\", null] } \n if (Array.isArray(subSchema.enum) && !subSchema.enum.includes(null)) {\n subSchema.enum.push(null)\n }\n }\n }\n }\n }\n }\n \n processFields(field.fields)\n\n const objSchema = {\n type: 'object',\n additionalProperties: false,\n properties,\n required: required.length ? required : undefined\n }\n\n if (type === 'array') {\n valueSchema = {\n type: 'array',\n items: objSchema\n }\n if (typeof field.maxRows === 'number') {\n valueSchema.maxItems = field.maxRows\n }\n if (typeof field.minRows === 'number') {\n valueSchema.minItems = field.minRows\n }\n } else {\n valueSchema = objSchema\n }\n \n const description = getDescription(field);\n if (description) {valueSchema.description = description;}\n }\n break;\n }\n\n case 'checkbox': {\n valueSchema = { type: 'boolean' };\n const description = getDescription(field);\n if (description) {valueSchema.description = description;}\n break;\n }\n\n case 'code': {\n const base = codeSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'date': {\n const base = dateSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'email': {\n const base = emailSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n\n case 'json': {\n const base = jsonValueSchema(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base as Record<string, any>;\n }\n break;\n }\n\n case 'number': {\n const base = numberWithBounds(field);\n if (field.hasMany) {\n valueSchema = { type: 'array', items: base };\n } else {\n valueSchema = base;\n }\n break;\n }\n case 'select': {\n const { values, valueType } = normalizeSelectOptions(field);\n const baseSingle: Record<string, any> = { type: valueType, enum: values };\n const description = getDescription(field);\n if (description) {baseSingle.description = description;}\n\n if (field.hasMany && supportsHasMany(type)) {\n valueSchema = {\n type: 'array',\n items: { type: valueType, enum: values },\n ...(description ? { description } : {}),\n };\n } else {\n valueSchema = baseSingle;\n }\n break;\n }\n\n case 'text':\n case 'textarea': {\n const base = stringWithDescription(field);\n if (field.hasMany && supportsHasMany(type)) {\n const arr: Record<string, any> = {\n type: 'array',\n items: { type: 'string' },\n };\n if (typeof field.minRows === 'number') {arr.minItems = field.minRows;}\n if (typeof field.maxRows === 'number') {arr.maxItems = field.maxRows;}\n if (base.description) {arr.description = base.description;}\n valueSchema = arr;\n } else {\n valueSchema = base;\n }\n break;\n }\n \n // Explicitly handle organizational types to avoid default breakage if passed directly\n // though usually they are handled by parent recursion in group/array case above.\n // If passed as root, we can't really return a meaningful single-value schema without a wrapper?\n // But let's leave default for them or handle if necessary. \n // For now, if someone passes a 'row' as root, it will fall to default (null).\n\n default: {\n valueSchema = null;\n break;\n }\n }\n\n const wrap = opts?.wrapObject !== false;\n\n if (!wrap) {\n return (valueSchema || {}) as JsonSchema;\n }\n\n if (!valueSchema) {\n return {} as JsonSchema;\n }\n\n const schema: JsonSchema = {\n type: 'object',\n additionalProperties: false,\n properties: {\n [name]: valueSchema,\n },\n required: [name]\n };\n\n return schema;\n}\n"],"names":["isString","s","isPlainObject","o","Array","isArray","getDescription","field","d","admin","description","undefined","stringWithDescription","out","type","numberWithBounds","min","minimum","max","maximum","dateSchema","format","codeSchema","lang","language","trim","emailSchema","jsonValueSchema","jsonSchema","schema","normalizeSelectOptions","raw","options","values","opt","push","v","value","allNumbers","length","every","valueType","supportsHasMany","fieldType","fieldToJsonSchema","fieldInput","opts","name","nameOverride","valueSchema","fields","properties","required","processFields","subField","subSchema","wrapObject","Object","keys","includes","enum","objSchema","additionalProperties","items","maxRows","maxItems","minRows","minItems","base","hasMany","baseSingle","arr","wrap"],"mappings":"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"}
@@ -17,12 +17,14 @@ interface ResolveImageReferencesResult {
17
17
  *
18
18
  * Supports two formats:
19
19
  * - @fieldName - for single upload fields
20
+ * - @collection.fieldName - schema path format (collection prefix is stripped)
20
21
  * - @fieldName:filename.jpg - for specific images in hasMany fields
21
22
  *
22
23
  * @param prompt - The prompt text containing @field references
23
24
  * @param contextData - The document data to resolve field values from
24
25
  * @param req - Payload request object for fetching media
26
+ * @param collectionSlug - Optional collection slug to strip from schema path references
25
27
  * @returns Processed prompt with references removed and array of resolved images
26
28
  */
27
- export declare function resolveImageReferences(prompt: string, contextData: Record<string, unknown>, req: PayloadRequest): Promise<ResolveImageReferencesResult>;
29
+ export declare function resolveImageReferences(prompt: string, contextData: Record<string, unknown>, req: PayloadRequest, collectionSlug?: string): Promise<ResolveImageReferencesResult>;
28
30
  export {};
@@ -1,15 +1,28 @@
1
+ /**
2
+ * Retrieves a nested value from an object using dot-notation path.
3
+ * For example, getNestedValue(obj, 'a.b.c') returns obj.a.b.c
4
+ */ function getNestedValue(obj, path) {
5
+ return path.split('.').reduce((current, key)=>{
6
+ if (current && typeof current === 'object' && key in current) {
7
+ return current[key];
8
+ }
9
+ return undefined;
10
+ }, obj);
11
+ }
1
12
  /**
2
13
  * Parses and resolves image references in prompts.
3
14
  *
4
15
  * Supports two formats:
5
16
  * - @fieldName - for single upload fields
17
+ * - @collection.fieldName - schema path format (collection prefix is stripped)
6
18
  * - @fieldName:filename.jpg - for specific images in hasMany fields
7
19
  *
8
20
  * @param prompt - The prompt text containing @field references
9
21
  * @param contextData - The document data to resolve field values from
10
22
  * @param req - Payload request object for fetching media
23
+ * @param collectionSlug - Optional collection slug to strip from schema path references
11
24
  * @returns Processed prompt with references removed and array of resolved images
12
- */ export async function resolveImageReferences(prompt, contextData, req) {
25
+ */ export async function resolveImageReferences(prompt, contextData, req, collectionSlug) {
13
26
  // Pattern matches: @fieldName or @fieldName:filename.ext (filename can have spaces)
14
27
  // The filename part matches everything up to and including an image extension
15
28
  const pattern = /@([\w.]+)(?::(.+?\.(?:png|jpe?g|webp|gif)))?/gi;
@@ -34,7 +47,13 @@
34
47
  // Resolve each reference
35
48
  for (const ref of references){
36
49
  try {
37
- const fieldValue = contextData[ref.fieldName];
50
+ // Strip collection prefix from schema path if it matches the current collection
51
+ // e.g., "characters.ortho3d.frame" becomes "ortho3d.frame" when collectionSlug is "characters"
52
+ let fieldPath = ref.fieldName;
53
+ if (collectionSlug && fieldPath.startsWith(`${collectionSlug}.`)) {
54
+ fieldPath = fieldPath.slice(collectionSlug.length + 1);
55
+ }
56
+ const fieldValue = getNestedValue(contextData, fieldPath);
38
57
  if (!fieldValue) {
39
58
  req.payload.logger.warn(`Image reference @${ref.fieldName} not found in document context`);
40
59
  continue;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/resolveImageReferences.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\ninterface ImageReference {\n fieldName: string\n filename?: string\n fullMatch: string\n}\n\nexport interface ResolvedImage {\n image: {\n mimeType?: string\n name: string\n thumbnailURL?: string\n type: string\n url: string\n }\n}\n\ninterface ResolveImageReferencesResult {\n images: ResolvedImage[]\n processedPrompt: string\n}\n\n/**\n * Parses and resolves image references in prompts.\n * \n * Supports two formats:\n * - @fieldName - for single upload fields\n * - @fieldName:filename.jpg - for specific images in hasMany fields\n * \n * @param prompt - The prompt text containing @field references\n * @param contextData - The document data to resolve field values from\n * @param req - Payload request object for fetching media\n * @returns Processed prompt with references removed and array of resolved images\n */\nexport async function resolveImageReferences(\n prompt: string,\n contextData: Record<string, unknown>,\n req: PayloadRequest,\n): Promise<ResolveImageReferencesResult> {\n // Pattern matches: @fieldName or @fieldName:filename.ext (filename can have spaces)\n // The filename part matches everything up to and including an image extension\n const pattern = /@([\\w.]+)(?::(.+?\\.(?:png|jpe?g|webp|gif)))?/gi\n const references: ImageReference[] = []\n let match: null | RegExpExecArray\n\n // Extract all image references\n while ((match = pattern.exec(prompt)) !== null) {\n references.push({\n fieldName: match[1],\n filename: match[2],\n fullMatch: match[0],\n })\n }\n\n if (references.length === 0) {\n return { images: [], processedPrompt: prompt }\n }\n\n const resolvedImages: ResolvedImage[] = []\n let processedPrompt = prompt\n\n // Resolve each reference\n for (const ref of references) {\n try {\n const fieldValue = contextData[ref.fieldName]\n\n if (!fieldValue) {\n req.payload.logger.warn(\n `Image reference @${ref.fieldName} not found in document context`,\n )\n continue\n }\n\n // Handle single upload field (value is an ID or object)\n if (!ref.filename) {\n const mediaDoc = await resolveMediaDocument(fieldValue, req)\n if (mediaDoc) {\n resolvedImages.push(formatImageData(mediaDoc))\n }\n }\n // Handle hasMany field with filename\n else {\n const mediaDoc = await resolveMediaFromArray(fieldValue, ref.filename, req)\n if (mediaDoc) {\n resolvedImages.push(formatImageData(mediaDoc))\n }\n }\n\n // Remove the reference from the prompt\n processedPrompt = processedPrompt.replace(ref.fullMatch, '')\n } catch (error) {\n req.payload.logger.error(\n error,\n `Error resolving image reference: ${ref.fullMatch}`,\n )\n }\n }\n\n // Clean up extra whitespace from removed references\n processedPrompt = processedPrompt.replace(/\\s+/g, ' ').trim()\n\n return {\n images: resolvedImages,\n processedPrompt,\n }\n}\n\n/**\n * Resolves a single media document from an ID or populated object\n */\nasync function resolveMediaDocument(\n value: unknown,\n req: PayloadRequest,\n): Promise<null | Record<string, unknown>> {\n // If it's already a populated object with required fields\n if (typeof value === 'object' && value !== null && 'url' in value) {\n return value as Record<string, unknown>\n }\n\n // If it's an ID string, fetch the media document\n if (typeof value === 'string' || typeof value === 'number') {\n try {\n // Try to find which collection this media belongs to\n // First, check the common 'media' collection\n const collections = ['media', 'uploads']\n\n for (const collectionSlug of collections) {\n try {\n const mediaDoc = await req.payload.findByID({\n id: value,\n collection: collectionSlug,\n req,\n })\n if (mediaDoc) {\n return mediaDoc as Record<string, unknown>\n }\n } catch (_ignore) {\n // Continue to next collection\n continue\n }\n }\n } catch (error) {\n req.payload.logger.error(error, 'Error fetching media document')\n }\n }\n\n return null\n}\n\n/**\n * Resolves a specific media document from an array by matching filename\n */\nasync function resolveMediaFromArray(\n arrayValue: unknown,\n filename: string,\n req: PayloadRequest,\n): Promise<null | Record<string, unknown>> {\n if (!Array.isArray(arrayValue)) {\n return null\n }\n\n // Search through array for matching filename\n for (const item of arrayValue) {\n const mediaDoc = await resolveMediaDocument(item, req)\n\n if (mediaDoc && matchesFilename(mediaDoc, filename)) {\n return mediaDoc\n }\n }\n\n return null\n}\n\n/**\n * Checks if a media document matches the given filename\n */\nfunction matchesFilename(mediaDoc: Record<string, unknown>, filename: string): boolean {\n const docFilename = mediaDoc.filename || mediaDoc.name\n\n if (!docFilename) {\n return false\n }\n\n // Case-insensitive match\n return (docFilename as string).toLowerCase() === filename.toLowerCase()\n}\n\n/**\n * Formats media document into the expected image data structure\n */\nfunction formatImageData(mediaDoc: Record<string, unknown>): ResolvedImage {\n return {\n image: {\n name: (mediaDoc.filename || mediaDoc.name || 'unknown') as string,\n type: extractFileExtension((mediaDoc.filename || mediaDoc.name || '') as string),\n mimeType: (mediaDoc.mimeType || mediaDoc.mimetype) as string | undefined,\n thumbnailURL: mediaDoc.thumbnailURL as string | undefined,\n url: mediaDoc.url as string,\n },\n }\n}\n\n/**\n * Extracts file extension from filename\n */\nfunction extractFileExtension(filename: string): string {\n const match = filename.match(/\\.([^.]+)$/)\n return match ? match[1].toLowerCase() : 'unknown'\n}\n"],"names":["resolveImageReferences","prompt","contextData","req","pattern","references","match","exec","push","fieldName","filename","fullMatch","length","images","processedPrompt","resolvedImages","ref","fieldValue","payload","logger","warn","mediaDoc","resolveMediaDocument","formatImageData","resolveMediaFromArray","replace","error","trim","value","collections","collectionSlug","findByID","id","collection","_ignore","arrayValue","Array","isArray","item","matchesFilename","docFilename","name","toLowerCase","image","type","extractFileExtension","mimeType","mimetype","thumbnailURL","url"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/resolveImageReferences.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\ninterface ImageReference {\n fieldName: string\n filename?: string\n fullMatch: string\n}\n\nexport interface ResolvedImage {\n image: {\n mimeType?: string\n name: string\n thumbnailURL?: string\n type: string\n url: string\n }\n}\n\ninterface ResolveImageReferencesResult {\n images: ResolvedImage[]\n processedPrompt: string\n}\n\n/**\n * Retrieves a nested value from an object using dot-notation path.\n * For example, getNestedValue(obj, 'a.b.c') returns obj.a.b.c\n */\nfunction getNestedValue(obj: Record<string, unknown>, path: string): unknown {\n return path.split('.').reduce((current, key) => {\n if (current && typeof current === 'object' && key in current) {\n return (current as Record<string, unknown>)[key]\n }\n return undefined\n }, obj as unknown)\n}\n\n/**\n * Parses and resolves image references in prompts.\n * \n * Supports two formats:\n * - @fieldName - for single upload fields\n * - @collection.fieldName - schema path format (collection prefix is stripped)\n * - @fieldName:filename.jpg - for specific images in hasMany fields\n * \n * @param prompt - The prompt text containing @field references\n * @param contextData - The document data to resolve field values from\n * @param req - Payload request object for fetching media\n * @param collectionSlug - Optional collection slug to strip from schema path references\n * @returns Processed prompt with references removed and array of resolved images\n */\nexport async function resolveImageReferences(\n prompt: string,\n contextData: Record<string, unknown>,\n req: PayloadRequest,\n collectionSlug?: string,\n): Promise<ResolveImageReferencesResult> {\n // Pattern matches: @fieldName or @fieldName:filename.ext (filename can have spaces)\n // The filename part matches everything up to and including an image extension\n const pattern = /@([\\w.]+)(?::(.+?\\.(?:png|jpe?g|webp|gif)))?/gi\n const references: ImageReference[] = []\n let match: null | RegExpExecArray\n\n // Extract all image references\n while ((match = pattern.exec(prompt)) !== null) {\n references.push({\n fieldName: match[1],\n filename: match[2],\n fullMatch: match[0],\n })\n }\n\n if (references.length === 0) {\n return { images: [], processedPrompt: prompt }\n }\n\n const resolvedImages: ResolvedImage[] = []\n let processedPrompt = prompt\n\n // Resolve each reference\n for (const ref of references) {\n try {\n // Strip collection prefix from schema path if it matches the current collection\n // e.g., \"characters.ortho3d.frame\" becomes \"ortho3d.frame\" when collectionSlug is \"characters\"\n let fieldPath = ref.fieldName\n if (collectionSlug && fieldPath.startsWith(`${collectionSlug}.`)) {\n fieldPath = fieldPath.slice(collectionSlug.length + 1)\n }\n\n const fieldValue = getNestedValue(contextData, fieldPath)\n\n if (!fieldValue) {\n req.payload.logger.warn(\n `Image reference @${ref.fieldName} not found in document context`,\n )\n continue\n }\n\n // Handle single upload field (value is an ID or object)\n if (!ref.filename) {\n const mediaDoc = await resolveMediaDocument(fieldValue, req)\n if (mediaDoc) {\n resolvedImages.push(formatImageData(mediaDoc))\n }\n }\n // Handle hasMany field with filename\n else {\n const mediaDoc = await resolveMediaFromArray(fieldValue, ref.filename, req)\n if (mediaDoc) {\n resolvedImages.push(formatImageData(mediaDoc))\n }\n }\n\n // Remove the reference from the prompt\n processedPrompt = processedPrompt.replace(ref.fullMatch, '')\n } catch (error) {\n req.payload.logger.error(\n error,\n `Error resolving image reference: ${ref.fullMatch}`,\n )\n }\n }\n\n // Clean up extra whitespace from removed references\n processedPrompt = processedPrompt.replace(/\\s+/g, ' ').trim()\n\n return {\n images: resolvedImages,\n processedPrompt,\n }\n}\n\n/**\n * Resolves a single media document from an ID or populated object\n */\nasync function resolveMediaDocument(\n value: unknown,\n req: PayloadRequest,\n): Promise<null | Record<string, unknown>> {\n // If it's already a populated object with required fields\n if (typeof value === 'object' && value !== null && 'url' in value) {\n return value as Record<string, unknown>\n }\n\n // If it's an ID string, fetch the media document\n if (typeof value === 'string' || typeof value === 'number') {\n try {\n // Try to find which collection this media belongs to\n // First, check the common 'media' collection\n const collections = ['media', 'uploads']\n\n for (const collectionSlug of collections) {\n try {\n const mediaDoc = await req.payload.findByID({\n id: value,\n collection: collectionSlug,\n req,\n })\n if (mediaDoc) {\n return mediaDoc as Record<string, unknown>\n }\n } catch (_ignore) {\n // Continue to next collection\n continue\n }\n }\n } catch (error) {\n req.payload.logger.error(error, 'Error fetching media document')\n }\n }\n\n return null\n}\n\n/**\n * Resolves a specific media document from an array by matching filename\n */\nasync function resolveMediaFromArray(\n arrayValue: unknown,\n filename: string,\n req: PayloadRequest,\n): Promise<null | Record<string, unknown>> {\n if (!Array.isArray(arrayValue)) {\n return null\n }\n\n // Search through array for matching filename\n for (const item of arrayValue) {\n const mediaDoc = await resolveMediaDocument(item, req)\n\n if (mediaDoc && matchesFilename(mediaDoc, filename)) {\n return mediaDoc\n }\n }\n\n return null\n}\n\n/**\n * Checks if a media document matches the given filename\n */\nfunction matchesFilename(mediaDoc: Record<string, unknown>, filename: string): boolean {\n const docFilename = mediaDoc.filename || mediaDoc.name\n\n if (!docFilename) {\n return false\n }\n\n // Case-insensitive match\n return (docFilename as string).toLowerCase() === filename.toLowerCase()\n}\n\n/**\n * Formats media document into the expected image data structure\n */\nfunction formatImageData(mediaDoc: Record<string, unknown>): ResolvedImage {\n return {\n image: {\n name: (mediaDoc.filename || mediaDoc.name || 'unknown') as string,\n type: extractFileExtension((mediaDoc.filename || mediaDoc.name || '') as string),\n mimeType: (mediaDoc.mimeType || mediaDoc.mimetype) as string | undefined,\n thumbnailURL: mediaDoc.thumbnailURL as string | undefined,\n url: mediaDoc.url as string,\n },\n }\n}\n\n/**\n * Extracts file extension from filename\n */\nfunction extractFileExtension(filename: string): string {\n const match = filename.match(/\\.([^.]+)$/)\n return match ? match[1].toLowerCase() : 'unknown'\n}\n"],"names":["getNestedValue","obj","path","split","reduce","current","key","undefined","resolveImageReferences","prompt","contextData","req","collectionSlug","pattern","references","match","exec","push","fieldName","filename","fullMatch","length","images","processedPrompt","resolvedImages","ref","fieldPath","startsWith","slice","fieldValue","payload","logger","warn","mediaDoc","resolveMediaDocument","formatImageData","resolveMediaFromArray","replace","error","trim","value","collections","findByID","id","collection","_ignore","arrayValue","Array","isArray","item","matchesFilename","docFilename","name","toLowerCase","image","type","extractFileExtension","mimeType","mimetype","thumbnailURL","url"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { PayloadRequest } from 'payload';
2
+ interface SeedPropertiesArgs {
3
+ enabledCollections: string[];
4
+ req: PayloadRequest;
5
+ }
6
+ export declare const seedProperties: ({ enabledCollections, req }: SeedPropertiesArgs) => Promise<void>;
7
+ export {};
@@ -0,0 +1,100 @@
1
+ import { PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js';
2
+ import { updateFieldsConfig } from './updateFieldsConfig.js';
3
+ export const seedProperties = async ({ enabledCollections, req })=>{
4
+ const { payload } = req;
5
+ if (!enabledCollections || enabledCollections.length === 0) {
6
+ return;
7
+ }
8
+ // Get all collections from payload config
9
+ const allCollections = payload.config.collections;
10
+ for (const collectionSlug of enabledCollections){
11
+ const collectionConfig = allCollections.find((c)=>c.slug === collectionSlug);
12
+ if (!collectionConfig) {
13
+ continue;
14
+ }
15
+ // Traverse the collection config effectively using updateFieldsConfig
16
+ // Use the side-effect of getting schemaPathMap from it
17
+ const { schemaPathMap } = updateFieldsConfig(collectionConfig);
18
+ for (const [schemaPath, fieldInfo] of Object.entries(schemaPathMap)){
19
+ const { type, custom, relationTo } = fieldInfo;
20
+ // Check if instruction already exists
21
+ const existingInstruction = await payload.find({
22
+ collection: PLUGIN_INSTRUCTIONS_TABLE,
23
+ depth: 0,
24
+ limit: 1,
25
+ overrideAccess: true,
26
+ where: {
27
+ 'schema-path': {
28
+ equals: schemaPath
29
+ }
30
+ }
31
+ });
32
+ if (existingInstruction.totalDocs > 0) {
33
+ // If developer has provided custom prompts in the schema, update the existing record
34
+ // but only if the values have actually changed.
35
+ if (custom?.ai?.prompt || custom?.ai?.system) {
36
+ const doc = existingInstruction.docs[0];
37
+ const currentPrompt = doc.prompt;
38
+ const currentSystem = doc.system;
39
+ let needsUpdate = false;
40
+ const updateData = {};
41
+ if (custom?.ai?.prompt && custom.ai.prompt !== currentPrompt) {
42
+ updateData.prompt = custom.ai.prompt;
43
+ needsUpdate = true;
44
+ }
45
+ if (custom?.ai?.system && custom.ai.system !== currentSystem) {
46
+ updateData.system = custom.ai.system;
47
+ needsUpdate = true;
48
+ }
49
+ if (needsUpdate) {
50
+ try {
51
+ await payload.update({
52
+ id: doc.id,
53
+ collection: PLUGIN_INSTRUCTIONS_TABLE,
54
+ data: updateData,
55
+ overrideAccess: true
56
+ });
57
+ } catch (error) {
58
+ payload.logger.error(`Failed to update instruction for ${schemaPath}: ${error}`);
59
+ }
60
+ }
61
+ }
62
+ continue;
63
+ }
64
+ // Use custom prompts if provided, otherwise leave empty
65
+ const prompt = custom?.ai?.prompt || '';
66
+ const system = custom?.ai?.system || '';
67
+ // Determine model-id based on field type
68
+ let modelId = 'text';
69
+ if (type === 'richText') {
70
+ modelId = 'richtext';
71
+ }
72
+ if (type === 'upload') {
73
+ modelId = 'image';
74
+ } // defaulting to image generation for uploads
75
+ if (type === 'array') {
76
+ modelId = 'array';
77
+ }
78
+ // Create new instruction
79
+ try {
80
+ await payload.create({
81
+ collection: PLUGIN_INSTRUCTIONS_TABLE,
82
+ data: {
83
+ disabled: false,
84
+ 'field-type': type,
85
+ 'model-id': modelId,
86
+ prompt,
87
+ 'relation-to': relationTo,
88
+ 'schema-path': schemaPath,
89
+ system
90
+ },
91
+ overrideAccess: true
92
+ });
93
+ } catch (error) {
94
+ payload.logger.error(`Failed to seed instruction for ${schemaPath}: ${error}`);
95
+ }
96
+ }
97
+ }
98
+ };
99
+
100
+ //# sourceMappingURL=seedProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/seedProperties.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\nimport { updateFieldsConfig } from './updateFieldsConfig.js'\n\ninterface SeedPropertiesArgs {\n enabledCollections: string[]\n req: PayloadRequest\n}\n\nexport const seedProperties = async ({ enabledCollections, req }: SeedPropertiesArgs): Promise<void> => {\n const { payload } = req\n\n if (!enabledCollections || enabledCollections.length === 0) {\n return\n }\n\n // Get all collections from payload config\n const allCollections = payload.config.collections\n\n for (const collectionSlug of enabledCollections) {\n const collectionConfig = allCollections.find((c) => c.slug === collectionSlug)\n if (!collectionConfig) {\n continue\n }\n\n // Traverse the collection config effectively using updateFieldsConfig\n // Use the side-effect of getting schemaPathMap from it\n const { schemaPathMap } = updateFieldsConfig(collectionConfig)\n\n for (const [schemaPath, fieldInfo] of Object.entries(schemaPathMap)) {\n const { type, custom, relationTo } = fieldInfo as {\n custom?: { ai?: { prompt?: string; system?: string } }\n relationTo?: string\n type: string\n }\n\n // Check if instruction already exists\n const existingInstruction = await payload.find({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n depth: 0,\n limit: 1,\n overrideAccess: true,\n where: {\n 'schema-path': {\n equals: schemaPath,\n },\n },\n })\n\n if (existingInstruction.totalDocs > 0) {\n // If developer has provided custom prompts in the schema, update the existing record\n // but only if the values have actually changed.\n if (custom?.ai?.prompt || custom?.ai?.system) {\n const doc = existingInstruction.docs[0] as any\n const currentPrompt = doc.prompt\n const currentSystem = doc.system\n\n let needsUpdate = false\n const updateData: any = {}\n\n if (custom?.ai?.prompt && custom.ai.prompt !== currentPrompt) {\n updateData.prompt = custom.ai.prompt\n needsUpdate = true\n }\n if (custom?.ai?.system && custom.ai.system !== currentSystem) {\n updateData.system = custom.ai.system\n needsUpdate = true\n }\n\n if (needsUpdate) {\n try {\n await payload.update({\n id: doc.id,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n data: updateData,\n overrideAccess: true,\n })\n } catch (error) {\n payload.logger.error(`Failed to update instruction for ${schemaPath}: ${error}`)\n }\n }\n }\n continue\n }\n\n // Use custom prompts if provided, otherwise leave empty\n const prompt = custom?.ai?.prompt || ''\n const system = custom?.ai?.system || ''\n\n // Determine model-id based on field type\n let modelId = 'text'\n if (type === 'richText') {\n modelId = 'richtext'\n }\n if (type === 'upload') {\n modelId = 'image'\n } // defaulting to image generation for uploads\n if (type === 'array') {\n modelId = 'array'\n }\n\n // Create new instruction\n try {\n await payload.create({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n data: {\n disabled: false,\n 'field-type': type,\n 'model-id': modelId,\n prompt,\n 'relation-to': relationTo,\n 'schema-path': schemaPath,\n system,\n },\n overrideAccess: true,\n })\n } catch (error) {\n payload.logger.error(`Failed to seed instruction for ${schemaPath}: ${error}`)\n }\n }\n }\n}\n"],"names":["PLUGIN_INSTRUCTIONS_TABLE","updateFieldsConfig","seedProperties","enabledCollections","req","payload","length","allCollections","config","collections","collectionSlug","collectionConfig","find","c","slug","schemaPathMap","schemaPath","fieldInfo","Object","entries","type","custom","relationTo","existingInstruction","collection","depth","limit","overrideAccess","where","equals","totalDocs","ai","prompt","system","doc","docs","currentPrompt","currentSystem","needsUpdate","updateData","update","id","data","error","logger","modelId","create","disabled"],"mappings":"AAEA,SAASA,yBAAyB,QAAQ,iBAAgB;AAC1D,SAASC,kBAAkB,QAAQ,0BAAyB;AAO5D,OAAO,MAAMC,iBAAiB,OAAO,EAAEC,kBAAkB,EAAEC,GAAG,EAAsB;IAClF,MAAM,EAAEC,OAAO,EAAE,GAAGD;IAEpB,IAAI,CAACD,sBAAsBA,mBAAmBG,MAAM,KAAK,GAAG;QAC1D;IACF;IAEA,0CAA0C;IAC1C,MAAMC,iBAAiBF,QAAQG,MAAM,CAACC,WAAW;IAEjD,KAAK,MAAMC,kBAAkBP,mBAAoB;QAC/C,MAAMQ,mBAAmBJ,eAAeK,IAAI,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKJ;QAC/D,IAAI,CAACC,kBAAkB;YACrB;QACF;QAEA,sEAAsE;QACtE,uDAAuD;QACvD,MAAM,EAAEI,aAAa,EAAE,GAAGd,mBAAmBU;QAE7C,KAAK,MAAM,CAACK,YAAYC,UAAU,IAAIC,OAAOC,OAAO,CAACJ,eAAgB;YACnE,MAAM,EAAEK,IAAI,EAAEC,MAAM,EAAEC,UAAU,EAAE,GAAGL;YAMrC,sCAAsC;YACtC,MAAMM,sBAAsB,MAAMlB,QAAQO,IAAI,CAAC;gBAC7CY,YAAYxB;gBACZyB,OAAO;gBACPC,OAAO;gBACPC,gBAAgB;gBAChBC,OAAO;oBACL,eAAe;wBACbC,QAAQb;oBACV;gBACF;YACF;YAEA,IAAIO,oBAAoBO,SAAS,GAAG,GAAG;gBACrC,qFAAqF;gBACrF,gDAAgD;gBAChD,IAAIT,QAAQU,IAAIC,UAAUX,QAAQU,IAAIE,QAAQ;oBAC5C,MAAMC,MAAMX,oBAAoBY,IAAI,CAAC,EAAE;oBACvC,MAAMC,gBAAgBF,IAAIF,MAAM;oBAChC,MAAMK,gBAAgBH,IAAID,MAAM;oBAEhC,IAAIK,cAAc;oBAClB,MAAMC,aAAkB,CAAC;oBAEzB,IAAIlB,QAAQU,IAAIC,UAAUX,OAAOU,EAAE,CAACC,MAAM,KAAKI,eAAe;wBAC5DG,WAAWP,MAAM,GAAGX,OAAOU,EAAE,CAACC,MAAM;wBACpCM,cAAc;oBAChB;oBACA,IAAIjB,QAAQU,IAAIE,UAAUZ,OAAOU,EAAE,CAACE,MAAM,KAAKI,eAAe;wBAC5DE,WAAWN,MAAM,GAAGZ,OAAOU,EAAE,CAACE,MAAM;wBACpCK,cAAc;oBAChB;oBAEA,IAAIA,aAAa;wBACf,IAAI;4BACF,MAAMjC,QAAQmC,MAAM,CAAC;gCACnBC,IAAIP,IAAIO,EAAE;gCACVjB,YAAYxB;gCACZ0C,MAAMH;gCACNZ,gBAAgB;4BAClB;wBACF,EAAE,OAAOgB,OAAO;4BACdtC,QAAQuC,MAAM,CAACD,KAAK,CAAC,CAAC,iCAAiC,EAAE3B,WAAW,EAAE,EAAE2B,MAAM,CAAC;wBACjF;oBACF;gBACF;gBACA;YACF;YAEA,wDAAwD;YACxD,MAAMX,SAASX,QAAQU,IAAIC,UAAU;YACrC,MAAMC,SAASZ,QAAQU,IAAIE,UAAU;YAErC,yCAAyC;YACzC,IAAIY,UAAU;YACd,IAAIzB,SAAS,YAAY;gBACvByB,UAAU;YACZ;YACA,IAAIzB,SAAS,UAAU;gBACrByB,UAAU;YACZ,EAAE,6CAA6C;YAC/C,IAAIzB,SAAS,SAAS;gBACpByB,UAAU;YACZ;YAEA,yBAAyB;YACzB,IAAI;gBACF,MAAMxC,QAAQyC,MAAM,CAAC;oBACnBtB,YAAYxB;oBACZ0C,MAAM;wBACJK,UAAU;wBACV,cAAc3B;wBACd,YAAYyB;wBACZb;wBACA,eAAeV;wBACf,eAAeN;wBACfiB;oBACF;oBACAN,gBAAgB;gBAClB;YACF,EAAE,OAAOgB,OAAO;gBACdtC,QAAQuC,MAAM,CAACD,KAAK,CAAC,CAAC,+BAA+B,EAAE3B,WAAW,EAAE,EAAE2B,MAAM,CAAC;YAC/E;QACF;IACF;AACF,EAAC"}
@@ -1,15 +1,88 @@
1
+ const sanitizeLexicalState = (state)=>{
2
+ // 1. Ensure root exists and is valid
3
+ if (!state || typeof state !== 'object') {
4
+ return null;
5
+ }
6
+ // If no root, or root is not an object, it's invalid
7
+ if (!state.root || typeof state.root !== 'object') {
8
+ return null;
9
+ }
10
+ // 2. Clone to avoid mutation
11
+ const cleanState = JSON.parse(JSON.stringify(state));
12
+ // 3. Ensure root has required props
13
+ cleanState.root.type = 'root';
14
+ cleanState.root.format = cleanState.root.format || 'left';
15
+ cleanState.root.indent = cleanState.root.indent || 0;
16
+ cleanState.root.version = cleanState.root.version || 1;
17
+ // 4. Recursive sanitizer for children
18
+ const sanitizeNode = (node)=>{
19
+ if (!node || typeof node !== 'object') {
20
+ return null;
21
+ }
22
+ // Must have a type. If streaming incomplete node (type is missing/empty), discard it.
23
+ if (!node.type || typeof node.type !== 'string') {
24
+ return null;
25
+ }
26
+ // Default version if missing
27
+ node.version = node.version || 1;
28
+ // If node has children, sanitize them
29
+ if (Array.isArray(node.children)) {
30
+ node.children = node.children.map(sanitizeNode).filter((child)=>child !== null);
31
+ } else {
32
+ // Ensure children is at least an empty array if it's supposed to be there?
33
+ // Actually lots of leaf nodes don't have children.
34
+ // But Root, Paragraph, etc do.
35
+ // Let's safe-guard standard ElementNodes:
36
+ if ([
37
+ 'heading',
38
+ 'link',
39
+ 'list',
40
+ 'listitem',
41
+ 'paragraph',
42
+ 'quote',
43
+ 'root'
44
+ ].includes(node.type)) {
45
+ node.children = node.children || [];
46
+ }
47
+ }
48
+ // Specific node fixes
49
+ if (node.type === 'text') {
50
+ // Text nodes must have text prop
51
+ if (typeof node.text !== 'string') {
52
+ // If text is missing, it might be incomplete.
53
+ // We can either discard or default to empty string.
54
+ // For streaming, empty string is safer than discarding early if we want to show cursor?
55
+ node.text = node.text || '';
56
+ }
57
+ node.mode = node.mode ?? 0;
58
+ node.style = node.style || '';
59
+ node.detail = node.detail ?? 0;
60
+ }
61
+ return node;
62
+ };
63
+ // 5. Sanitize root's children
64
+ if (Array.isArray(cleanState.root.children)) {
65
+ cleanState.root.children = cleanState.root.children.map(sanitizeNode).filter((child)=>child !== null);
66
+ } else {
67
+ cleanState.root.children = [];
68
+ }
69
+ return cleanState;
70
+ };
1
71
  export const setSafeLexicalState = (state, editorInstance)=>{
2
72
  try {
3
- const editorState = editorInstance.parseEditorState(state);
73
+ const validState = sanitizeLexicalState(state);
74
+ if (!validState) {
75
+ return;
76
+ }
77
+ const editorState = editorInstance.parseEditorState(validState);
4
78
  if (editorState.isEmpty()) {
5
79
  return;
6
80
  }
7
81
  editorInstance.setEditorState(editorState);
8
- } catch (error) {
9
- console.error('Error setting editor state: ', {
10
- error,
11
- state
12
- });
82
+ } catch (_error) {
83
+ // Silently catch errors during streaming to avoid console noise.
84
+ // Lexical's parseEditorState is very strict and will throw if the
85
+ // object structure is even slightly incomplete during the stream.
13
86
  }
14
87
  };
15
88
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/setSafeLexicalState.ts"],"sourcesContent":["import type { LexicalEditor } from 'lexical'\n\ntype EditorAction = 'replace' | 'update'\n\nexport const setSafeLexicalState = (\n state: unknown,\n editorInstance: LexicalEditor,\n // action: EditorAction = 'replace',\n) => {\n try {\n const editorState = editorInstance.parseEditorState(state as any)\n if (editorState.isEmpty()) {\n return\n }\n\n editorInstance.setEditorState(editorState)\n } catch (error) {\n console.error('Error setting editor state: ', { error, state })\n }\n}\n"],"names":["setSafeLexicalState","state","editorInstance","editorState","parseEditorState","isEmpty","setEditorState","error","console"],"mappings":"AAIA,OAAO,MAAMA,sBAAsB,CACjCC,OACAC;IAGA,IAAI;QACF,MAAMC,cAAcD,eAAeE,gBAAgB,CAACH;QACpD,IAAIE,YAAYE,OAAO,IAAI;YACzB;QACF;QAEAH,eAAeI,cAAc,CAACH;IAChC,EAAE,OAAOI,OAAO;QACdC,QAAQD,KAAK,CAAC,gCAAgC;YAAEA;YAAON;QAAM;IAC/D;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/utilities/setSafeLexicalState.ts"],"sourcesContent":["import type { LexicalEditor } from 'lexical'\n\nconst sanitizeLexicalState = (state: any): any => {\n // 1. Ensure root exists and is valid\n if (!state || typeof state !== 'object') {\n return null\n }\n\n // If no root, or root is not an object, it's invalid\n if (!state.root || typeof state.root !== 'object') {\n return null\n }\n\n // 2. Clone to avoid mutation\n const cleanState = JSON.parse(JSON.stringify(state))\n\n // 3. Ensure root has required props\n cleanState.root.type = 'root'\n cleanState.root.format = cleanState.root.format || 'left'\n cleanState.root.indent = cleanState.root.indent || 0\n cleanState.root.version = cleanState.root.version || 1\n\n // 4. Recursive sanitizer for children\n const sanitizeNode = (node: any): any => {\n if (!node || typeof node !== 'object') {\n return null\n }\n\n // Must have a type. If streaming incomplete node (type is missing/empty), discard it.\n if (!node.type || typeof node.type !== 'string') {\n return null\n }\n\n // Default version if missing\n node.version = node.version || 1\n\n // If node has children, sanitize them\n if (Array.isArray(node.children)) {\n node.children = node.children\n .map(sanitizeNode)\n .filter((child: any) => child !== null)\n } else {\n // Ensure children is at least an empty array if it's supposed to be there? \n // Actually lots of leaf nodes don't have children. \n // But Root, Paragraph, etc do. \n // Let's safe-guard standard ElementNodes:\n if (['heading', 'link', 'list', 'listitem', 'paragraph', 'quote', 'root'].includes(node.type)) {\n node.children = node.children || []\n }\n }\n\n // Specific node fixes\n if (node.type === 'text') {\n // Text nodes must have text prop\n if (typeof node.text !== 'string') {\n // If text is missing, it might be incomplete. \n // We can either discard or default to empty string.\n // For streaming, empty string is safer than discarding early if we want to show cursor?\n node.text = node.text || ''\n }\n node.mode = node.mode ?? 0\n node.style = node.style || ''\n node.detail = node.detail ?? 0\n }\n\n return node\n }\n\n // 5. Sanitize root's children\n if (Array.isArray(cleanState.root.children)) {\n cleanState.root.children = cleanState.root.children\n .map(sanitizeNode)\n .filter((child: any) => child !== null)\n } else {\n cleanState.root.children = []\n }\n\n return cleanState\n}\n\nexport const setSafeLexicalState = (state: unknown, editorInstance: LexicalEditor) => {\n try {\n const validState = sanitizeLexicalState(state)\n \n if (!validState) {\n return\n }\n\n const editorState = editorInstance.parseEditorState(validState)\n if (editorState.isEmpty()) {\n return\n }\n\n editorInstance.setEditorState(editorState)\n } catch (_error) {\n // Silently catch errors during streaming to avoid console noise.\n // Lexical's parseEditorState is very strict and will throw if the\n // object structure is even slightly incomplete during the stream.\n }\n}\n\n"],"names":["sanitizeLexicalState","state","root","cleanState","JSON","parse","stringify","type","format","indent","version","sanitizeNode","node","Array","isArray","children","map","filter","child","includes","text","mode","style","detail","setSafeLexicalState","editorInstance","validState","editorState","parseEditorState","isEmpty","setEditorState","_error"],"mappings":"AAEA,MAAMA,uBAAuB,CAACC;IAC5B,qCAAqC;IACrC,IAAI,CAACA,SAAS,OAAOA,UAAU,UAAU;QACvC,OAAO;IACT;IAEA,qDAAqD;IACrD,IAAI,CAACA,MAAMC,IAAI,IAAI,OAAOD,MAAMC,IAAI,KAAK,UAAU;QACjD,OAAO;IACT;IAEA,6BAA6B;IAC7B,MAAMC,aAAaC,KAAKC,KAAK,CAACD,KAAKE,SAAS,CAACL;IAE7C,oCAAoC;IACpCE,WAAWD,IAAI,CAACK,IAAI,GAAG;IACvBJ,WAAWD,IAAI,CAACM,MAAM,GAAGL,WAAWD,IAAI,CAACM,MAAM,IAAI;IACnDL,WAAWD,IAAI,CAACO,MAAM,GAAGN,WAAWD,IAAI,CAACO,MAAM,IAAI;IACnDN,WAAWD,IAAI,CAACQ,OAAO,GAAGP,WAAWD,IAAI,CAACQ,OAAO,IAAI;IAErD,sCAAsC;IACtC,MAAMC,eAAe,CAACC;QACpB,IAAI,CAACA,QAAQ,OAAOA,SAAS,UAAU;YACrC,OAAO;QACT;QAEA,sFAAsF;QACtF,IAAI,CAACA,KAAKL,IAAI,IAAI,OAAOK,KAAKL,IAAI,KAAK,UAAU;YAC/C,OAAO;QACT;QAEA,6BAA6B;QAC7BK,KAAKF,OAAO,GAAGE,KAAKF,OAAO,IAAI;QAE/B,sCAAsC;QACtC,IAAIG,MAAMC,OAAO,CAACF,KAAKG,QAAQ,GAAG;YAChCH,KAAKG,QAAQ,GAAGH,KAAKG,QAAQ,CAC1BC,GAAG,CAACL,cACJM,MAAM,CAAC,CAACC,QAAeA,UAAU;QACtC,OAAO;YACL,4EAA4E;YAC5E,oDAAoD;YACpD,gCAAgC;YAChC,0CAA0C;YAC1C,IAAI;gBAAC;gBAAW;gBAAQ;gBAAQ;gBAAY;gBAAa;gBAAS;aAAO,CAACC,QAAQ,CAACP,KAAKL,IAAI,GAAG;gBAC7FK,KAAKG,QAAQ,GAAGH,KAAKG,QAAQ,IAAI,EAAE;YACrC;QACF;QAEA,sBAAsB;QACtB,IAAIH,KAAKL,IAAI,KAAK,QAAQ;YACxB,iCAAiC;YACjC,IAAI,OAAOK,KAAKQ,IAAI,KAAK,UAAU;gBACjC,+CAA+C;gBAC/C,oDAAoD;gBACpD,wFAAwF;gBACxFR,KAAKQ,IAAI,GAAGR,KAAKQ,IAAI,IAAI;YAC3B;YACAR,KAAKS,IAAI,GAAGT,KAAKS,IAAI,IAAI;YACzBT,KAAKU,KAAK,GAAGV,KAAKU,KAAK,IAAI;YAC3BV,KAAKW,MAAM,GAAGX,KAAKW,MAAM,IAAI;QAC/B;QAEA,OAAOX;IACT;IAEA,8BAA8B;IAC9B,IAAIC,MAAMC,OAAO,CAACX,WAAWD,IAAI,CAACa,QAAQ,GAAG;QAC3CZ,WAAWD,IAAI,CAACa,QAAQ,GAAGZ,WAAWD,IAAI,CAACa,QAAQ,CAChDC,GAAG,CAACL,cACJM,MAAM,CAAC,CAACC,QAAeA,UAAU;IACtC,OAAO;QACLf,WAAWD,IAAI,CAACa,QAAQ,GAAG,EAAE;IAC/B;IAEA,OAAOZ;AACT;AAEA,OAAO,MAAMqB,sBAAsB,CAACvB,OAAgBwB;IAClD,IAAI;QACF,MAAMC,aAAa1B,qBAAqBC;QAExC,IAAI,CAACyB,YAAY;YACf;QACF;QAEA,MAAMC,cAAcF,eAAeG,gBAAgB,CAACF;QACpD,IAAIC,YAAYE,OAAO,IAAI;YACzB;QACF;QAEAJ,eAAeK,cAAc,CAACH;IAChC,EAAE,OAAOI,QAAQ;IACf,iEAAiE;IACjE,kEAAkE;IAClE,kEAAkE;IACpE;AACF,EAAC"}
@@ -1,6 +1,6 @@
1
1
  import type { CollectionConfig, GlobalConfig } from 'payload';
2
2
  interface UpdateFieldsConfig {
3
- schemaPathMap: Record<string, string>;
3
+ schemaPathMap: Record<string, any>;
4
4
  updatedCollectionConfig: CollectionConfig | GlobalConfig;
5
5
  }
6
6
  export declare const updateFieldsConfig: (collectionConfig: CollectionConfig | GlobalConfig) => UpdateFieldsConfig;
@@ -1,7 +1,7 @@
1
1
  export const updateFieldsConfig = (collectionConfig)=>{
2
2
  let schemaPathMap = {};
3
3
  function updateField(field, parentPath = '') {
4
- const currentPath = parentPath ? `${parentPath}.${field.name}` : field.name;
4
+ const currentPath = field.name ? parentPath ? `${parentPath}.${field.name}` : field.name : parentPath;
5
5
  const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`;
6
6
  // Disabled fields/ field types
7
7
  if (field.admin?.disabled || field.admin?.readOnly || field.admin?.hidden || field.type === 'row') {
@@ -11,6 +11,7 @@ export const updateFieldsConfig = (collectionConfig)=>{
11
11
  // This is done due to save extra API call to get instructions when Field components are loaded in admin
12
12
  // Doing is will only call instructions data when user clicks on settings
13
13
  if ([
14
+ 'array',
14
15
  'richText',
15
16
  'text',
16
17
  'textarea',
@@ -20,13 +21,16 @@ export const updateFieldsConfig = (collectionConfig)=>{
20
21
  ...schemaPathMap,
21
22
  [currentSchemaPath]: {
22
23
  type: field.type,
24
+ custom: field.custom,
23
25
  label: field.label || field.name,
24
26
  relationTo: field.relationTo
25
27
  }
26
28
  };
27
29
  }
28
30
  // Inject AI actions, richText is not included here as it has to be explicitly defined by user
31
+ // Array fields also get AI injection for bulk generation
29
32
  if ([
33
+ 'array',
30
34
  'text',
31
35
  'textarea',
32
36
  'upload'
@@ -39,6 +43,9 @@ export const updateFieldsConfig = (collectionConfig)=>{
39
43
  // by overriding Description. If you need both, consider composing your own wrapper.
40
44
  customField = {};
41
45
  }
46
+ // Array fields use ArrayComposeField (always visible) since they don't have focus events
47
+ // Other fields use ComposeField with focus-dependent visibility
48
+ const componentPath = field.type === 'array' ? '@ai-stack/payloadcms/fields#ArrayComposeField' : '@ai-stack/payloadcms/fields#ComposeField';
42
49
  return {
43
50
  ...field,
44
51
  admin: {
@@ -49,7 +56,7 @@ export const updateFieldsConfig = (collectionConfig)=>{
49
56
  clientProps: {
50
57
  schemaPath: currentSchemaPath
51
58
  },
52
- path: '@ai-stack/payloadcms/fields#ComposeField'
59
+ path: componentPath
53
60
  },
54
61
  ...customField
55
62
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, string>\n updatedCollectionConfig: CollectionConfig | GlobalConfig\n}\n\nexport const updateFieldsConfig = (collectionConfig: CollectionConfig | GlobalConfig): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n function updateField(field: any, parentPath = ''): any {\n const currentPath = parentPath ? `${parentPath}.${field.name}` : field.name\n const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`\n\n // Disabled fields/ field types\n if (\n field.admin?.disabled ||\n field.admin?.readOnly ||\n field.admin?.hidden ||\n field.type === 'row'\n ) {\n return field\n }\n\n // Map field path for global fieldInstructionsMap to load related instructions\n // This is done due to save extra API call to get instructions when Field components are loaded in admin\n // Doing is will only call instructions data when user clicks on settings\n if (['richText', 'text', 'textarea', 'upload'].includes(field.type)) {\n schemaPathMap = {\n ...schemaPathMap,\n [currentSchemaPath]: {\n type: field.type,\n label: field.label || field.name,\n relationTo: field.relationTo,\n },\n }\n }\n\n // Inject AI actions, richText is not included here as it has to be explicitly defined by user\n if (['text', 'textarea', 'upload'].includes(field.type)) {\n let customField = {}\n\n // Custom fields don't fully adhere to the Payload schema, making it difficult to\n // determine which components support injecting ComposeField as a Description.\n if (field.admin?.components?.Field || field.admin?.components?.Description) {\n // TODO: If a field already provides its own Description, we still inject our ComposeField\n // by overriding Description. If you need both, consider composing your own wrapper.\n customField = {}\n }\n\n return {\n ...field,\n admin: {\n ...field.admin,\n components: {\n ...(field.admin?.components || {}),\n Description: {\n clientProps: {\n schemaPath: currentSchemaPath,\n },\n path: '@ai-stack/payloadcms/fields#ComposeField',\n },\n ...customField,\n },\n },\n }\n }\n\n if (field.fields) {\n return {\n ...field,\n fields: field.fields.map((subField: any) => updateField(subField, currentPath)),\n }\n }\n\n if (field.tabs) {\n return {\n ...field,\n tabs: field.tabs.map((tab: any) => {\n return {\n ...tab,\n // Tabs are a UI construct and should not add to the schema path\n fields: (tab.fields || []).map((subField: any) => updateField(subField, parentPath)),\n }\n }),\n }\n }\n\n if (field.blocks) {\n return {\n ...field,\n blocks: field.blocks.map((block: any) => ({\n ...block,\n fields: block.fields.map((subField: any) =>\n updateField(subField, `${currentPath}.${block.slug}`),\n ),\n })),\n }\n }\n\n return field\n }\n\n const updatedCollectionConfig = {\n ...collectionConfig,\n fields: collectionConfig.fields.map((field) => updateField(field)),\n }\n\n return {\n schemaPathMap,\n updatedCollectionConfig,\n }\n}\n"],"names":["updateFieldsConfig","collectionConfig","schemaPathMap","updateField","field","parentPath","currentPath","name","currentSchemaPath","slug","admin","disabled","readOnly","hidden","type","includes","label","relationTo","customField","components","Field","Description","clientProps","schemaPath","path","fields","map","subField","tabs","tab","blocks","block","updatedCollectionConfig"],"mappings":"AAOA,OAAO,MAAMA,qBAAqB,CAACC;IACjC,IAAIC,gBAAgB,CAAC;IAErB,SAASC,YAAYC,KAAU,EAAEC,aAAa,EAAE;QAC9C,MAAMC,cAAcD,aAAa,CAAC,EAAEA,WAAW,CAAC,EAAED,MAAMG,IAAI,CAAC,CAAC,GAAGH,MAAMG,IAAI;QAC3E,MAAMC,oBAAoB,CAAC,EAAEP,iBAAiBQ,IAAI,CAAC,CAAC,EAAEH,YAAY,CAAC;QAEnE,+BAA+B;QAC/B,IACEF,MAAMM,KAAK,EAAEC,YACbP,MAAMM,KAAK,EAAEE,YACbR,MAAMM,KAAK,EAAEG,UACbT,MAAMU,IAAI,KAAK,OACf;YACA,OAAOV;QACT;QAEA,8EAA8E;QAC9E,wGAAwG;QACxG,yEAAyE;QACzE,IAAI;YAAC;YAAY;YAAQ;YAAY;SAAS,CAACW,QAAQ,CAACX,MAAMU,IAAI,GAAG;YACnEZ,gBAAgB;gBACd,GAAGA,aAAa;gBAChB,CAACM,kBAAkB,EAAE;oBACnBM,MAAMV,MAAMU,IAAI;oBAChBE,OAAOZ,MAAMY,KAAK,IAAIZ,MAAMG,IAAI;oBAChCU,YAAYb,MAAMa,UAAU;gBAC9B;YACF;QACF;QAEA,8FAA8F;QAC9F,IAAI;YAAC;YAAQ;YAAY;SAAS,CAACF,QAAQ,CAACX,MAAMU,IAAI,GAAG;YACvD,IAAII,cAAc,CAAC;YAEnB,iFAAiF;YACjF,8EAA8E;YAC9E,IAAId,MAAMM,KAAK,EAAES,YAAYC,SAAShB,MAAMM,KAAK,EAAES,YAAYE,aAAa;gBAC1E,0FAA0F;gBAC1F,oFAAoF;gBACpFH,cAAc,CAAC;YACjB;YAEA,OAAO;gBACL,GAAGd,KAAK;gBACRM,OAAO;oBACL,GAAGN,MAAMM,KAAK;oBACdS,YAAY;wBACV,GAAIf,MAAMM,KAAK,EAAES,cAAc,CAAC,CAAC;wBACjCE,aAAa;4BACXC,aAAa;gCACXC,YAAYf;4BACd;4BACAgB,MAAM;wBACR;wBACA,GAAGN,WAAW;oBAChB;gBACF;YACF;QACF;QAEA,IAAId,MAAMqB,MAAM,EAAE;YAChB,OAAO;gBACL,GAAGrB,KAAK;gBACRqB,QAAQrB,MAAMqB,MAAM,CAACC,GAAG,CAAC,CAACC,WAAkBxB,YAAYwB,UAAUrB;YACpE;QACF;QAEA,IAAIF,MAAMwB,IAAI,EAAE;YACd,OAAO;gBACL,GAAGxB,KAAK;gBACRwB,MAAMxB,MAAMwB,IAAI,CAACF,GAAG,CAAC,CAACG;oBACpB,OAAO;wBACL,GAAGA,GAAG;wBACN,gEAAgE;wBAChEJ,QAAQ,AAACI,CAAAA,IAAIJ,MAAM,IAAI,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC,WAAkBxB,YAAYwB,UAAUtB;oBAC1E;gBACF;YACF;QACF;QAEA,IAAID,MAAM0B,MAAM,EAAE;YAChB,OAAO;gBACL,GAAG1B,KAAK;gBACR0B,QAAQ1B,MAAM0B,MAAM,CAACJ,GAAG,CAAC,CAACK,QAAgB,CAAA;wBACxC,GAAGA,KAAK;wBACRN,QAAQM,MAAMN,MAAM,CAACC,GAAG,CAAC,CAACC,WACxBxB,YAAYwB,UAAU,CAAC,EAAErB,YAAY,CAAC,EAAEyB,MAAMtB,IAAI,CAAC,CAAC;oBAExD,CAAA;YACF;QACF;QAEA,OAAOL;IACT;IAEA,MAAM4B,0BAA0B;QAC9B,GAAG/B,gBAAgB;QACnBwB,QAAQxB,iBAAiBwB,MAAM,CAACC,GAAG,CAAC,CAACtB,QAAUD,YAAYC;IAC7D;IAEA,OAAO;QACLF;QACA8B;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/utilities/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, any>\n updatedCollectionConfig: CollectionConfig | GlobalConfig\n}\n\nexport const updateFieldsConfig = (collectionConfig: CollectionConfig | GlobalConfig): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n function updateField(field: any, parentPath = ''): any {\n const currentPath = field.name\n ? parentPath\n ? `${parentPath}.${field.name}`\n : field.name\n : parentPath\n const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`\n\n // Disabled fields/ field types\n if (\n field.admin?.disabled ||\n field.admin?.readOnly ||\n field.admin?.hidden ||\n field.type === 'row'\n ) {\n return field\n }\n\n // Map field path for global fieldInstructionsMap to load related instructions\n // This is done due to save extra API call to get instructions when Field components are loaded in admin\n // Doing is will only call instructions data when user clicks on settings\n if (['array', 'richText', 'text', 'textarea', 'upload'].includes(field.type)) {\n schemaPathMap = {\n ...schemaPathMap,\n [currentSchemaPath]: {\n type: field.type,\n custom: field.custom,\n label: field.label || field.name,\n relationTo: field.relationTo,\n },\n }\n }\n\n // Inject AI actions, richText is not included here as it has to be explicitly defined by user\n // Array fields also get AI injection for bulk generation\n if (['array', 'text', 'textarea', 'upload'].includes(field.type)) {\n let customField = {}\n\n // Custom fields don't fully adhere to the Payload schema, making it difficult to\n // determine which components support injecting ComposeField as a Description.\n if (field.admin?.components?.Field || field.admin?.components?.Description) {\n // TODO: If a field already provides its own Description, we still inject our ComposeField\n // by overriding Description. If you need both, consider composing your own wrapper.\n customField = {}\n }\n\n // Array fields use ArrayComposeField (always visible) since they don't have focus events\n // Other fields use ComposeField with focus-dependent visibility\n const componentPath = field.type === 'array'\n ? '@ai-stack/payloadcms/fields#ArrayComposeField'\n : '@ai-stack/payloadcms/fields#ComposeField'\n\n return {\n ...field,\n admin: {\n ...field.admin,\n components: {\n ...(field.admin?.components || {}),\n Description: {\n clientProps: {\n schemaPath: currentSchemaPath,\n },\n path: componentPath,\n },\n ...customField,\n },\n },\n }\n }\n\n if (field.fields) {\n return {\n ...field,\n fields: field.fields.map((subField: any) => updateField(subField, currentPath)),\n }\n }\n\n if (field.tabs) {\n return {\n ...field,\n tabs: field.tabs.map((tab: any) => {\n return {\n ...tab,\n // Tabs are a UI construct and should not add to the schema path\n fields: (tab.fields || []).map((subField: any) => updateField(subField, parentPath)),\n }\n }),\n }\n }\n\n if (field.blocks) {\n return {\n ...field,\n blocks: field.blocks.map((block: any) => ({\n ...block,\n fields: block.fields.map((subField: any) =>\n updateField(subField, `${currentPath}.${block.slug}`),\n ),\n })),\n }\n }\n\n return field\n }\n\n const updatedCollectionConfig = {\n ...collectionConfig,\n fields: collectionConfig.fields.map((field) => updateField(field)),\n }\n\n return {\n schemaPathMap,\n updatedCollectionConfig,\n }\n}\n"],"names":["updateFieldsConfig","collectionConfig","schemaPathMap","updateField","field","parentPath","currentPath","name","currentSchemaPath","slug","admin","disabled","readOnly","hidden","type","includes","custom","label","relationTo","customField","components","Field","Description","componentPath","clientProps","schemaPath","path","fields","map","subField","tabs","tab","blocks","block","updatedCollectionConfig"],"mappings":"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"}