@ai-stack/payloadcms 3.2.9-beta → 3.2.11-beta

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 (88) hide show
  1. package/README.md +36 -21
  2. package/dist/ai/models/anthropic/generateRichText.d.ts +1 -1
  3. package/dist/ai/models/anthropic/generateRichText.d.ts.map +1 -1
  4. package/dist/ai/models/anthropic/generateRichText.js +5 -6
  5. package/dist/ai/models/anthropic/generateRichText.js.map +1 -1
  6. package/dist/ai/models/anthropic/index.js +15 -12
  7. package/dist/ai/models/anthropic/index.js.map +1 -1
  8. package/dist/ai/models/openai/generateImage.d.ts +2 -6
  9. package/dist/ai/models/openai/generateImage.d.ts.map +1 -1
  10. package/dist/ai/models/openai/generateImage.js +19 -9
  11. package/dist/ai/models/openai/generateImage.js.map +1 -1
  12. package/dist/ai/models/openai/generateRichText.d.ts +1 -1
  13. package/dist/ai/models/openai/generateRichText.d.ts.map +1 -1
  14. package/dist/ai/models/openai/generateRichText.js +5 -6
  15. package/dist/ai/models/openai/generateRichText.js.map +1 -1
  16. package/dist/ai/models/openai/index.d.ts.map +1 -1
  17. package/dist/ai/models/openai/index.js +133 -4
  18. package/dist/ai/models/openai/index.js.map +1 -1
  19. package/dist/ai/prompts.js +6 -6
  20. package/dist/ai/prompts.js.map +1 -1
  21. package/dist/ai/schemas/lexicalJsonSchema.d.ts +19 -741
  22. package/dist/ai/schemas/lexicalJsonSchema.d.ts.map +1 -1
  23. package/dist/ai/schemas/lexicalJsonSchema.js +72 -4
  24. package/dist/ai/schemas/lexicalJsonSchema.js.map +1 -1
  25. package/dist/ai/utils/editImagesWithOpenAI.d.ts +11 -0
  26. package/dist/ai/utils/editImagesWithOpenAI.d.ts.map +1 -0
  27. package/dist/ai/utils/editImagesWithOpenAI.js +37 -0
  28. package/dist/ai/utils/editImagesWithOpenAI.js.map +1 -0
  29. package/dist/ai/utils/filterEditorSchemaByNodes.d.ts +72 -0
  30. package/dist/ai/utils/filterEditorSchemaByNodes.d.ts.map +1 -0
  31. package/dist/ai/utils/filterEditorSchemaByNodes.js +43 -0
  32. package/dist/ai/utils/filterEditorSchemaByNodes.js.map +1 -0
  33. package/dist/ai/utils/isObjectSchema.d.ts +3 -0
  34. package/dist/ai/utils/isObjectSchema.d.ts.map +1 -0
  35. package/dist/ai/utils/isObjectSchema.js +5 -0
  36. package/dist/ai/utils/isObjectSchema.js.map +1 -0
  37. package/dist/collections/Instructions.d.ts.map +1 -1
  38. package/dist/collections/Instructions.js +26 -1
  39. package/dist/collections/Instructions.js.map +1 -1
  40. package/dist/defaults.d.ts +1 -1
  41. package/dist/defaults.js +1 -1
  42. package/dist/defaults.js.map +1 -1
  43. package/dist/endpoints/index.d.ts.map +1 -1
  44. package/dist/endpoints/index.js +65 -15
  45. package/dist/endpoints/index.js.map +1 -1
  46. package/dist/fields/PromptEditorField/PromptEditorField.d.ts.map +1 -1
  47. package/dist/fields/PromptEditorField/PromptEditorField.js +46 -16
  48. package/dist/fields/PromptEditorField/PromptEditorField.js.map +1 -1
  49. package/dist/fields/PromptEditorField/defaultStyle.d.ts +50 -0
  50. package/dist/fields/PromptEditorField/defaultStyle.d.ts.map +1 -0
  51. package/dist/fields/PromptEditorField/defaultStyle.js +51 -0
  52. package/dist/fields/PromptEditorField/defaultStyle.js.map +1 -0
  53. package/dist/providers/InstructionsProvider/InstructionsProvider.d.ts +2 -0
  54. package/dist/providers/InstructionsProvider/InstructionsProvider.d.ts.map +1 -1
  55. package/dist/providers/InstructionsProvider/InstructionsProvider.js +4 -1
  56. package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
  57. package/dist/providers/InstructionsProvider/useInstructions.d.ts.map +1 -1
  58. package/dist/providers/InstructionsProvider/useInstructions.js +54 -29
  59. package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
  60. package/dist/types.d.ts +18 -1
  61. package/dist/types.d.ts.map +1 -1
  62. package/dist/types.js.map +1 -1
  63. package/dist/ui/Compose/Compose.js +2 -2
  64. package/dist/ui/Compose/Compose.js.map +1 -1
  65. package/dist/ui/Compose/hooks/menu/useMenu.d.ts +1 -1
  66. package/dist/ui/Compose/hooks/menu/useMenu.d.ts.map +1 -1
  67. package/dist/ui/Compose/hooks/menu/useMenu.js +2 -1
  68. package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
  69. package/dist/ui/Compose/hooks/useGenerate.d.ts.map +1 -1
  70. package/dist/ui/Compose/hooks/useGenerate.js +11 -4
  71. package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
  72. package/dist/utilities/extractImageData.d.ts +10 -0
  73. package/dist/utilities/extractImageData.d.ts.map +1 -0
  74. package/dist/utilities/extractImageData.js +22 -0
  75. package/dist/utilities/extractImageData.js.map +1 -0
  76. package/dist/utilities/setSafeLexicalState.js +5 -2
  77. package/dist/utilities/setSafeLexicalState.js.map +1 -1
  78. package/package.json +14 -9
  79. package/dist/ai/models/example-prompt-rich-text.md +0 -47
  80. package/dist/ai/models/example.d.ts +0 -73
  81. package/dist/ai/models/example.d.ts.map +0 -1
  82. package/dist/ai/models/example.js +0 -126
  83. package/dist/ai/models/example.js.map +0 -1
  84. package/dist/libraries/autocomplete/AutocompleteTextArea.d.ts +0 -8
  85. package/dist/libraries/autocomplete/AutocompleteTextArea.d.ts.map +0 -1
  86. package/dist/libraries/autocomplete/AutocompleteTextArea.js +0 -437
  87. package/dist/libraries/autocomplete/AutocompleteTextArea.js.map +0 -1
  88. package/dist/libraries/autocomplete/AutocompleteTextArea.module.scss +0 -35
@@ -1,8 +1,11 @@
1
+ import * as process from 'node:process';
1
2
  import { defaultPrompts } from '../ai/prompts.js';
3
+ import { filterEditorSchemaByNodes } from '../ai/utils/filterEditorSchemaByNodes.js';
2
4
  import { PLUGIN_API_ENDPOINT_GENERATE, PLUGIN_API_ENDPOINT_GENERATE_UPLOAD, PLUGIN_INSTRUCTIONS_TABLE, PLUGIN_NAME } from '../defaults.js';
3
5
  import { registerEditorHelper } from '../libraries/handlebars/helpers.js';
4
6
  import { handlebarsHelpersMap } from '../libraries/handlebars/helpersMap.js';
