@ai-stack/payloadcms 3.76.0-beta.6 → 3.76.0-beta.8
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.
- package/dist/endpoints/generate.js +4 -2
- package/dist/endpoints/generate.js.map +1 -1
- package/dist/endpoints/upload.js +10 -6
- package/dist/endpoints/upload.js.map +1 -1
- package/dist/libraries/{handlebars → templates}/helpersMap.d.ts +3 -3
- package/dist/libraries/templates/helpersMap.js +13 -0
- package/dist/libraries/templates/helpersMap.js.map +1 -0
- package/dist/libraries/templates/legacySyntax.d.ts +5 -0
- package/dist/libraries/templates/legacySyntax.js +273 -0
- package/dist/libraries/templates/legacySyntax.js.map +1 -0
- package/dist/libraries/templates/legacySyntax.test.d.ts +1 -0
- package/dist/libraries/templates/legacySyntax.test.js +41 -0
- package/dist/libraries/templates/legacySyntax.test.js.map +1 -0
- package/dist/libraries/templates/renderTemplate.d.ts +7 -0
- package/dist/libraries/templates/renderTemplate.js +108 -0
- package/dist/libraries/templates/renderTemplate.js.map +1 -0
- package/dist/providers/InstructionsProvider/useInstructions.js +2 -2
- package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
- package/dist/utilities/buildPromptUtils.d.ts +4 -2
- package/dist/utilities/buildPromptUtils.js +13 -15
- package/dist/utilities/buildPromptUtils.js.map +1 -1
- package/dist/utilities/lexical/lexicalToPromptTemplate.js +3 -13
- package/dist/utilities/lexical/lexicalToPromptTemplate.js.map +1 -1
- package/dist/utilities/runtime/resolveServerURL.js +16 -1
- package/dist/utilities/runtime/resolveServerURL.js.map +1 -1
- package/package.json +2 -3
- package/dist/libraries/handlebars/asyncHandlebars.d.ts +0 -1
- package/dist/libraries/handlebars/asyncHandlebars.js +0 -5
- package/dist/libraries/handlebars/asyncHandlebars.js.map +0 -1
- package/dist/libraries/handlebars/helpers.d.ts +0 -1
- package/dist/libraries/handlebars/helpers.js +0 -27
- package/dist/libraries/handlebars/helpers.js.map +0 -1
- package/dist/libraries/handlebars/helpersMap.js +0 -13
- package/dist/libraries/handlebars/helpersMap.js.map +0 -1
- package/dist/libraries/handlebars/replacePlaceholders.d.ts +0 -1
- package/dist/libraries/handlebars/replacePlaceholders.js +0 -12
- package/dist/libraries/handlebars/replacePlaceholders.js.map +0 -1
- package/dist/types/handlebars-async-helpers.d.ts +0 -1
- package/dist/types/handlebars-dist-handlebars.d.ts +0 -1
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { checkAccess } from '../access/checkAccess.js';
|
|
2
2
|
import { filterEditorSchemaByNodes } from '../ai/utilities/filterEditorSchemaByNodes.js';
|
|
3
3
|
import { PLUGIN_INSTRUCTIONS_TABLE, PLUGIN_NAME } from '../defaults.js';
|
|
4
|
-
import { registerEditorHelper } from '../libraries/handlebars/helpers.js';
|
|
5
4
|
import { resolveEffectiveInstructionSettings } from '../utilities/ai/resolveEffectiveInstructionSettings.js';
|
|
6
5
|
import { assignPrompt } from '../utilities/buildPromptUtils.js';
|
|
7
6
|
import { buildSmartPrompt, isGenericPrompt } from '../utilities/buildSmartPrompt.js';
|
|
@@ -98,7 +97,6 @@ import { sanitizeLog } from '../utilities/sanitizeLog.js';
|
|
|
98
97
|
const parts = (schemaPath || '').split('.') || [];
|
|
99
98
|
const collectionName = parts[0];
|
|
100
99
|
const fieldName = parts.length > 1 ? parts[parts.length - 1] : '';
|
|
101
|
-
registerEditorHelper(req.payload, schemaPath);
|
|
102
100
|
const localeData = locales.find((l)=>{
|
|
103
101
|
return l.code === locale;
|
|
104
102
|
});
|
|
@@ -116,6 +114,10 @@ import { sanitizeLog } from '../utilities/sanitizeLog.js';
|
|
|
116
114
|
locale: localeInfo,
|
|
117
115
|
pluginConfig,
|
|
118
116
|
systemPrompt: instructions.system,
|
|
117
|
+
templateRuntime: {
|
|
118
|
+
payload: req.payload,
|
|
119
|
+
schemaPath
|
|
120
|
+
},
|
|
119
121
|
template: String(promptTemplate)
|
|
120
122
|
});
|
|
121
123
|
if (pluginConfig.debugging) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/generate.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { Field, PayloadRequest } from 'payload'\n\nimport type { PluginConfig } from '../types.js'\n\nimport { checkAccess } from '../access/checkAccess.js'\nimport { filterEditorSchemaByNodes } from '../ai/utilities/filterEditorSchemaByNodes.js'\nimport { PLUGIN_INSTRUCTIONS_TABLE, PLUGIN_NAME } from '../defaults.js'\nimport { registerEditorHelper } from '../libraries/handlebars/helpers.js'\nimport { resolveEffectiveInstructionSettings } from '../utilities/ai/resolveEffectiveInstructionSettings.js'\nimport { assignPrompt } from '../utilities/buildPromptUtils.js'\nimport { buildSmartPrompt, isGenericPrompt } from '../utilities/buildSmartPrompt.js'\nimport { fieldToJsonSchema } from '../utilities/fields/fieldToJsonSchema.js'\nimport { getFieldBySchemaPath } from '../utilities/fields/getFieldBySchemaPath.js'\nimport { extractImageData } from '../utilities/images/extractImageData.js'\nimport { type FetchableImage, fetchImages } from '../utilities/images/fetchImages.js'\nimport { resolveImageReferences } from '../utilities/images/resolveImageReferences.js'\nimport { lexicalToPromptTemplate } from '../utilities/lexical/lexicalToPromptTemplate.js'\nimport { sanitizeLog } from '../utilities/sanitizeLog.js'\n\n/**\n * Text/rich-text generation endpoint handler.\n * Uses payload.ai.streamObject for structured text generation.\n */\nexport const generateHandler = (pluginConfig: PluginConfig) => async (req: PayloadRequest) => {\n try {\n // Check authentication and authorization first\n await checkAccess(req, pluginConfig)\n\n const data = await req.json?.()\n\n const { allowedEditorNodes = [], locale = 'en', options } = data\n const { action, actionParams, instructionId } = options\n let 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, or try again`,\n )\n }\n\n // Verify user has access to the specific instruction\n const instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n req, // Pass req to ensure access control is applied\n })\n\n const { collections } = req.payload.config\n const collection = collections.find(\n (collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE,\n )\n\n if (!collection) {\n throw new Error('Collection not found')\n }\n\n const { defaultLocale, locales = [] } = req.payload.config.localization || {}\n\n // If translating from default locale, we need to fetch the original content\n if (action === 'Translate' && actionParams?.translateFromDefault && contextData?.id) {\n try {\n const schemaPath = String(instructions['schema-path'])\n const parts = (schemaPath || '').split('.') || []\n const collectionName = parts[0]\n\n if (collectionName && defaultLocale) {\n const originalDoc = await req.payload.findByID({\n id: contextData.id,\n collection: collectionName as any,\n locale: defaultLocale,\n req,\n })\n if (originalDoc) {\n contextData = { ...contextData, ...originalDoc }\n }\n }\n } catch (e) {\n req.payload.logger.error(\n e,\n '— AI Plugin: Error fetching default locale document for translation',\n )\n }\n }\n\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin\n const { schema: editorSchema = {} } = editorConfig\n let { prompt: promptTemplate = '' } = instructions\n\n // Convert Lexical JSON to string template if needed\n if (promptTemplate && typeof promptTemplate === 'object') {\n promptTemplate = lexicalToPromptTemplate(promptTemplate)\n }\n\n // Smart fallback: if prompt is generic, build a contextual prompt from field metadata\n if (isGenericPrompt(promptTemplate)) {\n const schemaPath = String(instructions['schema-path'])\n promptTemplate = buildSmartPrompt({\n documentData: contextData,\n payload: req.payload,\n schemaPath,\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog({ smartPrompt: promptTemplate }),\n `— AI Plugin: Using smart fallback prompt for ${schemaPath}`,\n )\n }\n }\n\n let allowedEditorSchema = editorSchema\n if (allowedEditorNodes.length) {\n allowedEditorSchema = filterEditorSchemaByNodes(editorSchema, allowedEditorNodes)\n // Debug: Log what nodes were received and what definitions remain\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog({\n receivedNodes: allowedEditorNodes,\n remainingDefinitions: Object.keys(allowedEditorSchema.definitions || {}),\n }),\n '— AI Plugin: Schema filtering debug',\n )\n }\n }\n\n const schemaPath = String(instructions['schema-path'])\n const parts = (schemaPath || '').split('.') || []\n const collectionName = parts[0]\n const fieldName = parts.length > 1 ? parts[parts.length - 1] : ''\n\n registerEditorHelper(req.payload, schemaPath)\n\n const localeData = locales.find((l) => {\n return l.code === locale\n })\n\n let localeInfo = locale\n if (\n localeData &&\n defaultLocale &&\n localeData.label &&\n typeof localeData.label === 'object' &&\n defaultLocale in localeData.label\n ) {\n localeInfo = localeData.label[defaultLocale]\n }\n\n const prompts = await assignPrompt(action, {\n type: String(instructions['field-type']),\n actionParams,\n collection: collectionName,\n context: contextData,\n field: fieldName || '',\n layout: instructions.layout,\n locale: localeInfo,\n pluginConfig,\n systemPrompt: instructions.system,\n template: String(promptTemplate),\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(sanitizeLog({ prompts }), `— AI Plugin: Executing text prompt on ${schemaPath}`)\n }\n\n const aiSettings = await req.payload.findGlobal({\n slug: 'ai-providers',\n })\n const { effectiveSettings: modelSettings, settingsName } = resolveEffectiveInstructionSettings({\n defaults: aiSettings?.defaults as Record<string, unknown> | undefined,\n instructions: instructions as Record<string, unknown>,\n })\n\n if (!settingsName) {\n throw new Error(`Unsupported model-id: ${instructions['model-id']}`)\n }\n\n // Build per-field JSON schema for structured generation when applicable\n let jsonSchema = allowedEditorSchema\n let targetField: Field | null | undefined\n\n try {\n const targetCollection = req.payload.config.collections.find((c) => c.slug === collectionName)\n if (targetCollection && fieldName) {\n targetField = getFieldBySchemaPath(targetCollection, schemaPath)\n const supported = [\n 'array',\n 'text',\n 'textarea',\n 'select',\n 'number',\n 'date',\n 'code',\n 'email',\n 'json',\n ]\n const t = String(targetField?.type || '')\n if (targetField && supported.includes(t)) {\n // For array fields, use count from array-settings if available\n if (t === 'array') {\n const count = (modelSettings.count as number) || 3\n // Override the field's maxRows with the requested count\n const modifiedField = {\n ...targetField,\n maxRows: count,\n minRows: count,\n } as typeof targetField\n jsonSchema = fieldToJsonSchema(modifiedField, { nameOverride: fieldName })\n } else {\n jsonSchema = fieldToJsonSchema(targetField, { nameOverride: fieldName })\n }\n }\n }\n } catch (e) {\n req.payload.logger.error(e, '— AI Plugin: Error building field JSON schema')\n }\n\n // Resolve @field:filename references from the prompt\n const { images: resolvedImages, processedPrompt } = await resolveImageReferences(\n prompts.prompt,\n contextData,\n req,\n collectionName,\n )\n\n // Extract hardcoded URLs from the processed prompt\n const hardcodedImages = extractImageData(processedPrompt)\n\n // Combine images\n const allImages = [...hardcodedImages, ...resolvedImages] as FetchableImage[]\n\n let images: ImagePart[] | undefined\n\n if (allImages.length > 0) {\n const imageParts = await fetchImages(req, allImages)\n\n if (imageParts.length > 0) {\n images = imageParts\n }\n }\n\n let promptToUse = processedPrompt\n let systemToUse = prompts.system\n\n // Execute beforeGenerate hooks\n if (targetField && (targetField as any).custom?.ai?.beforeGenerate) {\n const beforeHooks = (targetField as any).custom.ai.beforeGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of beforeHooks) {\n const result = await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n prompt: promptToUse,\n req,\n system: systemToUse,\n })\n\n if (result) {\n if (result.prompt) {promptToUse = result.prompt}\n if (result.system) {systemToUse = result.system}\n }\n }\n }\n\n const generateParams = {\n images,\n maxTokens: modelSettings.maxTokens as number | undefined,\n model: modelSettings.model as string,\n prompt: promptToUse,\n provider: modelSettings.provider as string,\n providerOptions: modelSettings,\n\n schema: jsonSchema,\n system: systemToUse,\n temperature: modelSettings.temperature as number | undefined,\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog(generateParams),\n '— AI Plugin: Final generation parameters for text/rich-text',\n )\n }\n\n const streamResult = await req.payload.ai.streamObject({\n ...generateParams,\n onFinish: async ({ object }) => {\n if (targetField && (targetField as any).custom?.ai?.afterGenerate) {\n const afterHooks = (targetField as any).custom.ai.afterGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of afterHooks) {\n await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n req,\n result: object,\n })\n }\n }\n },\n })\n\n return streamResult\n } catch (error) {\n req.payload.logger.error(error, '— AI Plugin: Error generating text content:')\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as Error).message\n : String(error)\n return new Response(JSON.stringify({ error: message }), {\n headers: { 'Content-Type': 'application/json' },\n status:\n message.includes('Authentication required') || message.includes('Insufficient permissions')\n ? 401\n : 500,\n })\n }\n}\n"],"names":["checkAccess","filterEditorSchemaByNodes","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","registerEditorHelper","resolveEffectiveInstructionSettings","assignPrompt","buildSmartPrompt","isGenericPrompt","fieldToJsonSchema","getFieldBySchemaPath","extractImageData","fetchImages","resolveImageReferences","lexicalToPromptTemplate","sanitizeLog","generateHandler","pluginConfig","req","data","json","allowedEditorNodes","locale","options","action","actionParams","instructionId","contextData","doc","Error","instructions","payload","findByID","id","collection","collections","config","find","slug","defaultLocale","locales","localization","translateFromDefault","schemaPath","String","parts","split","collectionName","originalDoc","e","logger","error","custom","editorConfig","admin","schema","editorSchema","prompt","promptTemplate","documentData","debugging","info","smartPrompt","allowedEditorSchema","length","receivedNodes","remainingDefinitions","Object","keys","definitions","fieldName","localeData","l","code","localeInfo","label","prompts","type","context","field","layout","systemPrompt","system","template","aiSettings","findGlobal","effectiveSettings","modelSettings","settingsName","defaults","jsonSchema","targetField","targetCollection","c","supported","t","includes","count","modifiedField","maxRows","minRows","nameOverride","images","resolvedImages","processedPrompt","hardcodedImages","allImages","imageParts","promptToUse","systemToUse","ai","beforeGenerate","beforeHooks","hook","result","headers","generateParams","maxTokens","model","provider","providerOptions","temperature","streamResult","streamObject","onFinish","object","afterGenerate","afterHooks","message","Response","JSON","stringify","status"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/generate.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { Field, PayloadRequest } from 'payload'\n\nimport type { PluginConfig } from '../types.js'\n\nimport { checkAccess } from '../access/checkAccess.js'\nimport { filterEditorSchemaByNodes } from '../ai/utilities/filterEditorSchemaByNodes.js'\nimport { PLUGIN_INSTRUCTIONS_TABLE, PLUGIN_NAME } from '../defaults.js'\nimport { resolveEffectiveInstructionSettings } from '../utilities/ai/resolveEffectiveInstructionSettings.js'\nimport { assignPrompt } from '../utilities/buildPromptUtils.js'\nimport { buildSmartPrompt, isGenericPrompt } from '../utilities/buildSmartPrompt.js'\nimport { fieldToJsonSchema } from '../utilities/fields/fieldToJsonSchema.js'\nimport { getFieldBySchemaPath } from '../utilities/fields/getFieldBySchemaPath.js'\nimport { extractImageData } from '../utilities/images/extractImageData.js'\nimport { type FetchableImage, fetchImages } from '../utilities/images/fetchImages.js'\nimport { resolveImageReferences } from '../utilities/images/resolveImageReferences.js'\nimport { lexicalToPromptTemplate } from '../utilities/lexical/lexicalToPromptTemplate.js'\nimport { sanitizeLog } from '../utilities/sanitizeLog.js'\n\n/**\n * Text/rich-text generation endpoint handler.\n * Uses payload.ai.streamObject for structured text generation.\n */\nexport const generateHandler = (pluginConfig: PluginConfig) => async (req: PayloadRequest) => {\n try {\n // Check authentication and authorization first\n await checkAccess(req, pluginConfig)\n\n const data = await req.json?.()\n\n const { allowedEditorNodes = [], locale = 'en', options } = data\n const { action, actionParams, instructionId } = options\n let 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, or try again`,\n )\n }\n\n // Verify user has access to the specific instruction\n const instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n req, // Pass req to ensure access control is applied\n })\n\n const { collections } = req.payload.config\n const collection = collections.find(\n (collection) => collection.slug === PLUGIN_INSTRUCTIONS_TABLE,\n )\n\n if (!collection) {\n throw new Error('Collection not found')\n }\n\n const { defaultLocale, locales = [] } = req.payload.config.localization || {}\n\n // If translating from default locale, we need to fetch the original content\n if (action === 'Translate' && actionParams?.translateFromDefault && contextData?.id) {\n try {\n const schemaPath = String(instructions['schema-path'])\n const parts = (schemaPath || '').split('.') || []\n const collectionName = parts[0]\n\n if (collectionName && defaultLocale) {\n const originalDoc = await req.payload.findByID({\n id: contextData.id,\n collection: collectionName as any,\n locale: defaultLocale,\n req,\n })\n if (originalDoc) {\n contextData = { ...contextData, ...originalDoc }\n }\n }\n } catch (e) {\n req.payload.logger.error(\n e,\n '— AI Plugin: Error fetching default locale document for translation',\n )\n }\n }\n\n const { custom: { [PLUGIN_NAME]: { editorConfig = {} } = {} } = {} } = collection.admin\n const { schema: editorSchema = {} } = editorConfig\n let { prompt: promptTemplate = '' } = instructions\n\n // Convert Lexical JSON to string template if needed\n if (promptTemplate && typeof promptTemplate === 'object') {\n promptTemplate = lexicalToPromptTemplate(promptTemplate)\n }\n\n // Smart fallback: if prompt is generic, build a contextual prompt from field metadata\n if (isGenericPrompt(promptTemplate)) {\n const schemaPath = String(instructions['schema-path'])\n promptTemplate = buildSmartPrompt({\n documentData: contextData,\n payload: req.payload,\n schemaPath,\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog({ smartPrompt: promptTemplate }),\n `— AI Plugin: Using smart fallback prompt for ${schemaPath}`,\n )\n }\n }\n\n let allowedEditorSchema = editorSchema\n if (allowedEditorNodes.length) {\n allowedEditorSchema = filterEditorSchemaByNodes(editorSchema, allowedEditorNodes)\n // Debug: Log what nodes were received and what definitions remain\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog({\n receivedNodes: allowedEditorNodes,\n remainingDefinitions: Object.keys(allowedEditorSchema.definitions || {}),\n }),\n '— AI Plugin: Schema filtering debug',\n )\n }\n }\n\n const schemaPath = String(instructions['schema-path'])\n const parts = (schemaPath || '').split('.') || []\n const collectionName = parts[0]\n const fieldName = parts.length > 1 ? parts[parts.length - 1] : ''\n\n const localeData = locales.find((l) => {\n return l.code === locale\n })\n\n let localeInfo = locale\n if (\n localeData &&\n defaultLocale &&\n localeData.label &&\n typeof localeData.label === 'object' &&\n defaultLocale in localeData.label\n ) {\n localeInfo = localeData.label[defaultLocale]\n }\n\n const prompts = await assignPrompt(action, {\n type: String(instructions['field-type']),\n actionParams,\n collection: collectionName,\n context: contextData,\n field: fieldName || '',\n layout: instructions.layout,\n locale: localeInfo,\n pluginConfig,\n systemPrompt: instructions.system,\n templateRuntime: {\n payload: req.payload,\n schemaPath,\n },\n template: String(promptTemplate),\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(sanitizeLog({ prompts }), `— AI Plugin: Executing text prompt on ${schemaPath}`)\n }\n\n const aiSettings = await req.payload.findGlobal({\n slug: 'ai-providers',\n })\n const { effectiveSettings: modelSettings, settingsName } = resolveEffectiveInstructionSettings({\n defaults: aiSettings?.defaults as Record<string, unknown> | undefined,\n instructions: instructions as Record<string, unknown>,\n })\n\n if (!settingsName) {\n throw new Error(`Unsupported model-id: ${instructions['model-id']}`)\n }\n\n // Build per-field JSON schema for structured generation when applicable\n let jsonSchema = allowedEditorSchema\n let targetField: Field | null | undefined\n\n try {\n const targetCollection = req.payload.config.collections.find((c) => c.slug === collectionName)\n if (targetCollection && fieldName) {\n targetField = getFieldBySchemaPath(targetCollection, schemaPath)\n const supported = [\n 'array',\n 'text',\n 'textarea',\n 'select',\n 'number',\n 'date',\n 'code',\n 'email',\n 'json',\n ]\n const t = String(targetField?.type || '')\n if (targetField && supported.includes(t)) {\n // For array fields, use count from array-settings if available\n if (t === 'array') {\n const count = (modelSettings.count as number) || 3\n // Override the field's maxRows with the requested count\n const modifiedField = {\n ...targetField,\n maxRows: count,\n minRows: count,\n } as typeof targetField\n jsonSchema = fieldToJsonSchema(modifiedField, { nameOverride: fieldName })\n } else {\n jsonSchema = fieldToJsonSchema(targetField, { nameOverride: fieldName })\n }\n }\n }\n } catch (e) {\n req.payload.logger.error(e, '— AI Plugin: Error building field JSON schema')\n }\n\n // Resolve @field:filename references from the prompt\n const { images: resolvedImages, processedPrompt } = await resolveImageReferences(\n prompts.prompt,\n contextData,\n req,\n collectionName,\n )\n\n // Extract hardcoded URLs from the processed prompt\n const hardcodedImages = extractImageData(processedPrompt)\n\n // Combine images\n const allImages = [...hardcodedImages, ...resolvedImages] as FetchableImage[]\n\n let images: ImagePart[] | undefined\n\n if (allImages.length > 0) {\n const imageParts = await fetchImages(req, allImages)\n\n if (imageParts.length > 0) {\n images = imageParts\n }\n }\n\n let promptToUse = processedPrompt\n let systemToUse = prompts.system\n\n // Execute beforeGenerate hooks\n if (targetField && (targetField as any).custom?.ai?.beforeGenerate) {\n const beforeHooks = (targetField as any).custom.ai.beforeGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of beforeHooks) {\n const result = await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n prompt: promptToUse,\n req,\n system: systemToUse,\n })\n\n if (result) {\n if (result.prompt) {promptToUse = result.prompt}\n if (result.system) {systemToUse = result.system}\n }\n }\n }\n\n const generateParams = {\n images,\n maxTokens: modelSettings.maxTokens as number | undefined,\n model: modelSettings.model as string,\n prompt: promptToUse,\n provider: modelSettings.provider as string,\n providerOptions: modelSettings,\n\n schema: jsonSchema,\n system: systemToUse,\n temperature: modelSettings.temperature as number | undefined,\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog(generateParams),\n '— AI Plugin: Final generation parameters for text/rich-text',\n )\n }\n\n const streamResult = await req.payload.ai.streamObject({\n ...generateParams,\n onFinish: async ({ object }) => {\n if (targetField && (targetField as any).custom?.ai?.afterGenerate) {\n const afterHooks = (targetField as any).custom.ai.afterGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of afterHooks) {\n await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n req,\n result: object,\n })\n }\n }\n },\n })\n\n return streamResult\n } catch (error) {\n req.payload.logger.error(error, '— AI Plugin: Error generating text content:')\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as Error).message\n : String(error)\n return new Response(JSON.stringify({ error: message }), {\n headers: { 'Content-Type': 'application/json' },\n status:\n message.includes('Authentication required') || message.includes('Insufficient permissions')\n ? 401\n : 500,\n })\n }\n}\n"],"names":["checkAccess","filterEditorSchemaByNodes","PLUGIN_INSTRUCTIONS_TABLE","PLUGIN_NAME","resolveEffectiveInstructionSettings","assignPrompt","buildSmartPrompt","isGenericPrompt","fieldToJsonSchema","getFieldBySchemaPath","extractImageData","fetchImages","resolveImageReferences","lexicalToPromptTemplate","sanitizeLog","generateHandler","pluginConfig","req","data","json","allowedEditorNodes","locale","options","action","actionParams","instructionId","contextData","doc","Error","instructions","payload","findByID","id","collection","collections","config","find","slug","defaultLocale","locales","localization","translateFromDefault","schemaPath","String","parts","split","collectionName","originalDoc","e","logger","error","custom","editorConfig","admin","schema","editorSchema","prompt","promptTemplate","documentData","debugging","info","smartPrompt","allowedEditorSchema","length","receivedNodes","remainingDefinitions","Object","keys","definitions","fieldName","localeData","l","code","localeInfo","label","prompts","type","context","field","layout","systemPrompt","system","templateRuntime","template","aiSettings","findGlobal","effectiveSettings","modelSettings","settingsName","defaults","jsonSchema","targetField","targetCollection","c","supported","t","includes","count","modifiedField","maxRows","minRows","nameOverride","images","resolvedImages","processedPrompt","hardcodedImages","allImages","imageParts","promptToUse","systemToUse","ai","beforeGenerate","beforeHooks","hook","result","headers","generateParams","maxTokens","model","provider","providerOptions","temperature","streamResult","streamObject","onFinish","object","afterGenerate","afterHooks","message","Response","JSON","stringify","status"],"mappings":"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"}
|
package/dist/endpoints/upload.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { PLUGIN_AI_JOBS_TABLE, PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK, PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js';
|
|
2
|
-
import {
|
|
3
|
-
import { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js';
|
|
2
|
+
import { renderTemplate } from '../libraries/templates/renderTemplate.js';
|
|
4
3
|
import { resolveEffectiveInstructionSettings } from '../utilities/ai/resolveEffectiveInstructionSettings.js';
|
|
5
4
|
import { extendContextWithPromptFields } from '../utilities/buildPromptUtils.js';
|
|
6
5
|
import { buildSmartPrompt, isGenericPrompt } from '../utilities/buildSmartPrompt.js';
|
|
@@ -58,7 +57,6 @@ import { sanitizeLog } from '../utilities/sanitizeLog.js';
|
|
|
58
57
|
}
|
|
59
58
|
const { images: sampleImages = [] } = instructions;
|
|
60
59
|
const schemaPath = String(instructions['schema-path']);
|
|
61
|
-
registerEditorHelper(req.payload, schemaPath);
|
|
62
60
|
// Smart fallback: if prompt is generic, build a contextual prompt from field metadata
|
|
63
61
|
if (isGenericPrompt(promptTemplate)) {
|
|
64
62
|
promptTemplate = buildSmartPrompt({
|
|
@@ -75,7 +73,10 @@ import { sanitizeLog } from '../utilities/sanitizeLog.js';
|
|
|
75
73
|
const extendedContext = extendContextWithPromptFields(contextData, {
|
|
76
74
|
type: String(instructions['field-type']),
|
|
77
75
|
collection: collectionSlug
|
|
78
|
-
}, pluginConfig
|
|
76
|
+
}, pluginConfig, {
|
|
77
|
+
payload: req.payload,
|
|
78
|
+
schemaPath
|
|
79
|
+
});
|
|
79
80
|
if (pluginConfig.debugging) {
|
|
80
81
|
req.payload.logger.info(sanitizeLog({
|
|
81
82
|
contextDataKeys: Object.keys(contextData),
|
|
@@ -84,9 +85,12 @@ import { sanitizeLog } from '../utilities/sanitizeLog.js';
|
|
|
84
85
|
typeof v === 'object' ? `[object]` : v
|
|
85
86
|
])),
|
|
86
87
|
promptTemplate
|
|
87
|
-
}), `— AI Plugin: DEBUG upload context before
|
|
88
|
+
}), `— AI Plugin: DEBUG upload context before template rendering`);
|
|
88
89
|
}
|
|
89
|
-
const text = await
|
|
90
|
+
const text = await renderTemplate(promptTemplate, extendedContext, {
|
|
91
|
+
payload: req.payload,
|
|
92
|
+
schemaPath
|
|
93
|
+
});
|
|
90
94
|
const uploadCollectionSlug = instructions['relation-to'];
|
|
91
95
|
// Resolve @field:filename references from the prompt
|
|
92
96
|
const { images: resolvedImages, processedPrompt } = await resolveImageReferences(text, contextData, req, collectionSlug);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/upload.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { Field, PayloadRequest } from 'payload'\n\nimport type { PluginConfig } from '../types.js'\n\nimport { checkAccess } from '../access/checkAccess.js'\nimport {\n PLUGIN_AI_JOBS_TABLE,\n PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK,\n PLUGIN_INSTRUCTIONS_TABLE,\n} from '../defaults.js'\nimport { registerEditorHelper } from '../libraries/handlebars/helpers.js'\nimport { replacePlaceholders } from '../libraries/handlebars/replacePlaceholders.js'\nimport { resolveEffectiveInstructionSettings } from '../utilities/ai/resolveEffectiveInstructionSettings.js'\nimport { extendContextWithPromptFields } from '../utilities/buildPromptUtils.js'\nimport { buildSmartPrompt, isGenericPrompt } from '../utilities/buildSmartPrompt.js'\nimport { getFieldBySchemaPath } from '../utilities/fields/getFieldBySchemaPath.js'\nimport { extractImageData } from '../utilities/images/extractImageData.js'\nimport { type FetchableImage, fetchImages } from '../utilities/images/fetchImages.js'\nimport { resolveImageReferences } from '../utilities/images/resolveImageReferences.js'\nimport { lexicalToPromptTemplate } from '../utilities/lexical/lexicalToPromptTemplate.js'\nimport { resolveServerURL } from '../utilities/runtime/resolveServerURL.js'\nimport { sanitizeLog } from '../utilities/sanitizeLog.js'\n\n/**\n * Image/video/audio upload generation endpoint handler.\n * Uses payload.ai.generateMedia for media generation.\n */\nexport const uploadHandler = (pluginConfig: PluginConfig) => async (req: PayloadRequest) => {\n try {\n // Check authentication and authorization first\n // await checkAccess(req, pluginConfig)\n const data = await req.json?.()\n\n const { collectionSlug, documentId, options } = data\n const { instructionId } = options\n let docData = {}\n\n if (documentId) {\n try {\n docData = await req.payload.findByID({\n id: documentId,\n collection: collectionSlug as string,\n draft: true,\n req, // Pass req to ensure access control is applied\n })\n } catch (e) {\n req.payload.logger.error(\n e,\n '— AI Plugin: Error fetching document, you should try again after enabling drafts for this collection',\n )\n }\n }\n\n const contextData = {\n ...docData,\n ...data.doc,\n }\n\n let instructions: Record<string, unknown> = { images: [], 'model-id': '', prompt: '' }\n\n if (instructionId) {\n // Verify user has access to the specific instruction\n instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n req, // Pass req to ensure access control is applied\n })\n }\n\n let { prompt: promptTemplate = '' } = instructions\n\n // Convert Lexical JSON to string template if needed\n if (promptTemplate && typeof promptTemplate === 'object') {\n promptTemplate = lexicalToPromptTemplate(promptTemplate)\n }\n\n const { images: sampleImages = [] } = instructions\n const schemaPath = String(instructions['schema-path'])\n registerEditorHelper(req.payload, schemaPath)\n\n // Smart fallback: if prompt is generic, build a contextual prompt from field metadata\n if (isGenericPrompt(promptTemplate as string)) {\n promptTemplate = buildSmartPrompt({\n documentData: contextData,\n payload: req.payload,\n schemaPath,\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n { smartPrompt: promptTemplate },\n `— AI Plugin: Using smart fallback prompt for ${schemaPath}`,\n )\n }\n }\n\n const extendedContext = extendContextWithPromptFields(\n contextData,\n { type: String(instructions['field-type']), collection: collectionSlug },\n pluginConfig,\n )\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog({\n contextDataKeys: Object.keys(contextData),\n contextDataSample: Object.fromEntries(\n Object.entries(contextData).map(([k, v]) => [\n k,\n typeof v === 'object' ? `[object]` : v,\n ]),\n ),\n promptTemplate,\n }),\n `— AI Plugin: DEBUG upload context before replacePlaceholders`,\n )\n }\n\n const text = await replacePlaceholders(promptTemplate as string, extendedContext)\n const uploadCollectionSlug = instructions['relation-to']\n\n // Resolve @field:filename references from the prompt\n const { images: resolvedImages, processedPrompt } = await resolveImageReferences(\n text,\n contextData,\n req,\n collectionSlug,\n )\n\n // Extract hardcoded URLs from the processed prompt and merge with resolved images and sample images\n const images = [\n ...extractImageData(processedPrompt),\n ...resolvedImages,\n ...(sampleImages as unknown[]),\n ] as FetchableImage[]\n\n // Process images - convert to ImagePart format using helper\n const editImages: ImagePart[] = await fetchImages(req, images)\n\n let promptToUse = processedPrompt\n let targetField: Field | null | undefined\n\n try {\n const targetCollection = req.payload.config.collections.find((c) => c.slug === collectionSlug)\n if (targetCollection && schemaPath) {\n targetField = getFieldBySchemaPath(targetCollection, schemaPath)\n }\n } catch (e) {\n req.payload.logger.error(e, '— AI Plugin: Error finding field for hooks')\n }\n\n if (targetField && (targetField as any).custom?.ai?.beforeGenerate) {\n const beforeHooks = (targetField as any).custom.ai.beforeGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of beforeHooks) {\n const result = await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n prompt: promptToUse,\n req,\n })\n\n if (result) {\n if (result.prompt) {\n promptToUse = result.prompt\n }\n if (result.instructions) {\n instructions = {\n ...instructions,\n ...result.instructions,\n }\n }\n }\n }\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(sanitizeLog({ text: promptToUse }), `— AI Plugin: Executing media generation`)\n }\n\n // Prepare callback URL for async jobs\n const serverURL = resolveServerURL(req)\n\n const callbackUrl = serverURL\n ? `${serverURL.replace(/\\/$/, '')}/api${PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK}?instructionId=${instructionId}`\n : undefined\n\n const modelId = instructions['model-id']\n const aiSettings = await req.payload.findGlobal({\n slug: 'ai-providers',\n context: { unsafe: true },\n })\n const { effectiveSettings: modelSettings, settingsName } = resolveEffectiveInstructionSettings({\n defaults: aiSettings?.defaults as Record<string, unknown> | undefined,\n instructions,\n })\n\n if (!settingsName) {\n throw new Error(`Unsupported model-id: ${modelId}`)\n }\n\n const generateParams = {\n callbackUrl,\n images: editImages,\n instructionId,\n model: modelSettings.model as string,\n prompt: promptToUse,\n provider: modelSettings.provider as string,\n providerOptions: modelSettings,\n ...modelSettings,\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog(generateParams),\n '— AI Plugin: Final generation parameters for media',\n )\n }\n\n // Use payload.ai.generateMedia directly! 🎉\n const result = await req.payload.ai.generateMedia(generateParams)\n\n if (targetField && (targetField as any).custom?.ai?.afterGenerate) {\n const afterHooks = (targetField as any).custom.ai.afterGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of afterHooks) {\n await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n req,\n result,\n })\n }\n }\n\n // If model returned files immediately, proceed with upload\n if (result && 'files' in result && Array.isArray(result.files) && result.files.length > 0) {\n const uploadedDocs: Array<{ alt?: string; id: number | string }> = []\n\n for (const file of result.files) {\n let assetData: { alt?: string; id: number | string }\n\n // Create a synthetic result for the single file to pass to mediaUpload\n const singleFileResult = {\n files: [file],\n }\n\n if (typeof pluginConfig.mediaUpload === 'function') {\n const uploadResult = await pluginConfig.mediaUpload(singleFileResult, {\n collection: uploadCollectionSlug as string,\n request: req,\n })\n assetData = { id: uploadResult.id, alt: (uploadResult as any).alt }\n } else {\n const created = await req.payload.create({\n collection: uploadCollectionSlug as string,\n data: { alt: text },\n file, // Pass the file object directly: { data, mimetype, name, size }\n req, // Pass req to ensure access control is applied\n })\n assetData = { id: created.id, alt: created.alt as string }\n }\n\n if (assetData.id) {\n uploadedDocs.push(assetData)\n }\n }\n\n if (uploadedDocs.length === 0) {\n req.payload.logger.error(\n 'Error uploading generated media, is your media upload function correct?',\n )\n throw new Error('Error uploading generated media!')\n }\n\n // Check if target field supports multiple values\n let hasMany = false\n if (targetField) {\n if (\n targetField.type === 'relationship' ||\n targetField.type === 'upload' ||\n targetField.type === 'select'\n ) {\n hasMany = (targetField as any).hasMany === true\n }\n }\n\n if (hasMany) {\n return new Response(\n JSON.stringify({\n result: uploadedDocs.map((d) => ({\n id: d.id,\n alt: d.alt,\n })),\n }),\n )\n }\n\n return new Response(\n JSON.stringify({\n result: {\n id: uploadedDocs[0].id,\n alt: uploadedDocs[0].alt,\n },\n }),\n )\n }\n\n // Otherwise, assume async job launch\n if (result && ('jobId' in result || 'taskId' in result)) {\n const externalTaskId = result.jobId || result.taskId\n const status = result.status || 'queued'\n const progress = result.progress ?? 0\n\n // Create AI Job doc and return only its id\n const createdJob = await req.payload.create({\n collection: PLUGIN_AI_JOBS_TABLE,\n data: {\n instructionId,\n progress,\n status,\n task_id: externalTaskId,\n },\n overrideAccess: true,\n req,\n })\n\n return new Response(JSON.stringify({ job: { id: createdJob.id } }), {\n headers: { 'Content-Type': 'application/json' },\n })\n }\n\n throw new Error('Unexpected model response.')\n } catch (error) {\n req.payload.logger.error(\n // @ts-expect-error\n error?.type || (error as Error).message,\n '— AI Plugin: Error generating media upload:',\n )\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as Error).message\n : String(error)\n return new Response(JSON.stringify({ error: message }), {\n headers: { 'Content-Type': 'application/json' },\n status:\n message.includes('Authentication required') || message.includes('Insufficient permissions')\n ? 401\n : 500,\n })\n }\n}\n"],"names":["PLUGIN_AI_JOBS_TABLE","PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK","PLUGIN_INSTRUCTIONS_TABLE","registerEditorHelper","replacePlaceholders","resolveEffectiveInstructionSettings","extendContextWithPromptFields","buildSmartPrompt","isGenericPrompt","getFieldBySchemaPath","extractImageData","fetchImages","resolveImageReferences","lexicalToPromptTemplate","resolveServerURL","sanitizeLog","uploadHandler","pluginConfig","req","data","json","collectionSlug","documentId","options","instructionId","docData","payload","findByID","id","collection","draft","e","logger","error","contextData","doc","instructions","images","prompt","promptTemplate","sampleImages","schemaPath","String","documentData","debugging","info","smartPrompt","extendedContext","type","contextDataKeys","Object","keys","contextDataSample","fromEntries","entries","map","k","v","text","uploadCollectionSlug","resolvedImages","processedPrompt","editImages","promptToUse","targetField","targetCollection","config","collections","find","c","slug","custom","ai","beforeGenerate","beforeHooks","hook","result","field","headers","serverURL","callbackUrl","replace","undefined","modelId","aiSettings","findGlobal","context","unsafe","effectiveSettings","modelSettings","settingsName","defaults","Error","generateParams","model","provider","providerOptions","generateMedia","afterGenerate","afterHooks","Array","isArray","files","length","uploadedDocs","file","assetData","singleFileResult","mediaUpload","uploadResult","request","alt","created","create","push","hasMany","Response","JSON","stringify","d","externalTaskId","jobId","taskId","status","progress","createdJob","task_id","overrideAccess","job","message","includes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/upload.ts"],"sourcesContent":["import type { ImagePart } from 'ai'\nimport type { Field, PayloadRequest } from 'payload'\n\nimport type { PluginConfig } from '../types.js'\n\nimport { checkAccess } from '../access/checkAccess.js'\nimport {\n PLUGIN_AI_JOBS_TABLE,\n PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK,\n PLUGIN_INSTRUCTIONS_TABLE,\n} from '../defaults.js'\nimport { renderTemplate } from '../libraries/templates/renderTemplate.js'\nimport { resolveEffectiveInstructionSettings } from '../utilities/ai/resolveEffectiveInstructionSettings.js'\nimport { extendContextWithPromptFields } from '../utilities/buildPromptUtils.js'\nimport { buildSmartPrompt, isGenericPrompt } from '../utilities/buildSmartPrompt.js'\nimport { getFieldBySchemaPath } from '../utilities/fields/getFieldBySchemaPath.js'\nimport { extractImageData } from '../utilities/images/extractImageData.js'\nimport { type FetchableImage, fetchImages } from '../utilities/images/fetchImages.js'\nimport { resolveImageReferences } from '../utilities/images/resolveImageReferences.js'\nimport { lexicalToPromptTemplate } from '../utilities/lexical/lexicalToPromptTemplate.js'\nimport { resolveServerURL } from '../utilities/runtime/resolveServerURL.js'\nimport { sanitizeLog } from '../utilities/sanitizeLog.js'\n\n/**\n * Image/video/audio upload generation endpoint handler.\n * Uses payload.ai.generateMedia for media generation.\n */\nexport const uploadHandler = (pluginConfig: PluginConfig) => async (req: PayloadRequest) => {\n try {\n // Check authentication and authorization first\n // await checkAccess(req, pluginConfig)\n const data = await req.json?.()\n\n const { collectionSlug, documentId, options } = data\n const { instructionId } = options\n let docData = {}\n\n if (documentId) {\n try {\n docData = await req.payload.findByID({\n id: documentId,\n collection: collectionSlug as string,\n draft: true,\n req, // Pass req to ensure access control is applied\n })\n } catch (e) {\n req.payload.logger.error(\n e,\n '— AI Plugin: Error fetching document, you should try again after enabling drafts for this collection',\n )\n }\n }\n\n const contextData = {\n ...docData,\n ...data.doc,\n }\n\n let instructions: Record<string, unknown> = { images: [], 'model-id': '', prompt: '' }\n\n if (instructionId) {\n // Verify user has access to the specific instruction\n instructions = await req.payload.findByID({\n id: instructionId,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n req, // Pass req to ensure access control is applied\n })\n }\n\n let { prompt: promptTemplate = '' } = instructions\n\n // Convert Lexical JSON to string template if needed\n if (promptTemplate && typeof promptTemplate === 'object') {\n promptTemplate = lexicalToPromptTemplate(promptTemplate)\n }\n\n const { images: sampleImages = [] } = instructions\n const schemaPath = String(instructions['schema-path'])\n\n // Smart fallback: if prompt is generic, build a contextual prompt from field metadata\n if (isGenericPrompt(promptTemplate as string)) {\n promptTemplate = buildSmartPrompt({\n documentData: contextData,\n payload: req.payload,\n schemaPath,\n })\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n { smartPrompt: promptTemplate },\n `— AI Plugin: Using smart fallback prompt for ${schemaPath}`,\n )\n }\n }\n\n const extendedContext = extendContextWithPromptFields(\n contextData,\n { type: String(instructions['field-type']), collection: collectionSlug },\n pluginConfig,\n {\n payload: req.payload,\n schemaPath,\n },\n )\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog({\n contextDataKeys: Object.keys(contextData),\n contextDataSample: Object.fromEntries(\n Object.entries(contextData).map(([k, v]) => [\n k,\n typeof v === 'object' ? `[object]` : v,\n ]),\n ),\n promptTemplate,\n }),\n `— AI Plugin: DEBUG upload context before template rendering`,\n )\n }\n\n const text = await renderTemplate(promptTemplate as string, extendedContext, {\n payload: req.payload,\n schemaPath,\n })\n const uploadCollectionSlug = instructions['relation-to']\n\n // Resolve @field:filename references from the prompt\n const { images: resolvedImages, processedPrompt } = await resolveImageReferences(\n text,\n contextData,\n req,\n collectionSlug,\n )\n\n // Extract hardcoded URLs from the processed prompt and merge with resolved images and sample images\n const images = [\n ...extractImageData(processedPrompt),\n ...resolvedImages,\n ...(sampleImages as unknown[]),\n ] as FetchableImage[]\n\n // Process images - convert to ImagePart format using helper\n const editImages: ImagePart[] = await fetchImages(req, images)\n\n let promptToUse = processedPrompt\n let targetField: Field | null | undefined\n\n try {\n const targetCollection = req.payload.config.collections.find((c) => c.slug === collectionSlug)\n if (targetCollection && schemaPath) {\n targetField = getFieldBySchemaPath(targetCollection, schemaPath)\n }\n } catch (e) {\n req.payload.logger.error(e, '— AI Plugin: Error finding field for hooks')\n }\n\n if (targetField && (targetField as any).custom?.ai?.beforeGenerate) {\n const beforeHooks = (targetField as any).custom.ai.beforeGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of beforeHooks) {\n const result = await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n prompt: promptToUse,\n req,\n })\n\n if (result) {\n if (result.prompt) {\n promptToUse = result.prompt\n }\n if (result.instructions) {\n instructions = {\n ...instructions,\n ...result.instructions,\n }\n }\n }\n }\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(sanitizeLog({ text: promptToUse }), `— AI Plugin: Executing media generation`)\n }\n\n // Prepare callback URL for async jobs\n const serverURL = resolveServerURL(req)\n\n const callbackUrl = serverURL\n ? `${serverURL.replace(/\\/$/, '')}/api${PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK}?instructionId=${instructionId}`\n : undefined\n\n const modelId = instructions['model-id']\n const aiSettings = await req.payload.findGlobal({\n slug: 'ai-providers',\n context: { unsafe: true },\n })\n const { effectiveSettings: modelSettings, settingsName } = resolveEffectiveInstructionSettings({\n defaults: aiSettings?.defaults as Record<string, unknown> | undefined,\n instructions,\n })\n\n if (!settingsName) {\n throw new Error(`Unsupported model-id: ${modelId}`)\n }\n\n const generateParams = {\n callbackUrl,\n images: editImages,\n instructionId,\n model: modelSettings.model as string,\n prompt: promptToUse,\n provider: modelSettings.provider as string,\n providerOptions: modelSettings,\n ...modelSettings,\n }\n\n if (pluginConfig.debugging) {\n req.payload.logger.info(\n sanitizeLog(generateParams),\n '— AI Plugin: Final generation parameters for media',\n )\n }\n\n // Use payload.ai.generateMedia directly! 🎉\n const result = await req.payload.ai.generateMedia(generateParams)\n\n if (targetField && (targetField as any).custom?.ai?.afterGenerate) {\n const afterHooks = (targetField as any).custom.ai.afterGenerate as Array<\n (args: any) => Promise<any>\n >\n for (const hook of afterHooks) {\n await hook({\n doc: contextData,\n field: targetField,\n headers: req.headers,\n instructions,\n payload: req.payload,\n req,\n result,\n })\n }\n }\n\n // If model returned files immediately, proceed with upload\n if (result && 'files' in result && Array.isArray(result.files) && result.files.length > 0) {\n const uploadedDocs: Array<{ alt?: string; id: number | string }> = []\n\n for (const file of result.files) {\n let assetData: { alt?: string; id: number | string }\n\n // Create a synthetic result for the single file to pass to mediaUpload\n const singleFileResult = {\n files: [file],\n }\n\n if (typeof pluginConfig.mediaUpload === 'function') {\n const uploadResult = await pluginConfig.mediaUpload(singleFileResult, {\n collection: uploadCollectionSlug as string,\n request: req,\n })\n assetData = { id: uploadResult.id, alt: (uploadResult as any).alt }\n } else {\n const created = await req.payload.create({\n collection: uploadCollectionSlug as string,\n data: { alt: text },\n file, // Pass the file object directly: { data, mimetype, name, size }\n req, // Pass req to ensure access control is applied\n })\n assetData = { id: created.id, alt: created.alt as string }\n }\n\n if (assetData.id) {\n uploadedDocs.push(assetData)\n }\n }\n\n if (uploadedDocs.length === 0) {\n req.payload.logger.error(\n 'Error uploading generated media, is your media upload function correct?',\n )\n throw new Error('Error uploading generated media!')\n }\n\n // Check if target field supports multiple values\n let hasMany = false\n if (targetField) {\n if (\n targetField.type === 'relationship' ||\n targetField.type === 'upload' ||\n targetField.type === 'select'\n ) {\n hasMany = (targetField as any).hasMany === true\n }\n }\n\n if (hasMany) {\n return new Response(\n JSON.stringify({\n result: uploadedDocs.map((d) => ({\n id: d.id,\n alt: d.alt,\n })),\n }),\n )\n }\n\n return new Response(\n JSON.stringify({\n result: {\n id: uploadedDocs[0].id,\n alt: uploadedDocs[0].alt,\n },\n }),\n )\n }\n\n // Otherwise, assume async job launch\n if (result && ('jobId' in result || 'taskId' in result)) {\n const externalTaskId = result.jobId || result.taskId\n const status = result.status || 'queued'\n const progress = result.progress ?? 0\n\n // Create AI Job doc and return only its id\n const createdJob = await req.payload.create({\n collection: PLUGIN_AI_JOBS_TABLE,\n data: {\n instructionId,\n progress,\n status,\n task_id: externalTaskId,\n },\n overrideAccess: true,\n req,\n })\n\n return new Response(JSON.stringify({ job: { id: createdJob.id } }), {\n headers: { 'Content-Type': 'application/json' },\n })\n }\n\n throw new Error('Unexpected model response.')\n } catch (error) {\n req.payload.logger.error(\n // @ts-expect-error\n error?.type || (error as Error).message,\n '— AI Plugin: Error generating media upload:',\n )\n const message =\n error && typeof error === 'object' && 'message' in error\n ? (error as Error).message\n : String(error)\n return new Response(JSON.stringify({ error: message }), {\n headers: { 'Content-Type': 'application/json' },\n status:\n message.includes('Authentication required') || message.includes('Insufficient permissions')\n ? 401\n : 500,\n })\n }\n}\n"],"names":["PLUGIN_AI_JOBS_TABLE","PLUGIN_API_ENDPOINT_VIDEOGEN_WEBHOOK","PLUGIN_INSTRUCTIONS_TABLE","renderTemplate","resolveEffectiveInstructionSettings","extendContextWithPromptFields","buildSmartPrompt","isGenericPrompt","getFieldBySchemaPath","extractImageData","fetchImages","resolveImageReferences","lexicalToPromptTemplate","resolveServerURL","sanitizeLog","uploadHandler","pluginConfig","req","data","json","collectionSlug","documentId","options","instructionId","docData","payload","findByID","id","collection","draft","e","logger","error","contextData","doc","instructions","images","prompt","promptTemplate","sampleImages","schemaPath","String","documentData","debugging","info","smartPrompt","extendedContext","type","contextDataKeys","Object","keys","contextDataSample","fromEntries","entries","map","k","v","text","uploadCollectionSlug","resolvedImages","processedPrompt","editImages","promptToUse","targetField","targetCollection","config","collections","find","c","slug","custom","ai","beforeGenerate","beforeHooks","hook","result","field","headers","serverURL","callbackUrl","replace","undefined","modelId","aiSettings","findGlobal","context","unsafe","effectiveSettings","modelSettings","settingsName","defaults","Error","generateParams","model","provider","providerOptions","generateMedia","afterGenerate","afterHooks","Array","isArray","files","length","uploadedDocs","file","assetData","singleFileResult","mediaUpload","uploadResult","request","alt","created","create","push","hasMany","Response","JSON","stringify","d","externalTaskId","jobId","taskId","status","progress","createdJob","task_id","overrideAccess","job","message","includes"],"mappings":"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"}
|
|
@@ -3,9 +3,9 @@ interface HelperFieldConfig {
|
|
|
3
3
|
field: string;
|
|
4
4
|
name: string;
|
|
5
5
|
}
|
|
6
|
-
type
|
|
6
|
+
type TemplateHelpers = {
|
|
7
7
|
[K in SupportedHelpers]: HelperFieldConfig;
|
|
8
8
|
};
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const
|
|
9
|
+
export declare const templateHelpersMap: TemplateHelpers;
|
|
10
|
+
export declare const templateHelpers: string[];
|
|
11
11
|
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const templateHelpersMap = {
|
|
2
|
+
toHTML: {
|
|
3
|
+
name: 'toHTML',
|
|
4
|
+
field: 'richText'
|
|
5
|
+
},
|
|
6
|
+
toText: {
|
|
7
|
+
name: 'toText',
|
|
8
|
+
field: '-'
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export const templateHelpers = Object.keys(templateHelpersMap);
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=helpersMap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/libraries/templates/helpersMap.ts"],"sourcesContent":["type SupportedHelpers = 'toHTML' | 'toText'\n\ninterface HelperFieldConfig {\n field: string\n name: string\n}\n\ntype TemplateHelpers = {\n [K in SupportedHelpers]: HelperFieldConfig\n}\n\nexport const templateHelpersMap: TemplateHelpers = {\n toHTML: {\n name: 'toHTML',\n field: 'richText',\n },\n toText: {\n name: 'toText',\n field: '-',\n },\n}\n\nexport const templateHelpers = Object.keys(templateHelpersMap)\n"],"names":["templateHelpersMap","toHTML","name","field","toText","templateHelpers","Object","keys"],"mappings":"AAWA,OAAO,MAAMA,qBAAsC;IACjDC,QAAQ;QACNC,MAAM;QACNC,OAAO;IACT;IACAC,QAAQ;QACNF,MAAM;QACNC,OAAO;IACT;AACF,EAAC;AAED,OAAO,MAAME,kBAAkBC,OAAOC,IAAI,CAACP,oBAAmB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const convertLegacyTemplateToLiquid: (template: string) => string;
|
|
2
|
+
export declare const convertLiquidTemplateToLegacySuggestions: (value: string) => string;
|
|
3
|
+
export declare const isLegacyBlockExpression: (value: string) => boolean;
|
|
4
|
+
export declare const isLiquidBlockExpression: (value: string) => boolean;
|
|
5
|
+
export declare const usesLegacyToHTMLHelper: (value: string) => boolean;
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
const RESERVED_VALUES = new Set([
|
|
2
|
+
'blank',
|
|
3
|
+
'empty',
|
|
4
|
+
'false',
|
|
5
|
+
'nil',
|
|
6
|
+
'null',
|
|
7
|
+
'true'
|
|
8
|
+
]);
|
|
9
|
+
const PATH_PATTERN = /^[A-Za-z_][\w-]*(?:\.[A-Za-z0-9_-]+)*$/;
|
|
10
|
+
const TOKEN_PATTERN = /(?:\.\.\/)*[@A-Za-z_][\w@./-]*/g;
|
|
11
|
+
const normalizeNestedTemplateBraces = (template)=>{
|
|
12
|
+
return template.replace(/(\{\{[^{}]*)\{\{([^}]+)\}\}(.*?\}\})/g, '$1$2$3');
|
|
13
|
+
};
|
|
14
|
+
const sanitizeLegacyFieldMentions = (template)=>{
|
|
15
|
+
return template.replace(/\{\{\s*#\s*(?!if\b|unless\b|each\b|with\b)([\w.-]+)\s*\}\}/g, '{{ $1 }}');
|
|
16
|
+
};
|
|
17
|
+
const splitOutsideQuotes = (value, transformChunk)=>{
|
|
18
|
+
let output = '';
|
|
19
|
+
let current = '';
|
|
20
|
+
let quote = null;
|
|
21
|
+
for(let i = 0; i < value.length; i++){
|
|
22
|
+
const char = value[i];
|
|
23
|
+
if (quote) {
|
|
24
|
+
current += char;
|
|
25
|
+
if (char === quote && value[i - 1] !== '\\') {
|
|
26
|
+
quote = null;
|
|
27
|
+
}
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (char === '"' || char === "'") {
|
|
31
|
+
output += transformChunk(current);
|
|
32
|
+
current = char;
|
|
33
|
+
quote = char;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
current += char;
|
|
37
|
+
}
|
|
38
|
+
output += transformChunk(current);
|
|
39
|
+
return output;
|
|
40
|
+
};
|
|
41
|
+
const resolveScopeFrame = (frames, parentDepth = 0)=>{
|
|
42
|
+
const offset = Math.max(frames.length - parentDepth, 0);
|
|
43
|
+
for(let i = offset - 1; i >= 0; i--){
|
|
44
|
+
const frame = frames[i];
|
|
45
|
+
if (frame.scopeVar) {
|
|
46
|
+
return frame;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
};
|
|
51
|
+
const extractParentDepth = (expression)=>{
|
|
52
|
+
let depth = 0;
|
|
53
|
+
let value = expression;
|
|
54
|
+
while(value.startsWith('../')){
|
|
55
|
+
depth += 1;
|
|
56
|
+
value = value.slice(3);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
depth,
|
|
60
|
+
value
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
const mapSpecialLoopTokens = (expression, frame)=>{
|
|
64
|
+
if (!frame?.scopeVar || frame.type !== 'each') {
|
|
65
|
+
return expression;
|
|
66
|
+
}
|
|
67
|
+
if (expression === '.' || expression === 'this') {
|
|
68
|
+
return frame.scopeVar;
|
|
69
|
+
}
|
|
70
|
+
if (expression.startsWith('this.')) {
|
|
71
|
+
return `${frame.scopeVar}.${expression.slice(5)}`;
|
|
72
|
+
}
|
|
73
|
+
if (expression === '@index') {
|
|
74
|
+
return 'forloop.index0';
|
|
75
|
+
}
|
|
76
|
+
if (expression === '@first') {
|
|
77
|
+
return 'forloop.first';
|
|
78
|
+
}
|
|
79
|
+
if (expression === '@last') {
|
|
80
|
+
return 'forloop.last';
|
|
81
|
+
}
|
|
82
|
+
return expression;
|
|
83
|
+
};
|
|
84
|
+
const shouldPrefixWithScope = (expression)=>{
|
|
85
|
+
if (!PATH_PATTERN.test(expression)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (RESERVED_VALUES.has(expression)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
};
|
|
93
|
+
const transformSimpleExpression = (expression, frames)=>{
|
|
94
|
+
const trimmed = expression.trim();
|
|
95
|
+
if (!trimmed) {
|
|
96
|
+
return trimmed;
|
|
97
|
+
}
|
|
98
|
+
const { depth, value } = extractParentDepth(trimmed);
|
|
99
|
+
const scopedFrame = resolveScopeFrame(frames, depth);
|
|
100
|
+
const mapped = mapSpecialLoopTokens(value, scopedFrame);
|
|
101
|
+
if (!scopedFrame?.scopeVar) {
|
|
102
|
+
return mapped;
|
|
103
|
+
}
|
|
104
|
+
if (mapped.startsWith('forloop.')) {
|
|
105
|
+
return mapped;
|
|
106
|
+
}
|
|
107
|
+
if (mapped.startsWith(`${scopedFrame.scopeVar}.`) || mapped === scopedFrame.scopeVar) {
|
|
108
|
+
return mapped;
|
|
109
|
+
}
|
|
110
|
+
if (!shouldPrefixWithScope(mapped)) {
|
|
111
|
+
return mapped;
|
|
112
|
+
}
|
|
113
|
+
return `${scopedFrame.scopeVar}.${mapped}`;
|
|
114
|
+
};
|
|
115
|
+
const transformConditionExpression = (expression, frames)=>{
|
|
116
|
+
const operatorNormalized = expression.replace(/!==/g, '!=').replace(/===/g, '==').replace(/&&/g, ' and ').replace(/\|\|/g, ' or ');
|
|
117
|
+
return splitOutsideQuotes(operatorNormalized, (chunk)=>{
|
|
118
|
+
return chunk.replace(TOKEN_PATTERN, (token)=>{
|
|
119
|
+
if (RESERVED_VALUES.has(token)) {
|
|
120
|
+
return token;
|
|
121
|
+
}
|
|
122
|
+
if (token === 'and' || token === 'or' || token === 'contains') {
|
|
123
|
+
return token;
|
|
124
|
+
}
|
|
125
|
+
return transformSimpleExpression(token, frames);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
const rewriteOutputExpressions = (segment, frames)=>{
|
|
130
|
+
return segment.replace(/\{\{\s*([^}]+)\s*\}\}/g, (_full, expression)=>{
|
|
131
|
+
const trimmed = expression.trim();
|
|
132
|
+
if (trimmed.startsWith('toHTML ')) {
|
|
133
|
+
const fieldExpression = trimmed.slice('toHTML'.length).trim();
|
|
134
|
+
const transformed = transformSimpleExpression(fieldExpression, frames);
|
|
135
|
+
const escapedFieldExpression = fieldExpression.replace(/'/g, "\\'");
|
|
136
|
+
return `{{ ${transformed} | toHTML: '${escapedFieldExpression}' }}`;
|
|
137
|
+
}
|
|
138
|
+
if (trimmed.startsWith('toText ')) {
|
|
139
|
+
const fieldExpression = trimmed.slice('toText'.length).trim();
|
|
140
|
+
const transformed = transformSimpleExpression(fieldExpression, frames);
|
|
141
|
+
return `{{ ${transformed} }}`;
|
|
142
|
+
}
|
|
143
|
+
const transformedExpression = transformSimpleExpression(trimmed, frames);
|
|
144
|
+
return `{{ ${transformedExpression} }}`;
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const closeFrame = (frame)=>{
|
|
148
|
+
switch(frame.type){
|
|
149
|
+
case 'each':
|
|
150
|
+
return '{% endfor %}';
|
|
151
|
+
case 'if':
|
|
152
|
+
return '{% endif %}';
|
|
153
|
+
case 'unless':
|
|
154
|
+
return '{% endunless %}';
|
|
155
|
+
case 'with':
|
|
156
|
+
return '{% endif %}';
|
|
157
|
+
default:
|
|
158
|
+
return '';
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const convertBlockTag = (marker, keyword, rawExpression, frames, counters)=>{
|
|
162
|
+
if (marker === '#') {
|
|
163
|
+
if (keyword === 'if') {
|
|
164
|
+
const expression = transformConditionExpression(rawExpression.trim(), frames);
|
|
165
|
+
frames.push({
|
|
166
|
+
type: 'if'
|
|
167
|
+
});
|
|
168
|
+
return `{% if ${expression} %}`;
|
|
169
|
+
}
|
|
170
|
+
if (keyword === 'unless') {
|
|
171
|
+
const expression = transformConditionExpression(rawExpression.trim(), frames);
|
|
172
|
+
frames.push({
|
|
173
|
+
type: 'unless'
|
|
174
|
+
});
|
|
175
|
+
return `{% unless ${expression} %}`;
|
|
176
|
+
}
|
|
177
|
+
if (keyword === 'each') {
|
|
178
|
+
const expression = transformConditionExpression(rawExpression.trim(), frames);
|
|
179
|
+
const itemVar = `__item${counters.each++}`;
|
|
180
|
+
frames.push({
|
|
181
|
+
type: 'each',
|
|
182
|
+
scopeVar: itemVar
|
|
183
|
+
});
|
|
184
|
+
return `{% for ${itemVar} in ${expression} %}`;
|
|
185
|
+
}
|
|
186
|
+
if (keyword === 'with') {
|
|
187
|
+
const expression = transformConditionExpression(rawExpression.trim(), frames);
|
|
188
|
+
const withVar = `__with${counters.with++}`;
|
|
189
|
+
frames.push({
|
|
190
|
+
type: 'with',
|
|
191
|
+
scopeVar: withVar
|
|
192
|
+
});
|
|
193
|
+
return `{% assign ${withVar} = ${expression} %}{% if ${withVar} %}`;
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const closingIndex = [
|
|
198
|
+
...frames
|
|
199
|
+
].reverse().findIndex((frame)=>frame.type === keyword);
|
|
200
|
+
if (closingIndex === -1) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
const frameIndex = frames.length - 1 - closingIndex;
|
|
204
|
+
const [frame] = frames.splice(frameIndex, 1);
|
|
205
|
+
return closeFrame(frame);
|
|
206
|
+
};
|
|
207
|
+
export const convertLegacyTemplateToLiquid = (template)=>{
|
|
208
|
+
if (!template) {
|
|
209
|
+
return '';
|
|
210
|
+
}
|
|
211
|
+
const preprocessed = sanitizeLegacyFieldMentions(normalizeNestedTemplateBraces(template));
|
|
212
|
+
const blockPattern = /\{\{\s*(#|\/)\s*(if|unless|each|with)\s*([^}]*)\}\}|\{\{\s*else(?:\s+if\s+([^}]+))?\s*\}\}/g;
|
|
213
|
+
const frames = [];
|
|
214
|
+
const counters = {
|
|
215
|
+
each: 0,
|
|
216
|
+
with: 0
|
|
217
|
+
};
|
|
218
|
+
let output = '';
|
|
219
|
+
let cursor = 0;
|
|
220
|
+
for(let match = blockPattern.exec(preprocessed); match; match = blockPattern.exec(preprocessed)){
|
|
221
|
+
const [fullMatch, marker, keyword, rawExpression = '', elseIfExpression = ''] = match;
|
|
222
|
+
const segment = preprocessed.slice(cursor, match.index);
|
|
223
|
+
output += rewriteOutputExpressions(segment, frames);
|
|
224
|
+
if (marker && keyword) {
|
|
225
|
+
const converted = convertBlockTag(marker, keyword, rawExpression, frames, counters);
|
|
226
|
+
output += converted ?? fullMatch;
|
|
227
|
+
cursor = match.index + fullMatch.length;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const topFrame = frames[frames.length - 1];
|
|
231
|
+
if (!topFrame) {
|
|
232
|
+
output += fullMatch;
|
|
233
|
+
cursor = match.index + fullMatch.length;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (elseIfExpression) {
|
|
237
|
+
const condition = transformConditionExpression(elseIfExpression.trim(), frames);
|
|
238
|
+
if (topFrame.type === 'if') {
|
|
239
|
+
output += `{% elsif ${condition} %}`;
|
|
240
|
+
} else {
|
|
241
|
+
output += `{% else %}{% if ${condition} %}`;
|
|
242
|
+
frames.push({
|
|
243
|
+
type: 'if'
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
cursor = match.index + fullMatch.length;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
output += '{% else %}';
|
|
250
|
+
cursor = match.index + fullMatch.length;
|
|
251
|
+
}
|
|
252
|
+
output += rewriteOutputExpressions(preprocessed.slice(cursor), frames);
|
|
253
|
+
return output;
|
|
254
|
+
};
|
|
255
|
+
export const convertLiquidTemplateToLegacySuggestions = (value)=>{
|
|
256
|
+
if (!value) {
|
|
257
|
+
return value;
|
|
258
|
+
}
|
|
259
|
+
return value.replace(/\{\{\s*([^}|]+?)\s*\|\s*toHTML(?::\s*'([^']+)')?\s*\}\}/g, (_, lhs, rhs)=>{
|
|
260
|
+
return `{{toHTML ${(rhs || lhs).trim()}}}`;
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
export const isLegacyBlockExpression = (value)=>{
|
|
264
|
+
return /\{\{\s*#\s*(if|unless|each|with)\b/.test(value);
|
|
265
|
+
};
|
|
266
|
+
export const isLiquidBlockExpression = (value)=>{
|
|
267
|
+
return /\{\%\s*(if|unless|for)\b/.test(value);
|
|
268
|
+
};
|
|
269
|
+
export const usesLegacyToHTMLHelper = (value)=>{
|
|
270
|
+
return /\{\{\s*toHTML\s+[^}]+\}\}/.test(value);
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
//# sourceMappingURL=legacySyntax.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/libraries/templates/legacySyntax.ts"],"sourcesContent":["interface ScopeFrame {\n scopeVar?: string\n type: 'each' | 'if' | 'unless' | 'with'\n}\n\nconst RESERVED_VALUES = new Set(['blank', 'empty', 'false', 'nil', 'null', 'true'])\nconst PATH_PATTERN = /^[A-Za-z_][\\w-]*(?:\\.[A-Za-z0-9_-]+)*$/\nconst TOKEN_PATTERN = /(?:\\.\\.\\/)*[@A-Za-z_][\\w@./-]*/g\n\nconst normalizeNestedTemplateBraces = (template: string): string => {\n return template.replace(/(\\{\\{[^{}]*)\\{\\{([^}]+)\\}\\}(.*?\\}\\})/g, '$1$2$3')\n}\n\nconst sanitizeLegacyFieldMentions = (template: string): string => {\n return template.replace(\n /\\{\\{\\s*#\\s*(?!if\\b|unless\\b|each\\b|with\\b)([\\w.-]+)\\s*\\}\\}/g,\n '{{ $1 }}',\n )\n}\n\nconst splitOutsideQuotes = (\n value: string,\n transformChunk: (chunk: string) => string,\n): string => {\n let output = ''\n let current = ''\n let quote: '\"' | \"'\" | null = null\n\n for (let i = 0; i < value.length; i++) {\n const char = value[i]\n\n if (quote) {\n current += char\n if (char === quote && value[i - 1] !== '\\\\') {\n quote = null\n }\n continue\n }\n\n if (char === '\"' || char === \"'\") {\n output += transformChunk(current)\n current = char\n quote = char\n continue\n }\n\n current += char\n }\n\n output += transformChunk(current)\n return output\n}\n\nconst resolveScopeFrame = (frames: ScopeFrame[], parentDepth = 0): ScopeFrame | undefined => {\n const offset = Math.max(frames.length - parentDepth, 0)\n for (let i = offset - 1; i >= 0; i--) {\n const frame = frames[i]\n if (frame.scopeVar) {\n return frame\n }\n }\n return undefined\n}\n\nconst extractParentDepth = (expression: string): { depth: number; value: string } => {\n let depth = 0\n let value = expression\n\n while (value.startsWith('../')) {\n depth += 1\n value = value.slice(3)\n }\n\n return { depth, value }\n}\n\nconst mapSpecialLoopTokens = (expression: string, frame: ScopeFrame | undefined): string => {\n if (!frame?.scopeVar || frame.type !== 'each') {\n return expression\n }\n\n if (expression === '.' || expression === 'this') {\n return frame.scopeVar\n }\n\n if (expression.startsWith('this.')) {\n return `${frame.scopeVar}.${expression.slice(5)}`\n }\n\n if (expression === '@index') {\n return 'forloop.index0'\n }\n\n if (expression === '@first') {\n return 'forloop.first'\n }\n\n if (expression === '@last') {\n return 'forloop.last'\n }\n\n return expression\n}\n\nconst shouldPrefixWithScope = (expression: string): boolean => {\n if (!PATH_PATTERN.test(expression)) {\n return false\n }\n\n if (RESERVED_VALUES.has(expression)) {\n return false\n }\n\n return true\n}\n\nconst transformSimpleExpression = (expression: string, frames: ScopeFrame[]): string => {\n const trimmed = expression.trim()\n if (!trimmed) {\n return trimmed\n }\n\n const { depth, value } = extractParentDepth(trimmed)\n const scopedFrame = resolveScopeFrame(frames, depth)\n const mapped = mapSpecialLoopTokens(value, scopedFrame)\n\n if (!scopedFrame?.scopeVar) {\n return mapped\n }\n\n if (mapped.startsWith('forloop.')) {\n return mapped\n }\n\n if (mapped.startsWith(`${scopedFrame.scopeVar}.`) || mapped === scopedFrame.scopeVar) {\n return mapped\n }\n\n if (!shouldPrefixWithScope(mapped)) {\n return mapped\n }\n\n return `${scopedFrame.scopeVar}.${mapped}`\n}\n\nconst transformConditionExpression = (expression: string, frames: ScopeFrame[]): string => {\n const operatorNormalized = expression\n .replace(/!==/g, '!=')\n .replace(/===/g, '==')\n .replace(/&&/g, ' and ')\n .replace(/\\|\\|/g, ' or ')\n\n return splitOutsideQuotes(operatorNormalized, (chunk) => {\n return chunk.replace(TOKEN_PATTERN, (token) => {\n if (RESERVED_VALUES.has(token)) {\n return token\n }\n\n if (token === 'and' || token === 'or' || token === 'contains') {\n return token\n }\n\n return transformSimpleExpression(token, frames)\n })\n })\n}\n\nconst rewriteOutputExpressions = (segment: string, frames: ScopeFrame[]): string => {\n return segment.replace(/\\{\\{\\s*([^}]+)\\s*\\}\\}/g, (_full, expression: string) => {\n const trimmed = expression.trim()\n\n if (trimmed.startsWith('toHTML ')) {\n const fieldExpression = trimmed.slice('toHTML'.length).trim()\n const transformed = transformSimpleExpression(fieldExpression, frames)\n const escapedFieldExpression = fieldExpression.replace(/'/g, \"\\\\'\")\n return `{{ ${transformed} | toHTML: '${escapedFieldExpression}' }}`\n }\n\n if (trimmed.startsWith('toText ')) {\n const fieldExpression = trimmed.slice('toText'.length).trim()\n const transformed = transformSimpleExpression(fieldExpression, frames)\n return `{{ ${transformed} }}`\n }\n\n const transformedExpression = transformSimpleExpression(trimmed, frames)\n return `{{ ${transformedExpression} }}`\n })\n}\n\nconst closeFrame = (frame: ScopeFrame): string => {\n switch (frame.type) {\n case 'each':\n return '{% endfor %}'\n case 'if':\n return '{% endif %}'\n case 'unless':\n return '{% endunless %}'\n case 'with':\n return '{% endif %}'\n default:\n return ''\n }\n}\n\nconst convertBlockTag = (\n marker: '#' | '/',\n keyword: string,\n rawExpression: string,\n frames: ScopeFrame[],\n counters: { each: number; with: number },\n): string | null => {\n if (marker === '#') {\n if (keyword === 'if') {\n const expression = transformConditionExpression(rawExpression.trim(), frames)\n frames.push({ type: 'if' })\n return `{% if ${expression} %}`\n }\n\n if (keyword === 'unless') {\n const expression = transformConditionExpression(rawExpression.trim(), frames)\n frames.push({ type: 'unless' })\n return `{% unless ${expression} %}`\n }\n\n if (keyword === 'each') {\n const expression = transformConditionExpression(rawExpression.trim(), frames)\n const itemVar = `__item${counters.each++}`\n frames.push({ type: 'each', scopeVar: itemVar })\n return `{% for ${itemVar} in ${expression} %}`\n }\n\n if (keyword === 'with') {\n const expression = transformConditionExpression(rawExpression.trim(), frames)\n const withVar = `__with${counters.with++}`\n frames.push({ type: 'with', scopeVar: withVar })\n return `{% assign ${withVar} = ${expression} %}{% if ${withVar} %}`\n }\n\n return null\n }\n\n const closingIndex = [...frames].reverse().findIndex((frame) => frame.type === keyword)\n if (closingIndex === -1) {\n return null\n }\n\n const frameIndex = frames.length - 1 - closingIndex\n const [frame] = frames.splice(frameIndex, 1)\n return closeFrame(frame)\n}\n\nexport const convertLegacyTemplateToLiquid = (template: string): string => {\n if (!template) {\n return ''\n }\n\n const preprocessed = sanitizeLegacyFieldMentions(normalizeNestedTemplateBraces(template))\n const blockPattern =\n /\\{\\{\\s*(#|\\/)\\s*(if|unless|each|with)\\s*([^}]*)\\}\\}|\\{\\{\\s*else(?:\\s+if\\s+([^}]+))?\\s*\\}\\}/g\n\n const frames: ScopeFrame[] = []\n const counters = { each: 0, with: 0 }\n\n let output = ''\n let cursor = 0\n\n for (let match = blockPattern.exec(preprocessed); match; match = blockPattern.exec(preprocessed)) {\n const [fullMatch, marker, keyword, rawExpression = '', elseIfExpression = ''] = match\n const segment = preprocessed.slice(cursor, match.index)\n output += rewriteOutputExpressions(segment, frames)\n\n if (marker && keyword) {\n const converted = convertBlockTag(\n marker as '#' | '/',\n keyword,\n rawExpression,\n frames,\n counters,\n )\n output += converted ?? fullMatch\n cursor = match.index + fullMatch.length\n continue\n }\n\n const topFrame = frames[frames.length - 1]\n if (!topFrame) {\n output += fullMatch\n cursor = match.index + fullMatch.length\n continue\n }\n\n if (elseIfExpression) {\n const condition = transformConditionExpression(elseIfExpression.trim(), frames)\n if (topFrame.type === 'if') {\n output += `{% elsif ${condition} %}`\n } else {\n output += `{% else %}{% if ${condition} %}`\n frames.push({ type: 'if' })\n }\n cursor = match.index + fullMatch.length\n continue\n }\n\n output += '{% else %}'\n cursor = match.index + fullMatch.length\n }\n\n output += rewriteOutputExpressions(preprocessed.slice(cursor), frames)\n\n return output\n}\n\nexport const convertLiquidTemplateToLegacySuggestions = (value: string): string => {\n if (!value) {\n return value\n }\n\n return value.replace(/\\{\\{\\s*([^}|]+?)\\s*\\|\\s*toHTML(?::\\s*'([^']+)')?\\s*\\}\\}/g, (_, lhs, rhs) => {\n return `{{toHTML ${(rhs || lhs).trim()}}}`\n })\n}\n\nexport const isLegacyBlockExpression = (value: string): boolean => {\n return /\\{\\{\\s*#\\s*(if|unless|each|with)\\b/.test(value)\n}\n\nexport const isLiquidBlockExpression = (value: string): boolean => {\n return /\\{\\%\\s*(if|unless|for)\\b/.test(value)\n}\n\nexport const usesLegacyToHTMLHelper = (value: string): boolean => {\n return /\\{\\{\\s*toHTML\\s+[^}]+\\}\\}/.test(value)\n}\n"],"names":["RESERVED_VALUES","Set","PATH_PATTERN","TOKEN_PATTERN","normalizeNestedTemplateBraces","template","replace","sanitizeLegacyFieldMentions","splitOutsideQuotes","value","transformChunk","output","current","quote","i","length","char","resolveScopeFrame","frames","parentDepth","offset","Math","max","frame","scopeVar","undefined","extractParentDepth","expression","depth","startsWith","slice","mapSpecialLoopTokens","type","shouldPrefixWithScope","test","has","transformSimpleExpression","trimmed","trim","scopedFrame","mapped","transformConditionExpression","operatorNormalized","chunk","token","rewriteOutputExpressions","segment","_full","fieldExpression","transformed","escapedFieldExpression","transformedExpression","closeFrame","convertBlockTag","marker","keyword","rawExpression","counters","push","itemVar","each","withVar","with","closingIndex","reverse","findIndex","frameIndex","splice","convertLegacyTemplateToLiquid","preprocessed","blockPattern","cursor","match","exec","fullMatch","elseIfExpression","index","converted","topFrame","condition","convertLiquidTemplateToLegacySuggestions","_","lhs","rhs","isLegacyBlockExpression","isLiquidBlockExpression","usesLegacyToHTMLHelper"],"mappings":"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"}
|