5
7
  import { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js';
8
+ import { extractImageData } from '../utilities/extractImageData.js';
6
9
  import { getGenerationModels } from '../utilities/getGenerationModels.js';
7
10
  const assignPrompt = async (action, { type, actionParams, context, field, layout, systemPrompt = '', template })=>{
8
11
  const prompt = await replacePlaceholders(template, context);
@@ -38,7 +41,7 @@ export const endpoints = (pluginConfig)=>({
38
41
  //TODO: This is the main endpoint for generating content - its just needs to be renamed to 'generate' or something.
39
42
  handler: async (req)=>{
40
43
  const data = await req.json?.();
41
- const { locale = 'en', options } = data;
44
+ const { allowedEditorNodes = [], locale = 'en', options } = data;
42
45
  const { action, actionParams, instructionId } = options;
43
46
  const contextData = data.doc;
44
47
  if (!instructionId) {
@@ -53,6 +56,10 @@ export const endpoints = (pluginConfig)=>({
53
56
  const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin;
54
57
  const { schema: editorSchema = {} } = editorConfig;
55
58
  const { prompt: promptTemplate = '' } = instructions;
59
+ let allowedEditorSchema = editorSchema;
60
+ if (allowedEditorNodes.length) {
61
+ allowedEditorSchema = filterEditorSchemaByNodes(editorSchema, allowedEditorNodes);
62
+ }
56
63
  const schemaPath = instructions['schema-path'];
57
64
  const fieldName = schemaPath?.split('.').pop();
58
65
  registerEditorHelper(req.payload, schemaPath);
@@ -73,19 +80,20 @@ export const endpoints = (pluginConfig)=>({
73
80
  systemPrompt: instructions.system,
74
81
  template: promptTemplate
75
82
  });
76
- // console.log('Running handler with prompts:', prompts)
77
- return model.handler?.(prompts.prompt, {
78
- ...modelOptions,
79
- editorSchema,
80
- layout: prompts.layout,
81
- locale: localeInfo,
82
- system: prompts.system
83
- }).catch((error)=>{
84
- console.error('Error: endpoint - generating text:', error);
83
+ try {
84
+ return model.handler?.(prompts.prompt, {
85
+ ...modelOptions,
86
+ editorSchema: allowedEditorSchema,
87
+ layout: prompts.layout,
88
+ locale: localeInfo,
89
+ system: prompts.system
90
+ });
91
+ } catch (error) {
92
+ req.payload.logger.error('Error generating content: ', error);
85
93
  return new Response(JSON.stringify(error.message), {
86
94
  status: 500
87
95
  });
88
- });
96
+ }
89
97
  },
90
98
  method: 'post',
91
99
  path: PLUGIN_API_ENDPOINT_GENERATE
@@ -93,10 +101,19 @@ export const endpoints = (pluginConfig)=>({
93
101
  upload: {
94
102
  handler: async (req)=>{
95
103
  const data = await req.json?.();
96
- const { options } = data;
104
+ const { collectionSlug, documentId, options } = data;
97
105
  const { instructionId } = options;
98
- const contextData = data.doc;
106
+ const docData = await req.payload.findByID({
107
+ id: documentId,
108
+ collection: collectionSlug,
109
+ draft: true
110
+ });
111
+ const contextData = {
112
+ ...data.doc,
113
+ ...docData
114
+ };
99
115
  let instructions = {
116
+ images: [],
100
117
  'model-id': '',
101
118
  prompt: ''
102
119
  };
@@ -107,15 +124,48 @@ export const endpoints = (pluginConfig)=>({
107
124
  collection: PLUGIN_INSTRUCTIONS_TABLE
108
125
  });
109
126
  }
110
- const { prompt: promptTemplate = '' } = instructions;
127
+ const { images: sampleImages = [], prompt: promptTemplate = '' } = instructions;
111
128
  const schemaPath = instructions['schema-path'];
112
129
  registerEditorHelper(req.payload, schemaPath);
113
130
  const text = await replacePlaceholders(promptTemplate, contextData);
114
131
  const modelId = instructions['model-id'];
115
132
  const uploadCollectionSlug = instructions['relation-to'];
133
+ const images = [
134
+ ...extractImageData(text),
135
+ ...sampleImages
136
+ ];
137
+ const editImages = [];
138
+ for (const img of images){
139
+ try {
140
+ const serverURL = req.payload.config?.serverURL || process.env.SERVER_URL || process.env.NEXT_PUBLIC_SERVER_URL;
141
+ const response = await fetch(`${serverURL}${img.image.url}`, {
142
+ headers: {
143
+ //TODO: Further testing needed or so find a proper way.
144
+ Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`
145
+ },
146
+ method: 'GET'
147
+ });
148
+ const blob = await response.blob();
149
+ editImages.push({
150
+ name: img.image.name,
151
+ type: img.image.type,
152
+ data: blob,
153
+ size: blob.size,
154
+ url: `${serverURL}${img.image.url}`
155
+ });
156
+ } catch (e) {
157
+ req.payload.logger.error('Error fetching reference images!');
158
+ console.error(e);
159
+ throw Error("We couldn't fetch the images. Please ensure the images are accessible and hosted publicly.");
160
+ }
161
+ }
116
162
  const model = getGenerationModels(pluginConfig).find((model)=>model.id === modelId);
117
163
  const settingsName = model.settings?.name;
118
- const modelOptions = instructions[settingsName] || {};
164
+ let modelOptions = instructions[settingsName] || {};
165
+ modelOptions = {
166
+ ...modelOptions,
167
+ images: editImages
168
+ };
119
169
  const result = await model.handler?.(text, modelOptions);
120
170
  const assetData = await req.payload.create({
121
171
  collection: uploadCollectionSlug,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoints/index.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport type { ActionMenuItems, Endpoints, PluginConfig } from '../types.js'\n\nimport { defaultPrompts } from '../ai/prompts.js'\nimport {\n PLUGIN_API_ENDPOINT_GENERATE,\n PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_NAME,\n} from '../defaults.js'\nimport { registerEditorHelper } from '../libraries/handlebars/helpers.js'\nimport { handlebarsHelpersMap } from '../libraries/handlebars/helpersMap.js'\nimport { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js'\nimport { getGenerationModels } from '../utilities/getGenerationModels.js'\n\nconst assignPrompt = async (\n action: ActionMenuItems,\n {\n type,\n actionParams,\n context,\n field,\n layout,\n systemPrompt = '',\n template,\n }: {\n actionParams: Record<any, any>\n context: object\n field: string\n layout: string\n systemPrompt: string\n template: string\n type: string\n },\n) => {\n const prompt = await replacePlaceholders(template, context)\n const toLexicalHTML = type === 'richText' ? handlebarsHelpersMap.toHTML.name : ''\n\n const assignedPrompts = {\n layout: type === 'richText' ? layout : undefined,\n prompt,\n //TODO: Define only once on a collection level\n system: type === 'richText' ? systemPrompt : undefined,\n }\n\n if (action === 'Compose') {\n return assignedPrompts\n }\n\n const { layout: getLayout, system: getSystemPrompt } = defaultPrompts.find(\n (p) => p.name === action,\n )\n\n let updatedLayout = layout\n if (getLayout) {\n updatedLayout = getLayout()\n }\n\n const system = getSystemPrompt({\n ...(actionParams || {}),\n prompt,\n systemPrompt,\n })\n\n return {\n layout: updatedLayout,\n // TODO: revisit this toLexicalHTML\n prompt: await replacePlaceholders(`{{${toLexicalHTML} ${field}}}`, context),\n system,\n }\n}\n\nexport const endpoints: (pluginConfig: PluginConfig) => Endpoints = (pluginConfig) =>\n ({\n textarea: {\n //TODO: This is the main endpoint for generating content - its just needs to be renamed to 'generate' or something.\n handler: async (req: PayloadRequest) => {\n const data = await req.json?.()\n\n const { locale = 'en', options } = data\n const { action, actionParams, instructionId } = options\n const contextData = data.doc\n\n if (!instructionId) {\n throw new Error(\n `Instruction ID is required for \"${PLUGIN_NAME}\" to work, please check your configuration`,\n )\n }\n\n const instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n })\n\n const { collections } = req.payload.config\n const collection = collections.find(\n (collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE,\n )\n\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin\n const { schema: editorSchema = {} } = editorConfig\n const { prompt: promptTemplate = '' } = instructions\n\n const schemaPath = instructions['schema-path'] as string\n const fieldName = schemaPath?.split('.').pop()\n\n registerEditorHelper(req.payload, schemaPath)\n\n const { defaultLocale, locales = [] } = req.payload.config.localization || {}\n const localeData = locales.find((l) => {\n return l.code === locale\n })\n\n const localeInfo = localeData?.label[defaultLocale] || locale\n\n const model = getGenerationModels(pluginConfig)\n .find((model) => model.id === instructions['model-id'])\n const settingsName = model.settings?.name\n const modelOptions = instructions[settingsName] || {}\n\n const prompts = await assignPrompt(action, {\n type: instructions['field-type'] as string,\n actionParams,\n context: contextData,\n field: fieldName,\n layout: instructions.layout,\n systemPrompt: instructions.system,\n template: promptTemplate as string,\n })\n\n // console.log('Running handler with prompts:', prompts)\n return model\n .handler?.(prompts.prompt, {\n ...modelOptions,\n editorSchema,\n layout: prompts.layout,\n locale: localeInfo,\n system: prompts.system,\n })\n .catch((error) => {\n console.error('Error: endpoint - generating text:', error)\n return new Response(JSON.stringify(error.message), { status: 500 })\n })\n },\n method: 'post',\n path: PLUGIN_API_ENDPOINT_GENERATE,\n },\n upload: {\n handler: async (req: PayloadRequest) => {\n const data = await req.json?.()\n\n const { options } = data\n const { instructionId } = options\n const contextData = data.doc\n\n let instructions = { 'model-id': '', prompt: '' }\n\n if (instructionId) {\n // @ts-expect-error\n instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n })\n }\n\n const { prompt: promptTemplate = '' } = instructions\n const schemaPath = instructions['schema-path']\n\n registerEditorHelper(req.payload, schemaPath)\n\n const text = await replacePlaceholders(promptTemplate, contextData)\n const modelId = instructions['model-id']\n const uploadCollectionSlug = instructions['relation-to']\n\n const model = getGenerationModels(pluginConfig)\n .find((model) => model.id === modelId)\n const settingsName = model.settings?.name\n const modelOptions = instructions[settingsName] || {}\n\n const result = await model.handler?.(text, modelOptions)\n\n const assetData = await req.payload.create({\n collection: uploadCollectionSlug,\n data: result.data,\n file: result.file,\n })\n\n return new Response(\n JSON.stringify({\n result: {\n id: assetData.id,\n alt: assetData.alt,\n },\n }),\n )\n },\n method: 'post',\n path: PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n },\n }) satisfies Endpoints\n"],"names":["defaultPrompts","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","registerEditorHelper","handlebarsHelpersMap","replacePlaceholders","getGenerationModels","assignPrompt","action","type","actionParams","context","field","layout","systemPrompt","template","prompt","toLexicalHTML","toHTML","name","assignedPrompts","undefined","system","getLayout","getSystemPrompt","find","p","updatedLayout","endpoints","pluginConfig","textarea","handler","req","data","json","locale","options","instructionId","contextData","doc","Error","instructions","payload","findByID","id","collection","collections","config","slug","custom","editorConfig","admin","schema","editorSchema","promptTemplate","schemaPath","fieldName","split","pop","defaultLocale","locales","localization","localeData","l","code","localeInfo","label","model","settingsName","settings","modelOptions","prompts","catch","error","console","Response","JSON","stringify","message","status","method","path","upload","text","modelId","uploadCollectionSlug","result","assetData","create","file","alt"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/endpoints/index.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport * as process from 'node:process'\n\nimport type { ActionMenuItems, Endpoints, PluginConfig } from '../types.js'\n\nimport { defaultPrompts } from '../ai/prompts.js'\nimport { filterEditorSchemaByNodes } from '../ai/utils/filterEditorSchemaByNodes.js'\nimport {\n PLUGIN_API_ENDPOINT_GENERATE,\n PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n PLUGIN_INSTRUCTIONS_TABLE,\n PLUGIN_NAME,\n} from '../defaults.js'\nimport { registerEditorHelper } from '../libraries/handlebars/helpers.js'\nimport { handlebarsHelpersMap } from '../libraries/handlebars/helpersMap.js'\nimport { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js'\nimport { extractImageData } from '../utilities/extractImageData.js'\nimport { getGenerationModels } from '../utilities/getGenerationModels.js'\n\nconst assignPrompt = async (\n action: ActionMenuItems,\n {\n type,\n actionParams,\n context,\n field,\n layout,\n systemPrompt = '',\n template,\n }: {\n actionParams: Record<any, any>\n context: object\n field: string\n layout: string\n systemPrompt: string\n template: string\n type: string\n },\n) => {\n const prompt = await replacePlaceholders(template, context)\n const toLexicalHTML = type === 'richText' ? handlebarsHelpersMap.toHTML.name : ''\n\n const assignedPrompts = {\n layout: type === 'richText' ? layout : undefined,\n prompt,\n //TODO: Define only once on a collection level\n system: type === 'richText' ? systemPrompt : undefined,\n }\n\n if (action === 'Compose') {\n return assignedPrompts\n }\n\n const { layout: getLayout, system: getSystemPrompt } = defaultPrompts.find(\n (p) => p.name === action,\n )\n\n let updatedLayout = layout\n if (getLayout) {\n updatedLayout = getLayout()\n }\n\n const system = getSystemPrompt({\n ...(actionParams || {}),\n prompt,\n systemPrompt,\n })\n\n return {\n layout: updatedLayout,\n // TODO: revisit this toLexicalHTML\n prompt: await replacePlaceholders(`{{${toLexicalHTML} ${field}}}`, context),\n system,\n }\n}\n\nexport const endpoints: (pluginConfig: PluginConfig) => Endpoints = (pluginConfig) =>\n ({\n textarea: {\n //TODO: This is the main endpoint for generating content - its just needs to be renamed to 'generate' or something.\n handler: async (req: PayloadRequest) => {\n const data = await req.json?.()\n\n const { allowedEditorNodes = [], locale = 'en', options } = data\n const { action, actionParams, instructionId } = options\n const contextData = data.doc\n\n if (!instructionId) {\n throw new Error(\n `Instruction ID is required for \"${PLUGIN_NAME}\" to work, please check your configuration`,\n )\n }\n\n const instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n })\n\n const { collections } = req.payload.config\n const collection = collections.find(\n (collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE,\n )\n\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin\n const { schema: editorSchema = {} } = editorConfig\n const { prompt: promptTemplate = '' } = instructions\n\n let allowedEditorSchema = editorSchema\n if (allowedEditorNodes.length) {\n allowedEditorSchema = filterEditorSchemaByNodes(editorSchema, allowedEditorNodes)\n }\n\n const schemaPath = instructions['schema-path'] as string\n const fieldName = schemaPath?.split('.').pop()\n\n registerEditorHelper(req.payload, schemaPath)\n\n const { defaultLocale, locales = [] } = req.payload.config.localization || {}\n const localeData = locales.find((l) => {\n return l.code === locale\n })\n\n const localeInfo = localeData?.label[defaultLocale] || locale\n\n const model = getGenerationModels(pluginConfig).find(\n (model) => model.id === instructions['model-id'],\n )\n const settingsName = model.settings?.name\n const modelOptions = instructions[settingsName] || {}\n\n const prompts = await assignPrompt(action, {\n type: instructions['field-type'] as string,\n actionParams,\n context: contextData,\n field: fieldName,\n layout: instructions.layout,\n systemPrompt: instructions.system,\n template: promptTemplate as string,\n })\n\n try {\n return model.handler?.(prompts.prompt, {\n ...modelOptions,\n editorSchema: allowedEditorSchema,\n layout: prompts.layout,\n locale: localeInfo,\n system: prompts.system,\n })\n } catch (error) {\n req.payload.logger.error('Error generating content: ', error)\n return new Response(JSON.stringify(error.message), { status: 500 })\n }\n },\n method: 'post',\n path: PLUGIN_API_ENDPOINT_GENERATE,\n },\n upload: {\n handler: async (req: PayloadRequest) => {\n const data = await req.json?.()\n\n const { collectionSlug, documentId, options } = data\n const { instructionId } = options\n\n const docData = await req.payload.findByID({\n id: documentId,\n collection: collectionSlug,\n draft: true,\n })\n const contextData = {\n ...data.doc,\n ...docData,\n }\n\n let instructions = { images: [], 'model-id': '', prompt: '' }\n\n if (instructionId) {\n // @ts-expect-error\n instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n })\n }\n\n const { images: sampleImages = [], prompt: promptTemplate = '' } = instructions\n const schemaPath = instructions['schema-path']\n\n registerEditorHelper(req.payload, schemaPath)\n\n const text = await replacePlaceholders(promptTemplate, contextData)\n const modelId = instructions['model-id']\n const uploadCollectionSlug = instructions['relation-to']\n\n const images = [...extractImageData(text), ...sampleImages]\n\n const editImages = []\n for (const img of images) {\n try {\n const serverURL =\n req.payload.config?.serverURL ||\n process.env.SERVER_URL ||\n process.env.NEXT_PUBLIC_SERVER_URL\n\n const response = await fetch(`${serverURL}${img.image.url}`, {\n headers: {\n //TODO: Further testing needed or so find a proper way.\n Authorization: `Bearer ${req.headers.get('Authorization')?.split('Bearer ')[1] || ''}`,\n },\n method: 'GET',\n })\n\n const blob = await response.blob()\n editImages.push({\n name: img.image.name,\n type: img.image.type,\n data: blob,\n size: blob.size,\n url: `${serverURL}${img.image.url}`,\n })\n } catch (e) {\n req.payload.logger.error('Error fetching reference images!')\n console.error(e)\n throw Error(\n \"We couldn't fetch the images. Please ensure the images are accessible and hosted publicly.\",\n )\n }\n }\n\n const model = getGenerationModels(pluginConfig).find((model) => model.id === modelId)\n const settingsName = model.settings?.name\n let modelOptions = instructions[settingsName] || {}\n modelOptions = {\n ...modelOptions,\n images: editImages,\n }\n\n const result = await model.handler?.(text, modelOptions)\n\n const assetData = await req.payload.create({\n collection: uploadCollectionSlug,\n data: result.data,\n file: result.file,\n })\n\n return new Response(\n JSON.stringify({\n result: {\n id: assetData.id,\n alt: assetData.alt,\n },\n }),\n )\n },\n method: 'post',\n path: PLUGIN_API_ENDPOINT_GENERATE_UPLOAD,\n },\n }) satisfies Endpoints\n"],"names":["process","defaultPrompts","filterEditorSchemaByNodes","PLUGIN_API_ENDPOINT_GENERATE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","registerEditorHelper","handlebarsHelpersMap","replacePlaceholders","extractImageData","getGenerationModels","assignPrompt","action","type","actionParams","context","field","layout","systemPrompt","template","prompt","toLexicalHTML","toHTML","name","assignedPrompts","undefined","system","getLayout","getSystemPrompt","find","p","updatedLayout","endpoints","pluginConfig","textarea","handler","req","data","json","allowedEditorNodes","locale","options","instructionId","contextData","doc","Error","instructions","payload","findByID","id","collection","collections","config","slug","custom","editorConfig","admin","schema","editorSchema","promptTemplate","allowedEditorSchema","length","schemaPath","fieldName","split","pop","defaultLocale","locales","localization","localeData","l","code","localeInfo","label","model","settingsName","settings","modelOptions","prompts","error","logger","Response","JSON","stringify","message","status","method","path","upload","collectionSlug","documentId","docData","draft","images","sampleImages","text","modelId","uploadCollectionSlug","editImages","img","serverURL","env","SERVER_URL","NEXT_PUBLIC_SERVER_URL","response","fetch","image","url","headers","Authorization","get","blob","push","size","e","console","result","assetData","create","file","alt"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PromptEditorField.d.ts","sourceRoot":"","sources":["../../../src/fields/PromptEditorField/PromptEditorField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAGvD,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA0BhE,CAAA"}
1
+ {"version":3,"file":"PromptEditorField.d.ts","sourceRoot":"","sources":["../../../src/fields/PromptEditorField/PromptEditorField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAGvD,OAAO,KAA4D,MAAM,OAAO,CAAA;AAMhF,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA6DhE,CAAA"}
@@ -1,34 +1,64 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { FieldDescription, FieldLabel, useField } from '@payloadcms/ui';
4
- import React from 'react';
5
- import { AutocompleteTextField } from '../../libraries/autocomplete/AutocompleteTextArea.js';
4
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import { Mention, MentionsInput } from 'react-mentions/dist/react-mentions.cjs.js';
6
6
  import { useInstructions } from '../../providers/InstructionsProvider/useInstructions.js';
7
- //NOTE: HMR does not work for plugin components anymore, I think it has to do with importMap/ string path
7
+ import { defaultStyle } from './defaultStyle.js';
8
8
  export const PromptEditorField = (props)=>{
9
9
  const { field, path: pathFromContext } = props;
10
- const { setValue, value } = useField({
10
+ const { setValue, value: payloadValue } = useField({
11
11
  path: pathFromContext
12
12
  });
13
+ const [localValue, setLocalValue] = useState(payloadValue || '');
14
+ const hasInitialized = useRef(false);
13
15
  const { promptEditorSuggestions } = useInstructions();
16
+ const suggestions = useMemo(()=>promptEditorSuggestions.map((suggestion)=>({
17
+ id: suggestion,
18
+ display: suggestion
19
+ })), [
20
+ promptEditorSuggestions
21
+ ]);
22
+ useEffect(()=>{
23
+ if (!hasInitialized.current || payloadValue === '') {
24
+ setLocalValue(payloadValue || '');
25
+ hasInitialized.current = true;
26
+ }
27
+ }, [
28
+ payloadValue
29
+ ]);
30
+ const handleChange = useCallback((e)=>{
31
+ setLocalValue(e.target.value);
32
+ }, []);
33
+ const handleBlur = useCallback(()=>{
34
+ setValue(localValue);
35
+ }, [
36
+ localValue,
37
+ setValue
38
+ ]);
39
+ const displayTransform = useCallback((id)=>`{{ ${id} }}`, []);
14
40
  return /*#__PURE__*/ _jsxs("div", {
15
41
  className: "field-type textarea",
16
42
  children: [
17
43
  /*#__PURE__*/ _jsx(FieldLabel, {
18
44
  label: field.label
19
45
  }),
20
- /*#__PURE__*/ _jsx(AutocompleteTextField, {
21
- changeOnSelect: (trigger, selected)=>{
22
- return trigger + selected + ' }}';
23
- },
24
- onChange: (val)=>{
25
- setValue(val);
26
- },
27
- options: promptEditorSuggestions,
28
- trigger: [
29
- '{{ '
30
- ],
31
- value: value
46
+ /*#__PURE__*/ _jsx(MentionsInput, {
47
+ onBlur: handleBlur,
48
+ onChange: handleChange,
49
+ placeholder: "Type your prompt using {{ fieldName }} variables...",
50
+ style: defaultStyle,
51
+ value: localValue,
52
+ children: /*#__PURE__*/ _jsx(Mention, {
53
+ data: suggestions,
54
+ displayTransform: displayTransform,
55
+ markup: "{{__id__}}",
56
+ style: {
57
+ backgroundColor: 'var(--theme-elevation-100)',
58
+ padding: "2px 0"
59
+ },
60
+ trigger: "{"
61
+ })
32
62
  }),
33
63
  /*#__PURE__*/ _jsx(FieldDescription, {
34
64
  description: field?.admin?.description,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/fields/PromptEditorField/PromptEditorField.tsx"],"sourcesContent":["'use client'\n\nimport type { TextareaFieldClientProps } from 'payload'\n\nimport { FieldDescription, FieldLabel, useField } from '@payloadcms/ui'\nimport React from 'react'\n\nimport { AutocompleteTextField } from '../../libraries/autocomplete/AutocompleteTextArea.js'\nimport { useInstructions } from '../../providers/InstructionsProvider/useInstructions.js'\n\n//NOTE: HMR does not work for plugin components anymore, I think it has to do with importMap/ string path\nexport const PromptEditorField: React.FC<TextareaFieldClientProps> = (props) => {\n const { field, path: pathFromContext } = props\n\n const { setValue, value } = useField<string>({\n path: pathFromContext,\n })\n\n const { promptEditorSuggestions } = useInstructions()\n\n return (\n <div className=\"field-type textarea\">\n <FieldLabel label={field.label} />\n <AutocompleteTextField\n changeOnSelect={(trigger, selected) => {\n return trigger + selected + ' }}'\n }}\n onChange={(val: string) => {\n setValue(val)\n }}\n options={promptEditorSuggestions}\n trigger={['{{ ']}\n value={value}\n />\n <FieldDescription description={field?.admin?.description} path=\"\" />\n </div>\n )\n}\n"],"names":["FieldDescription","FieldLabel","useField","React","AutocompleteTextField","useInstructions","PromptEditorField","props","field","path","pathFromContext","setValue","value","promptEditorSuggestions","div","className","label","changeOnSelect","trigger","selected","onChange","val","options","description","admin"],"mappings":"AAAA;;AAIA,SAASA,gBAAgB,EAAEC,UAAU,EAAEC,QAAQ,QAAQ,iBAAgB;AACvE,OAAOC,WAAW,QAAO;AAEzB,SAASC,qBAAqB,QAAQ,uDAAsD;AAC5F,SAASC,eAAe,QAAQ,0DAAyD;AAEzF,yGAAyG;AACzG,OAAO,MAAMC,oBAAwD,CAACC;IACpE,MAAM,EAAEC,KAAK,EAAEC,MAAMC,eAAe,EAAE,GAAGH;IAEzC,MAAM,EAAEI,QAAQ,EAAEC,KAAK,EAAE,GAAGV,SAAiB;QAC3CO,MAAMC;IACR;IAEA,MAAM,EAAEG,uBAAuB,EAAE,GAAGR;IAEpC,qBACE,MAACS;QAAIC,WAAU;;0BACb,KAACd;gBAAWe,OAAOR,MAAMQ,KAAK;;0BAC9B,KAACZ;gBACCa,gBAAgB,CAACC,SAASC;oBACxB,OAAOD,UAAUC,WAAW;gBAC9B;gBACAC,UAAU,CAACC;oBACTV,SAASU;gBACX;gBACAC,SAAST;gBACTK,SAAS;oBAAC;iBAAM;gBAChBN,OAAOA;;0BAET,KAACZ;gBAAiBuB,aAAaf,OAAOgB,OAAOD;gBAAad,MAAK;;;;AAGrE,EAAC"}
1
+ {"version":3,"sources":["../../../src/fields/PromptEditorField/PromptEditorField.tsx"],"sourcesContent":["'use client'\n\nimport type { TextareaFieldClientProps } from 'payload'\n\nimport { FieldDescription, FieldLabel, useField } from '@payloadcms/ui'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Mention, MentionsInput } from 'react-mentions/dist/react-mentions.cjs.js'\n\nimport { useInstructions } from '../../providers/InstructionsProvider/useInstructions.js'\nimport { defaultStyle } from './defaultStyle.js'\n\nexport const PromptEditorField: React.FC<TextareaFieldClientProps> = (props) => {\n const { field, path: pathFromContext } = props\n const { setValue, value: payloadValue } = useField<string>({\n path: pathFromContext,\n })\n\n const [localValue, setLocalValue] = useState(payloadValue || '')\n const hasInitialized = useRef(false)\n\n const { promptEditorSuggestions } = useInstructions()\n\n const suggestions = useMemo(\n () =>\n promptEditorSuggestions.map((suggestion) => ({\n id: suggestion,\n display: suggestion,\n })),\n [promptEditorSuggestions],\n )\n\n useEffect(() => {\n if (!hasInitialized.current || payloadValue === '') {\n setLocalValue(payloadValue || '')\n hasInitialized.current = true\n }\n }, [payloadValue])\n\n const handleChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setLocalValue(e.target.value)\n }, [])\n\n const handleBlur = useCallback(() => {\n setValue(localValue)\n }, [localValue, setValue])\n\n const displayTransform = useCallback((id: string) => `{{ ${id} }}`, [])\n\n return (\n <div className=\"field-type textarea\">\n <FieldLabel label={field.label} />\n <MentionsInput\n onBlur={handleBlur}\n onChange={handleChange}\n placeholder=\"Type your prompt using {{ fieldName }} variables...\"\n style={defaultStyle}\n value={localValue}\n >\n <Mention\n data={suggestions}\n displayTransform={displayTransform}\n markup=\"{{__id__}}\"\n style={{\n backgroundColor: 'var(--theme-elevation-100)',\n padding: \"2px 0\"\n }}\n trigger=\"{\"\n />\n </MentionsInput>\n <FieldDescription description={field?.admin?.description} path=\"\" />\n </div>\n )\n}"],"names":["FieldDescription","FieldLabel","useField","React","useCallback","useEffect","useMemo","useRef","useState","Mention","MentionsInput","useInstructions","defaultStyle","PromptEditorField","props","field","path","pathFromContext","setValue","value","payloadValue","localValue","setLocalValue","hasInitialized","promptEditorSuggestions","suggestions","map","suggestion","id","display","current","handleChange","e","target","handleBlur","displayTransform","div","className","label","onBlur","onChange","placeholder","style","data","markup","backgroundColor","padding","trigger","description","admin"],"mappings":"AAAA;;AAIA,SAASA,gBAAgB,EAAEC,UAAU,EAAEC,QAAQ,QAAQ,iBAAgB;AACvE,OAAOC,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAChF,SAASC,OAAO,EAAEC,aAAa,QAAQ,4CAA2C;AAElF,SAASC,eAAe,QAAQ,0DAAyD;AACzF,SAASC,YAAY,QAAQ,oBAAmB;AAEhD,OAAO,MAAMC,oBAAwD,CAACC;IACpE,MAAM,EAAEC,KAAK,EAAEC,MAAMC,eAAe,EAAE,GAAGH;IACzC,MAAM,EAAEI,QAAQ,EAAEC,OAAOC,YAAY,EAAE,GAAGlB,SAAiB;QACzDc,MAAMC;IACR;IAEA,MAAM,CAACI,YAAYC,cAAc,GAAGd,SAASY,gBAAgB;IAC7D,MAAMG,iBAAiBhB,OAAO;IAE9B,MAAM,EAAEiB,uBAAuB,EAAE,GAAGb;IAEpC,MAAMc,cAAcnB,QAClB,IACEkB,wBAAwBE,GAAG,CAAC,CAACC,aAAgB,CAAA;gBAC3CC,IAAID;gBACJE,SAASF;YACX,CAAA,IACF;QAACH;KAAwB;IAG3BnB,UAAU;QACR,IAAI,CAACkB,eAAeO,OAAO,IAAIV,iBAAiB,IAAI;YAClDE,cAAcF,gBAAgB;YAC9BG,eAAeO,OAAO,GAAG;QAC3B;IACF,GAAG;QAACV;KAAa;IAEjB,MAAMW,eAAe3B,YAAY,CAAC4B;QAChCV,cAAcU,EAAEC,MAAM,CAACd,KAAK;IAC9B,GAAG,EAAE;IAEL,MAAMe,aAAa9B,YAAY;QAC7Bc,SAASG;IACX,GAAG;QAACA;QAAYH;KAAS;IAEzB,MAAMiB,mBAAmB/B,YAAY,CAACwB,KAAe,CAAC,GAAG,EAAEA,GAAG,GAAG,CAAC,EAAE,EAAE;IAEtE,qBACE,MAACQ;QAAIC,WAAU;;0BACb,KAACpC;gBAAWqC,OAAOvB,MAAMuB,KAAK;;0BAC9B,KAAC5B;gBACC6B,QAAQL;gBACRM,UAAUT;gBACVU,aAAY;gBACZC,OAAO9B;gBACPO,OAAOE;0BAEP,cAAA,KAACZ;oBACCkC,MAAMlB;oBACNU,kBAAkBA;oBAClBS,QAAO;oBACPF,OAAO;wBACLG,iBAAiB;wBACjBC,SAAS;oBACX;oBACAC,SAAQ;;;0BAGZ,KAAC/C;gBAAiBgD,aAAajC,OAAOkC,OAAOD;gBAAahC,MAAK;;;;AAGrE,EAAC"}
@@ -0,0 +1,50 @@
1
+ export declare const defaultStyle: {
2
+ control: {
3
+ fontSize: number;
4
+ fontWeight: string;
5
+ };
6
+ '&multiLine': {
7
+ control: {
8
+ fontFamily: string;
9
+ minHeight: number;
10
+ };
11
+ highlighter: {
12
+ border: string;
13
+ padding: number;
14
+ };
15
+ input: {
16
+ padding: number;
17
+ };
18
+ };
19
+ '&singleLine': {
20
+ display: string;
21
+ width: number;
22
+ highlighter: {
23
+ border: string;
24
+ padding: number;
25
+ };
26
+ input: {
27
+ border: string;
28
+ padding: number;
29
+ };
30
+ };
31
+ suggestions: {
32
+ item: {
33
+ '&focused': {
34
+ backgroundColor: string;
35
+ };
36
+ borderBottom: string;
37
+ padding: string;
38
+ };
39
+ list: {
40
+ backgroundColor: string;
41
+ borderRadius: string;
42
+ bottom: number;
43
+ fontSize: number;
44
+ maxHeight: number;
45
+ overflow: string;
46
+ position: string;
47
+ };
48
+ };
49
+ };
50
+ //# sourceMappingURL=defaultStyle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaultStyle.d.ts","sourceRoot":"","sources":["../../../src/fields/PromptEditorField/defaultStyle.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDxB,CAAA"}
@@ -0,0 +1,51 @@
1
+ export const defaultStyle = {
2
+ control: {
3
+ fontSize: 12,
4
+ fontWeight: 'normal'
5
+ },
6
+ '&multiLine': {
7
+ control: {
8
+ fontFamily: 'monospace',
9
+ minHeight: 63
10
+ },
11
+ highlighter: {
12
+ border: '1px solid transparent',
13
+ padding: 9
14
+ },
15
+ input: {
16
+ padding: 9
17
+ }
18
+ },
19
+ '&singleLine': {
20
+ display: 'inline-block',
21
+ width: 180,
22
+ highlighter: {
23
+ border: '2px inset transparent',
24
+ padding: 1
25
+ },
26
+ input: {
27
+ border: '2px inset',
28
+ padding: 1
29
+ }
30
+ },
31
+ suggestions: {
32
+ item: {
33
+ '&focused': {
34
+ backgroundColor: 'var(--theme-elevation-100)'
35
+ },
36
+ borderBottom: '1px solid rgba(0,0,0,0.15)',
37
+ padding: '5px 15px'
38
+ },
39
+ list: {
40
+ backgroundColor: 'var(--theme-input-bg)',
41
+ borderRadius: '4px',
42
+ bottom: 14,
43
+ fontSize: 14,
44
+ maxHeight: 160,
45
+ overflow: 'auto',
46
+ position: 'absolute'
47
+ }
48
+ }
49
+ };
50
+
51
+ //# sourceMappingURL=defaultStyle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/fields/PromptEditorField/defaultStyle.ts"],"sourcesContent":["export const defaultStyle = {\n control: {\n fontSize: 12,\n fontWeight: 'normal',\n },\n\n '&multiLine': {\n control: {\n fontFamily: 'monospace',\n minHeight: 63,\n },\n highlighter: {\n border: '1px solid transparent',\n padding: 9,\n },\n input: {\n padding: 9,\n },\n },\n\n '&singleLine': {\n display: 'inline-block',\n width: 180,\n\n highlighter: {\n border: '2px inset transparent',\n padding: 1,\n },\n input: {\n border: '2px inset',\n padding: 1,\n },\n },\n\n suggestions: {\n item: {\n '&focused': {\n backgroundColor: 'var(--theme-elevation-100)',\n },\n borderBottom: '1px solid rgba(0,0,0,0.15)',\n padding: '5px 15px',\n },\n list: {\n backgroundColor: 'var(--theme-input-bg)',\n borderRadius: '4px',\n bottom: 14,\n fontSize: 14,\n maxHeight: 160,\n overflow: 'auto',\n position: 'absolute',\n },\n },\n}\n"],"names":["defaultStyle","control","fontSize","fontWeight","fontFamily","minHeight","highlighter","border","padding","input","display","width","suggestions","item","backgroundColor","borderBottom","list","borderRadius","bottom","maxHeight","overflow","position"],"mappings":"AAAA,OAAO,MAAMA,eAAe;IAC1BC,SAAS;QACPC,UAAU;QACVC,YAAY;IACd;IAEA,cAAc;QACZF,SAAS;YACPG,YAAY;YACZC,WAAW;QACb;QACAC,aAAa;YACXC,QAAQ;YACRC,SAAS;QACX;QACAC,OAAO;YACLD,SAAS;QACX;IACF;IAEA,eAAe;QACbE,SAAS;QACTC,OAAO;QAEPL,aAAa;YACXC,QAAQ;YACRC,SAAS;QACX;QACAC,OAAO;YACLF,QAAQ;YACRC,SAAS;QACX;IACF;IAEAI,aAAa;QACXC,MAAM;YACJ,YAAY;gBACVC,iBAAiB;YACnB;YACAC,cAAc;YACdP,SAAS;QACX;QACAQ,MAAM;YACJF,iBAAiB;YACjBG,cAAc;YACdC,QAAQ;YACRhB,UAAU;YACViB,WAAW;YACXC,UAAU;YACVC,UAAU;QACZ;IACF;AACF,EAAC"}
@@ -1,11 +1,13 @@
1
1
  import type { Field } from 'payload';
2
2
  import React from 'react';
3
3
  export declare const InstructionsContext: React.Context<{
4
+ activeCollection?: string;
4
5
  field?: Field;
5
6
  instructions: Record<string, any>;
6
7
  isConfigAllowed: boolean;
7
8
  path?: string;
8
9
  schemaPath?: unknown;
10
+ setActiveCollection?: (val: unknown) => void;
9
11
  }>;
10
12
  export declare const InstructionsProvider: React.FC;
11
13
  //# sourceMappingURL=InstructionsProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"InstructionsProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/InstructionsProvider/InstructionsProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAGpC,OAAO,KAA6C,MAAM,OAAO,CAAA;AAkBjE,eAAO,MAAM,mBAAmB;YAbtB,KAAK;kBACC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;qBAChB,OAAO;WACjB,MAAM;iBACA,OAAO;EAS0C,CAAA;AAEhE,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EA+BxC,CAAA"}
1
+ {"version":3,"file":"InstructionsProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/InstructionsProvider/InstructionsProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAGpC,OAAO,KAA6C,MAAM,OAAO,CAAA;AAoBjE,eAAO,MAAM,mBAAmB;uBAfX,MAAM;YACjB,KAAK;kBACC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;qBAChB,OAAO;WACjB,MAAM;iBACA,OAAO;0BACE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI;EASkB,CAAA;AAEhE,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAkCxC,CAAA"}
@@ -13,6 +13,7 @@ const initialContext = {
13
13
  export const InstructionsContext = /*#__PURE__*/ createContext(initialContext);
14
14
  export const InstructionsProvider = ({ children })=>{
15
15
  const [instructions, setInstructionsState] = useState({});
16
+ const [activeCollection, setActiveCollection] = useState('');
16
17
  const [isConfigAllowed, setIsConfigAllowed] = useState(false);
17
18
  const { user } = useAuth();
18
19
  const { config } = useConfig();
@@ -33,8 +34,10 @@ export const InstructionsProvider = ({ children })=>{
33
34
  ]);
34
35
  return /*#__PURE__*/ _jsx(InstructionsContext.Provider, {
35
36
  value: {
37
+ activeCollection,
36
38
  instructions,
37
- isConfigAllowed
39
+ isConfigAllowed,
40
+ setActiveCollection
38
41
  },
39
42
  children: children
40
43
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/providers/InstructionsProvider/InstructionsProvider.tsx"],"sourcesContent":["'use client'\n\nimport type { Field } from 'payload'\n\nimport { useAuth, useConfig } from '@payloadcms/ui'\nimport React, { createContext, useEffect, useState } from 'react'\n\nimport { PLUGIN_FETCH_FIELDS_ENDPOINT } from '../../defaults.js'\n\nconst initialContext: {\n field?: Field\n instructions: Record<string, any>\n isConfigAllowed: boolean\n path?: string\n schemaPath?: unknown\n} = {\n field: undefined,\n instructions: undefined,\n isConfigAllowed: true,\n path: '',\n schemaPath: '',\n}\n\nexport const InstructionsContext = createContext(initialContext)\n\nexport const InstructionsProvider: React.FC = ({ children }: { children: React.ReactNode }) => {\n const [instructions, setInstructionsState] = useState({})\n const [isConfigAllowed, setIsConfigAllowed] = useState(false)\n const {\n user\n } = useAuth();\n\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n\n // This is here because each field have separate instructions and\n // their ID is needed to edit them for Drawer\n useEffect(() => {\n fetch(`${serverURL}${api}${PLUGIN_FETCH_FIELDS_ENDPOINT}`)\n .then(async (res) => {\n await res.json().then((data) => {\n setIsConfigAllowed(data?.isConfigAllowed)\n setInstructionsState(data?.fields)\n })\n })\n .catch((err) => {\n console.error('InstructionsProvider:', err)\n })\n }, [user])\n\n return (\n <InstructionsContext.Provider value={{ instructions, isConfigAllowed }}>{children}</InstructionsContext.Provider>\n )\n}\n"],"names":["useAuth","useConfig","React","createContext","useEffect","useState","PLUGIN_FETCH_FIELDS_ENDPOINT","initialContext","field","undefined","instructions","isConfigAllowed","path","schemaPath","InstructionsContext","InstructionsProvider","children","setInstructionsState","setIsConfigAllowed","user","config","routes","api","serverURL","fetch","then","res","json","data","fields","catch","err","console","error","Provider","value"],"mappings":"AAAA;;AAIA,SAASA,OAAO,EAAEC,SAAS,QAAQ,iBAAgB;AACnD,OAAOC,SAASC,aAAa,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAEjE,SAASC,4BAA4B,QAAQ,oBAAmB;AAEhE,MAAMC,iBAMF;IACFC,OAAOC;IACPC,cAAcD;IACdE,iBAAiB;IACjBC,MAAM;IACNC,YAAY;AACd;AAEA,OAAO,MAAMC,oCAAsBX,cAAcI,gBAAe;AAEhE,OAAO,MAAMQ,uBAAiC,CAAC,EAAEC,QAAQ,EAAiC;IACxF,MAAM,CAACN,cAAcO,qBAAqB,GAAGZ,SAAS,CAAC;IACvD,MAAM,CAACM,iBAAiBO,mBAAmB,GAAGb,SAAS;IACvD,MAAM,EACJc,IAAI,EACL,GAAGnB;IAEJ,MAAM,EAAEoB,MAAM,EAAE,GAAGnB;IACnB,MAAM,EACJoB,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,GAAGH;IAEJ,iEAAiE;IACjE,6CAA6C;IAC7ChB,UAAU;QACRoB,MAAM,GAAGD,YAAYD,MAAMhB,8BAA8B,EACtDmB,IAAI,CAAC,OAAOC;YACX,MAAMA,IAAIC,IAAI,GAAGF,IAAI,CAAC,CAACG;gBACrBV,mBAAmBU,MAAMjB;gBACzBM,qBAAqBW,MAAMC;YAC7B;QACF,GACCC,KAAK,CAAC,CAACC;YACNC,QAAQC,KAAK,CAAC,yBAAyBF;QACzC;IACJ,GAAG;QAACZ;KAAK;IAET,qBACE,KAACL,oBAAoBoB,QAAQ;QAACC,OAAO;YAAEzB;YAAcC;QAAgB;kBAAIK;;AAE7E,EAAC"}
1
+ {"version":3,"sources":["../../../src/providers/InstructionsProvider/InstructionsProvider.tsx"],"sourcesContent":["'use client'\n\nimport type { Field } from 'payload'\n\nimport { useAuth, useConfig } from '@payloadcms/ui'\nimport React, { createContext, useEffect, useState } from 'react'\n\nimport { PLUGIN_FETCH_FIELDS_ENDPOINT } from '../../defaults.js'\n\nconst initialContext: {\n activeCollection?: string\n field?: Field\n instructions: Record<string, any>\n isConfigAllowed: boolean\n path?: string\n schemaPath?: unknown\n setActiveCollection?: (val: unknown) => void\n} = {\n field: undefined,\n instructions: undefined,\n isConfigAllowed: true,\n path: '',\n schemaPath: '',\n}\n\nexport const InstructionsContext = createContext(initialContext)\n\nexport const InstructionsProvider: React.FC = ({ children }: { children: React.ReactNode }) => {\n const [instructions, setInstructionsState] = useState({})\n const [activeCollection, setActiveCollection] = useState('')\n const [isConfigAllowed, setIsConfigAllowed] = useState(false)\n const { user } = useAuth()\n\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n\n // This is here because each field have separate instructions and\n // their ID is needed to edit them for Drawer\n useEffect(() => {\n fetch(`${serverURL}${api}${PLUGIN_FETCH_FIELDS_ENDPOINT}`)\n .then(async (res) => {\n await res.json().then((data) => {\n setIsConfigAllowed(data?.isConfigAllowed)\n setInstructionsState(data?.fields)\n })\n })\n .catch((err) => {\n console.error('InstructionsProvider:', err)\n })\n }, [user])\n\n return (\n <InstructionsContext.Provider\n value={{ activeCollection, instructions, isConfigAllowed, setActiveCollection }}\n >\n {children}\n </InstructionsContext.Provider>\n )\n}\n"],"names":["useAuth","useConfig","React","createContext","useEffect","useState","PLUGIN_FETCH_FIELDS_ENDPOINT","initialContext","field","undefined","instructions","isConfigAllowed","path","schemaPath","InstructionsContext","InstructionsProvider","children","setInstructionsState","activeCollection","setActiveCollection","setIsConfigAllowed","user","config","routes","api","serverURL","fetch","then","res","json","data","fields","catch","err","console","error","Provider","value"],"mappings":"AAAA;;AAIA,SAASA,OAAO,EAAEC,SAAS,QAAQ,iBAAgB;AACnD,OAAOC,SAASC,aAAa,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAEjE,SAASC,4BAA4B,QAAQ,oBAAmB;AAEhE,MAAMC,iBAQF;IACFC,OAAOC;IACPC,cAAcD;IACdE,iBAAiB;IACjBC,MAAM;IACNC,YAAY;AACd;AAEA,OAAO,MAAMC,oCAAsBX,cAAcI,gBAAe;AAEhE,OAAO,MAAMQ,uBAAiC,CAAC,EAAEC,QAAQ,EAAiC;IACxF,MAAM,CAACN,cAAcO,qBAAqB,GAAGZ,SAAS,CAAC;IACvD,MAAM,CAACa,kBAAkBC,oBAAoB,GAAGd,SAAS;IACzD,MAAM,CAACM,iBAAiBS,mBAAmB,GAAGf,SAAS;IACvD,MAAM,EAAEgB,IAAI,EAAE,GAAGrB;IAEjB,MAAM,EAAEsB,MAAM,EAAE,GAAGrB;IACnB,MAAM,EACJsB,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,GAAGH;IAEJ,iEAAiE;IACjE,6CAA6C;IAC7ClB,UAAU;QACRsB,MAAM,GAAGD,YAAYD,MAAMlB,8BAA8B,EACtDqB,IAAI,CAAC,OAAOC;YACX,MAAMA,IAAIC,IAAI,GAAGF,IAAI,CAAC,CAACG;gBACrBV,mBAAmBU,MAAMnB;gBACzBM,qBAAqBa,MAAMC;YAC7B;QACF,GACCC,KAAK,CAAC,CAACC;YACNC,QAAQC,KAAK,CAAC,yBAAyBF;QACzC;IACJ,GAAG;QAACZ;KAAK;IAET,qBACE,KAACP,oBAAoBsB,QAAQ;QAC3BC,OAAO;YAAEnB;YAAkBR;YAAcC;YAAiBQ;QAAoB;kBAE7EH;;AAGP,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useInstructions.d.ts","sourceRoot":"","sources":["../../../src/providers/InstructionsProvider/useInstructions.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,GAC1B,SAAQ;IACN,UAAU,CAAC,EAAE,OAAO,CAAA;CAChB,QAgDP,CAAA"}
1
+ {"version":3,"file":"useInstructions.d.ts","sourceRoot":"","sources":["../../../src/providers/InstructionsProvider/useInstructions.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,eAAe,GAC1B,SAAQ;IACN,UAAU,CAAC,EAAE,OAAO,CAAA;CAChB,QAqEP,CAAA"}
@@ -1,45 +1,70 @@
1
- import { useContext, useEffect, useState } from 'react';
1
+ import { useDocumentInfo } from '@payloadcms/ui';
2
+ import { useContext, useEffect, useMemo, useState } from 'react';
3
+ import { PLUGIN_INSTRUCTIONS_TABLE } from '../../defaults.js';
2
4
  import { handlebarsHelpers, handlebarsHelpersMap } from '../../libraries/handlebars/helpersMap.js';
3
5
  import { InstructionsContext } from './InstructionsProvider.js';
4
6
  export const useInstructions = (update = {})=>{
5
7
  const context = useContext(InstructionsContext);
6
- //Fields are used for autocompletion in PromptTextareaField
7
- const fields = Object.keys(context.instructions || {}).map((key)=>{
8
- return key.split('.').slice(1).join('.');
9
- });
10
- const promptEditorSuggestions = [
11
- ...fields
12
- ].reduce((acc, f)=>{
13
- const fieldKey = Object.keys(context.instructions).find((k)=>k.endsWith(f));
14
- const fieldInfo = context.instructions[fieldKey];
15
- // Currently, Upload fields are excluded from suggestions
16
- if (fieldInfo.fieldType === 'upload') {
17
- return acc;
18
- }
19
- const helpers = handlebarsHelpers.filter((h)=>handlebarsHelpersMap[h]?.field === fieldInfo.fieldType);
20
- if (helpers.length) {
21
- for (const helper of helpers){
22
- acc.push(helper + ` ${f}`);
23
- }
24
- return acc;
25
- }
26
- acc.push(f);
27
- return acc;
28
- }, []);
8
+ const { collectionSlug } = useDocumentInfo();
9
+ const { activeCollection, instructions, setActiveCollection } = context;
29
10
  const [schemaPath, setSchemaPath] = useState(update.schemaPath);
30
11
  useEffect(()=>{
31
12
  if (update.schemaPath !== schemaPath) {
32
13
  setSchemaPath(update.schemaPath);
33
14
  }
34
15
  }, [
35
- schemaPath,
36
- update
16
+ update.schemaPath
17
+ ]);
18
+ useEffect(()=>{
19
+ if (activeCollection !== collectionSlug && collectionSlug !== PLUGIN_INSTRUCTIONS_TABLE) {
20
+ setActiveCollection(collectionSlug);
21
+ }
22
+ }, [
23
+ activeCollection,
24
+ collectionSlug,
25
+ setActiveCollection
26
+ ]);
27
+ const groupedFields = useMemo(()=>{
28
+ const result = {};
29
+ for (const fullKey of Object.keys(instructions)){
30
+ const [collection, ...pathParts] = fullKey.split('.');
31
+ const path = pathParts.join('.');
32
+ if (!result[collection]) result[collection] = [];
33
+ result[collection].push(path);
34
+ }
35
+ return result;
36
+ }, [
37
+ instructions
38
+ ]);
39
+ // Suggestions for prompt editor
40
+ const promptEditorSuggestions = useMemo(()=>{
41
+ const activeFields = groupedFields[activeCollection] || [];
42
+ return activeFields.reduce((acc, f)=>{
43
+ const fieldKey = Object.keys(instructions).find((k)=>k.endsWith(f));
44
+ const fieldInfo = instructions[fieldKey];
45
+ if (!fieldInfo) return acc;
46
+ if (fieldInfo.fieldType === 'upload') {
47
+ acc.push(`${f}.url`);
48
+ return acc;
49
+ }
50
+ const helpers = handlebarsHelpers.filter((h)=>handlebarsHelpersMap[h]?.field === fieldInfo.fieldType);
51
+ if (helpers.length) {
52
+ for (const helper of helpers){
53
+ acc.push(`${helper} ${f}`);
54
+ }
55
+ } else {
56
+ acc.push(f);
57
+ }
58
+ return acc;
59
+ }, []);
60
+ }, [
61
+ groupedFields,
62
+ activeCollection,
63
+ instructions
37
64
  ]);
38
65
  return {
39
66
  ...context,
40
- ...context.instructions[schemaPath] || {},
41
- fields,
42
- map: context.instructions,
67
+ ...instructions[schemaPath] || {},
43
68
  promptEditorSuggestions
44
69
  };
45
70
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/providers/InstructionsProvider/useInstructions.ts"],"sourcesContent":["import { useContext, useEffect, useState } from 'react'\n\nimport { handlebarsHelpers, handlebarsHelpersMap } from '../../libraries/handlebars/helpersMap.js'\nimport { InstructionsContext } from './InstructionsProvider.js'\n\nexport const useInstructions = (\n update: {\n schemaPath?: unknown\n } = {},\n) => {\n const context = useContext(InstructionsContext)\n\n //Fields are used for autocompletion in PromptTextareaField\n const fields = Object.keys(context.instructions || {}).map((key) => {\n return key.split('.').slice(1).join('.')\n })\n\n const promptEditorSuggestions = [...fields].reduce((acc, f) => {\n const fieldKey = Object.keys(context.instructions).find((k) => k.endsWith(f))\n const fieldInfo = context.instructions[fieldKey]\n\n // Currently, Upload fields are excluded from suggestions\n if (fieldInfo.fieldType === 'upload') {\n return acc\n }\n\n const helpers = handlebarsHelpers.filter(\n (h) => handlebarsHelpersMap[h]?.field === fieldInfo.fieldType,\n )\n\n if (helpers.length) {\n for (const helper of helpers) {\n acc.push(helper + ` ${f}`)\n }\n return acc\n }\n\n acc.push(f)\n return acc\n }, [])\n\n const [schemaPath, setSchemaPath] = useState(update.schemaPath as string)\n\n useEffect(() => {\n if(update.schemaPath !== schemaPath) {\n setSchemaPath(update.schemaPath as string)\n }\n }, [schemaPath, update])\n\n return {\n ...context,\n ...(context.instructions[schemaPath] || {}),\n fields,\n map: context.instructions,\n promptEditorSuggestions,\n }\n}\n"],"names":["useContext","useEffect","useState","handlebarsHelpers","handlebarsHelpersMap","InstructionsContext","useInstructions","update","context","fields","Object","keys","instructions","map","key","split","slice","join","promptEditorSuggestions","reduce","acc","f","fieldKey","find","k","endsWith","fieldInfo","fieldType","helpers","filter","h","field","length","helper","push","schemaPath","setSchemaPath"],"mappings":"AAAA,SAASA,UAAU,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAEvD,SAASC,iBAAiB,EAAEC,oBAAoB,QAAQ,2CAA0C;AAClG,SAASC,mBAAmB,QAAQ,4BAA2B;AAE/D,OAAO,MAAMC,kBAAkB,CAC7BC,SAEI,CAAC,CAAC;IAEN,MAAMC,UAAUR,WAAWK;IAE3B,2DAA2D;IAC3D,MAAMI,SAASC,OAAOC,IAAI,CAACH,QAAQI,YAAY,IAAI,CAAC,GAAGC,GAAG,CAAC,CAACC;QAC1D,OAAOA,IAAIC,KAAK,CAAC,KAAKC,KAAK,CAAC,GAAGC,IAAI,CAAC;IACtC;IAEA,MAAMC,0BAA0B;WAAIT;KAAO,CAACU,MAAM,CAAC,CAACC,KAAKC;QACvD,MAAMC,WAAWZ,OAAOC,IAAI,CAACH,QAAQI,YAAY,EAAEW,IAAI,CAAC,CAACC,IAAMA,EAAEC,QAAQ,CAACJ;QAC1E,MAAMK,YAAYlB,QAAQI,YAAY,CAACU,SAAS;QAEhD,yDAAyD;QACzD,IAAII,UAAUC,SAAS,KAAK,UAAU;YACpC,OAAOP;QACT;QAEA,MAAMQ,UAAUzB,kBAAkB0B,MAAM,CACtC,CAACC,IAAM1B,oBAAoB,CAAC0B,EAAE,EAAEC,UAAUL,UAAUC,SAAS;QAG/D,IAAIC,QAAQI,MAAM,EAAE;YAClB,KAAK,MAAMC,UAAUL,QAAS;gBAC5BR,IAAIc,IAAI,CAACD,SAAS,CAAC,CAAC,EAAEZ,GAAG;YAC3B;YACA,OAAOD;QACT;QAEAA,IAAIc,IAAI,CAACb;QACT,OAAOD;IACT,GAAG,EAAE;IAEL,MAAM,CAACe,YAAYC,cAAc,GAAGlC,SAASK,OAAO4B,UAAU;IAE9DlC,UAAU;QACR,IAAGM,OAAO4B,UAAU,KAAKA,YAAY;YACnCC,cAAc7B,OAAO4B,UAAU;QACjC;IACF,GAAG;QAACA;QAAY5B;KAAO;IAEvB,OAAO;QACL,GAAGC,OAAO;QACV,GAAIA,QAAQI,YAAY,CAACuB,WAAW,IAAI,CAAC,CAAC;QAC1C1B;QACAI,KAAKL,QAAQI,YAAY;QACzBM;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../../src/providers/InstructionsProvider/useInstructions.ts"],"sourcesContent":["import { useDocumentInfo } from '@payloadcms/ui'\nimport { useContext, useEffect, useMemo, useState } from 'react'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../../defaults.js'\nimport { handlebarsHelpers, handlebarsHelpersMap } from '../../libraries/handlebars/helpersMap.js'\nimport { InstructionsContext } from './InstructionsProvider.js'\n\nexport const useInstructions = (\n update: {\n schemaPath?: unknown\n } = {},\n) => {\n const context = useContext(InstructionsContext)\n const { collectionSlug } = useDocumentInfo()\n const { activeCollection, instructions, setActiveCollection } = context\n\n const [schemaPath, setSchemaPath] = useState(update.schemaPath as string)\n\n useEffect(() => {\n if (update.schemaPath !== schemaPath) {\n setSchemaPath(update.schemaPath as string)\n }\n }, [update.schemaPath])\n\n useEffect(() => {\n if (activeCollection !== collectionSlug && collectionSlug !== PLUGIN_INSTRUCTIONS_TABLE) {\n setActiveCollection(collectionSlug)\n }\n }, [activeCollection, collectionSlug, setActiveCollection])\n\n const groupedFields = useMemo(() => {\n const result: Record<string, string[]> = {}\n\n for (const fullKey of Object.keys(instructions)) {\n const [collection, ...pathParts] = fullKey.split('.')\n const path = pathParts.join('.')\n if (!result[collection]) result[collection] = []\n result[collection].push(path)\n }\n\n return result\n }, [instructions])\n\n // Suggestions for prompt editor\n const promptEditorSuggestions = useMemo(() => {\n const activeFields = groupedFields[activeCollection] || []\n\n return activeFields.reduce<string[]>((acc, f) => {\n const fieldKey = Object.keys(instructions).find((k) => k.endsWith(f))\n const fieldInfo = instructions[fieldKey]\n\n if (!fieldInfo) return acc\n\n if (fieldInfo.fieldType === 'upload') {\n acc.push(`${f}.url`)\n return acc\n }\n\n const helpers = handlebarsHelpers.filter(\n (h) => handlebarsHelpersMap[h]?.field === fieldInfo.fieldType,\n )\n\n if (helpers.length) {\n for (const helper of helpers) {\n acc.push(`${helper} ${f}`)\n }\n } else {\n acc.push(f)\n }\n\n return acc\n }, [])\n }, [groupedFields, activeCollection, instructions])\n\n return {\n ...context,\n ...(instructions[schemaPath] || {}),\n promptEditorSuggestions,\n }\n}\n"],"names":["useDocumentInfo","useContext","useEffect","useMemo","useState","PLUGIN_INSTRUCTIONS_TABLE","handlebarsHelpers","handlebarsHelpersMap","InstructionsContext","useInstructions","update","context","collectionSlug","activeCollection","instructions","setActiveCollection","schemaPath","setSchemaPath","groupedFields","result","fullKey","Object","keys","collection","pathParts","split","path","join","push","promptEditorSuggestions","activeFields","reduce","acc","f","fieldKey","find","k","endsWith","fieldInfo","fieldType","helpers","filter","h","field","length","helper"],"mappings":"AAAA,SAASA,eAAe,QAAQ,iBAAgB;AAChD,SAASC,UAAU,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAEhE,SAASC,yBAAyB,QAAQ,oBAAmB;AAC7D,SAASC,iBAAiB,EAAEC,oBAAoB,QAAQ,2CAA0C;AAClG,SAASC,mBAAmB,QAAQ,4BAA2B;AAE/D,OAAO,MAAMC,kBAAkB,CAC7BC,SAEI,CAAC,CAAC;IAEN,MAAMC,UAAUV,WAAWO;IAC3B,MAAM,EAAEI,cAAc,EAAE,GAAGZ;IAC3B,MAAM,EAAEa,gBAAgB,EAAEC,YAAY,EAAEC,mBAAmB,EAAE,GAAGJ;IAEhE,MAAM,CAACK,YAAYC,cAAc,GAAGb,SAASM,OAAOM,UAAU;IAE9Dd,UAAU;QACR,IAAIQ,OAAOM,UAAU,KAAKA,YAAY;YACpCC,cAAcP,OAAOM,UAAU;QACjC;IACF,GAAG;QAACN,OAAOM,UAAU;KAAC;IAEtBd,UAAU;QACR,IAAIW,qBAAqBD,kBAAkBA,mBAAmBP,2BAA2B;YACvFU,oBAAoBH;QACtB;IACF,GAAG;QAACC;QAAkBD;QAAgBG;KAAoB;IAE1D,MAAMG,gBAAgBf,QAAQ;QAC5B,MAAMgB,SAAmC,CAAC;QAE1C,KAAK,MAAMC,WAAWC,OAAOC,IAAI,CAACR,cAAe;YAC/C,MAAM,CAACS,YAAY,GAAGC,UAAU,GAAGJ,QAAQK,KAAK,CAAC;YACjD,MAAMC,OAAOF,UAAUG,IAAI,CAAC;YAC5B,IAAI,CAACR,MAAM,CAACI,WAAW,EAAEJ,MAAM,CAACI,WAAW,GAAG,EAAE;YAChDJ,MAAM,CAACI,WAAW,CAACK,IAAI,CAACF;QAC1B;QAEA,OAAOP;IACT,GAAG;QAACL;KAAa;IAEjB,gCAAgC;IAChC,MAAMe,0BAA0B1B,QAAQ;QACtC,MAAM2B,eAAeZ,aAAa,CAACL,iBAAiB,IAAI,EAAE;QAE1D,OAAOiB,aAAaC,MAAM,CAAW,CAACC,KAAKC;YACzC,MAAMC,WAAWb,OAAOC,IAAI,CAACR,cAAcqB,IAAI,CAAC,CAACC,IAAMA,EAAEC,QAAQ,CAACJ;YAClE,MAAMK,YAAYxB,YAAY,CAACoB,SAAS;YAExC,IAAI,CAACI,WAAW,OAAON;YAEvB,IAAIM,UAAUC,SAAS,KAAK,UAAU;gBACpCP,IAAIJ,IAAI,CAAC,GAAGK,EAAE,IAAI,CAAC;gBACnB,OAAOD;YACT;YAEA,MAAMQ,UAAUlC,kBAAkBmC,MAAM,CACtC,CAACC,IAAMnC,oBAAoB,CAACmC,EAAE,EAAEC,UAAUL,UAAUC,SAAS;YAG/D,IAAIC,QAAQI,MAAM,EAAE;gBAClB,KAAK,MAAMC,UAAUL,QAAS;oBAC5BR,IAAIJ,IAAI,CAAC,GAAGiB,OAAO,CAAC,EAAEZ,GAAG;gBAC3B;YACF,OAAO;gBACLD,IAAIJ,IAAI,CAACK;YACX;YAEA,OAAOD;QACT,GAAG,EAAE;IACP,GAAG;QAACd;QAAeL;QAAkBC;KAAa;IAElD,OAAO;QACL,GAAGH,OAAO;QACV,GAAIG,YAAY,CAACE,WAAW,IAAI,CAAC,CAAC;QAClCa;IACF;AACF,EAAC"}