@strapi/upload 5.52.0 → 5.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/admin/future/components/TruncatedText.js +76 -0
  2. package/dist/admin/future/components/TruncatedText.js.map +1 -0
  3. package/dist/admin/future/components/TruncatedText.mjs +74 -0
  4. package/dist/admin/future/components/TruncatedText.mjs.map +1 -0
  5. package/dist/admin/future/hooks/useTracking.js +57 -0
  6. package/dist/admin/future/hooks/useTracking.js.map +1 -0
  7. package/dist/admin/future/hooks/useTracking.mjs +53 -0
  8. package/dist/admin/future/hooks/useTracking.mjs.map +1 -0
  9. package/dist/admin/future/pages/Assets/AssetsPage.js +31 -0
  10. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  11. package/dist/admin/future/pages/Assets/AssetsPage.mjs +31 -0
  12. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  13. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +9 -6
  14. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -1
  15. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +9 -6
  16. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
  17. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +21 -1
  18. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  19. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +21 -1
  20. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  21. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +3 -4
  22. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
  23. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +4 -5
  24. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  25. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +11 -1
  26. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -1
  27. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +11 -1
  28. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
  29. package/dist/admin/future/pages/Assets/components/AssetsTable.js +6 -4
  30. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
  31. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +6 -4
  32. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
  33. package/dist/admin/future/pages/Assets/components/FilterMenu.js +18 -2
  34. package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -1
  35. package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +18 -2
  36. package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -1
  37. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js +9 -7
  38. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js.map +1 -1
  39. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs +9 -7
  40. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs.map +1 -1
  41. package/dist/admin/future/pages/Assets/components/FolderFormDialog.js +12 -0
  42. package/dist/admin/future/pages/Assets/components/FolderFormDialog.js.map +1 -1
  43. package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs +12 -0
  44. package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs.map +1 -1
  45. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +21 -38
  46. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  47. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +23 -40
  48. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  49. package/dist/admin/future/pages/Assets/components/SortMenu.js +14 -0
  50. package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -1
  51. package/dist/admin/future/pages/Assets/components/SortMenu.mjs +14 -0
  52. package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -1
  53. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +5 -0
  54. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -1
  55. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +6 -1
  56. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
  57. package/dist/admin/future/pages/Assets/utils/selection.js +17 -0
  58. package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -1
  59. package/dist/admin/future/pages/Assets/utils/selection.mjs +17 -1
  60. package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -1
  61. package/dist/admin/future/services/api.js +7 -8
  62. package/dist/admin/future/services/api.js.map +1 -1
  63. package/dist/admin/future/services/api.mjs +7 -8
  64. package/dist/admin/future/services/api.mjs.map +1 -1
  65. package/dist/admin/future/services/assets.js +11 -23
  66. package/dist/admin/future/services/assets.js.map +1 -1
  67. package/dist/admin/future/services/assets.mjs +11 -23
  68. package/dist/admin/future/services/assets.mjs.map +1 -1
  69. package/dist/admin/hooks/useAIMetadataJob.js +1 -1
  70. package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
  71. package/dist/admin/hooks/useAIMetadataJob.mjs +1 -1
  72. package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -1
  73. package/dist/admin/pages/SettingsPage/SettingsPage.js +2 -2
  74. package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
  75. package/dist/admin/pages/SettingsPage/SettingsPage.mjs +2 -2
  76. package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
  77. package/dist/admin/src/future/components/TruncatedText.d.ts +32 -0
  78. package/dist/admin/src/future/hooks/useTracking.d.ts +29 -0
  79. package/dist/admin/src/future/pages/Assets/components/AssetActionsMenu.d.ts +5 -3
  80. package/dist/admin/src/future/pages/Assets/components/FolderActionsMenu.d.ts +5 -4
  81. package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +2 -0
  82. package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +10 -0
  83. package/dist/admin/src/future/services/api.d.ts +6 -7
  84. package/dist/server/controllers/admin-file.js +27 -9
  85. package/dist/server/controllers/admin-file.js.map +1 -1
  86. package/dist/server/controllers/admin-file.mjs +27 -9
  87. package/dist/server/controllers/admin-file.mjs.map +1 -1
  88. package/dist/server/controllers/admin-upload.js +24 -8
  89. package/dist/server/controllers/admin-upload.js.map +1 -1
  90. package/dist/server/controllers/admin-upload.mjs +24 -8
  91. package/dist/server/controllers/admin-upload.mjs.map +1 -1
  92. package/dist/server/routes/admin.js +41 -21
  93. package/dist/server/routes/admin.js.map +1 -1
  94. package/dist/server/routes/admin.mjs +41 -21
  95. package/dist/server/routes/admin.mjs.map +1 -1
  96. package/dist/server/services/ai-metadata.js.map +1 -1
  97. package/dist/server/services/ai-metadata.mjs.map +1 -1
  98. package/dist/server/src/controllers/admin-file.d.ts +29 -8
  99. package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
  100. package/dist/server/src/controllers/admin-upload.d.ts +20 -4
  101. package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
  102. package/dist/server/src/controllers/index.d.ts +4 -4
  103. package/dist/server/src/index.d.ts +4 -4
  104. package/dist/server/src/routes/admin.d.ts.map +1 -1
  105. package/dist/server/src/services/ai-metadata.d.ts +2 -2
  106. package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
  107. package/dist/shared/contracts/ai-metadata-jobs.d.ts +10 -32
  108. package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -1
  109. package/dist/shared/contracts/files.d.ts +10 -10
  110. package/dist/shared/contracts/files.d.ts.map +1 -1
  111. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"ai-metadata.js","sources":["../../../server/src/services/ai-metadata.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { z } from 'zod';\nimport { InputFile, File } from '../types';\nimport { Settings } from '../controllers/validation/admin/settings';\nimport { getService } from '../utils';\nimport { buildFormDataFromFiles } from '../utils/images';\nimport { AI_METADATA_CHUNK_SIZE, AI_METADATA_SUPPORTED_IMAGE_TYPES } from '../constants';\n\nimport { isAIMetadataSupportedMime } from '../../../shared/constants';\n\nimport type { UnstableGenerateAIMetadata } from '../../../shared/contracts/files';\n\nexport type AIMetadataFileResult = UnstableGenerateAIMetadata.FileResult;\n\n/**\n * Supported image types for AI metadata generation. Lives in `shared/` so the\n * admin panel gates the bulk action on exactly what the provider accepts.\n */\nconst SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;\n\nconst isSupportedImage = (file: File): boolean => isAIMetadataSupportedMime(file.mime);\n\nconst chunk = <T>(items: T[], size: number): T[][] => {\n const chunks: T[][] = [];\n\n for (let i = 0; i < items.length; i += size) {\n chunks.push(items.slice(i, i + size));\n }\n\n return chunks;\n};\n\nconst createAIMetadataService = ({ strapi }: { strapi: Core.Strapi }) => {\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return {\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings: Settings = await strapi.plugin('upload').service('upload').getSettings();\n return settings.aiMetadata ?? true;\n },\n\n async countImagesWithoutMetadata() {\n const imagesWithoutMetadataCountPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n const totalImagesPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n },\n });\n\n const [imagesWithoutMetadataCount, totalImages] = await Promise.all([\n imagesWithoutMetadataCountPromise,\n totalImagesPromise,\n ]);\n\n return { imagesWithoutMetadataCount, totalImages };\n },\n\n /**\n * Update files with AI-generated metadata\n * Shared logic used by both upload flow and retroactive processing\n */\n async updateFilesWithAIMetadata(\n files: File[],\n metadataResults: Array<{ altText: string; caption: string } | null>,\n user: { id: string | number }\n ) {\n const uploadService = strapi.plugin('upload').service('upload');\n\n await Promise.all(\n files.map(async (file, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n // Only update fields that are missing (null or empty string)\n const updateData: { alternativeText?: string; caption?: string } = {};\n\n if (!file.alternativeText || file.alternativeText === '') {\n updateData.alternativeText = aiMetadata.altText;\n }\n\n if (!file.caption || file.caption === '') {\n updateData.caption = aiMetadata.caption;\n }\n\n // Only update if there are fields to update\n if (Object.keys(updateData).length > 0) {\n await uploadService.updateFileInfo(file.id, updateData, { user });\n\n // Update in-memory file object (needed for upload flow response)\n if (updateData.alternativeText !== undefined) {\n file.alternativeText = updateData.alternativeText;\n }\n if (updateData.caption !== undefined) {\n file.caption = updateData.caption;\n }\n }\n }\n })\n );\n },\n\n /**\n * Process existing files with job tracking for progress updates\n */\n async processExistingFiles(jobId: number, user: { id: string | number }): Promise<void> {\n const jobService = getService('aiMetadataJobs');\n\n try {\n // Mark as processing\n await jobService.updateJob(jobId, { status: 'processing' });\n\n // Query all images without metadata\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n if (files.length === 0) {\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n return;\n }\n\n // Process all files at once\n const metadataResults = await this.processFiles(files);\n await this.updateFilesWithAIMetadata(files, metadataResults, user);\n\n // Mark as completed\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n } catch (error) {\n strapi.log.error('AI metadata job failed', {\n jobId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n await jobService.updateJob(jobId, {\n status: 'failed',\n completedAt: new Date(),\n });\n }\n },\n\n /**\n * Generate AI metadata for an explicit selection of files, synchronously.\n *\n * Unlike `processExistingFiles`, this does not create a job and does not\n * filter on missing metadata — the selection is what the user asked for.\n * Existing alt text / captions are still preserved by\n * `updateFilesWithAIMetadata`, so a file that already has both is reported\n * as `success` without being modified.\n *\n * Images are processed in sequential chunks so one failing chunk only\n * affects its own files; every other chunk still runs.\n *\n * @experimental\n */\n async generateForFiles(\n fileIds: Array<number | string>,\n user: { id: string | number }\n ): Promise<AIMetadataFileResult[]> {\n // `yup.strapiID()` accepts both numbers and numeric strings without\n // coercing, so normalise here — otherwise a request sending `[\"1\"]`\n // would never match the numeric ids coming back from the database.\n const normalisedIds = fileIds.map(Number);\n const uniqueIds = [...new Set(normalisedIds)];\n\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: { id: { $in: uniqueIds } },\n });\n\n const filesById = new Map(files.map((file) => [file.id, file]));\n\n // Keyed by input id so the response order matches the request order.\n const resultsById = new Map<number, AIMetadataFileResult>();\n const images: File[] = [];\n\n uniqueIds.forEach((id) => {\n const file = filesById.get(id);\n\n if (!file) {\n resultsById.set(id, { id, status: 'error', error: 'File not found' });\n return;\n }\n\n // Only the formats the AI provider understands are sent; anything else\n // (non-images, but also exotic image formats like SVG or TIFF) is\n // reported as skipped rather than failed.\n if (!isSupportedImage(file)) {\n resultsById.set(id, { id, status: 'skipped' });\n return;\n }\n\n images.push(file);\n });\n\n for (const imageChunk of chunk(images, AI_METADATA_CHUNK_SIZE)) {\n try {\n const metadataResults = await this.processFiles(imageChunk);\n await this.updateFilesWithAIMetadata(imageChunk, metadataResults, user);\n\n imageChunk.forEach((file, index) => {\n resultsById.set(file.id, {\n id: file.id,\n status: metadataResults[index] ? 'success' : 'error',\n ...(metadataResults[index]\n ? {}\n : { error: 'AI metadata generation returned no result' }),\n });\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'AI metadata generation failed';\n\n strapi.log.error('AI metadata generation failed for a chunk of files', {\n fileIds: imageChunk.map((file) => file.id),\n message,\n });\n\n imageChunk.forEach((file) => {\n resultsById.set(file.id, { id: file.id, status: 'error', error: message });\n });\n }\n }\n\n return normalisedIds.map(\n (id) => resultsById.get(id) ?? { id, status: 'error', error: 'File not processed' }\n );\n },\n\n /**\n * Processes provided files for AI metadata generation\n */\n async processFiles(files: File[]): Promise<Array<{ altText: string; caption: string } | null>> {\n if (!(await this.isEnabled()) || !aiServerUrl) {\n throw new Error('AI Metadata service is not enabled');\n }\n\n // Filter for image files only and track their original positions\n // We need to maintain the original indices so we can map AI results back correctly\n const imageFiles = files\n .map((file, index) => ({ file, originalIndex: index }))\n .filter(({ file }) => file.mime?.startsWith('image/'));\n\n // Convert filtered image files to InputFile format (uses thumbnails when available)\n const imageInputFiles = imageFiles.map(({ file }) => {\n const thumbnail = (file.formats as any)?.thumbnail;\n return {\n filepath: thumbnail?.url || file.url || '',\n mimetype: file.mime,\n originalFilename: file.name,\n size: thumbnail?.size || file.size,\n provider: file.provider,\n } as InputFile;\n });\n const createEmptyMetadataResults = (): Array<{ altText: string; caption: string } | null> =>\n Array.from({ length: files.length }, () => null);\n\n // If no image files, return sparse array with all nulls to avoid calling the AI server\n // This maintains the same array length as input files for proper index alignment\n if (imageFiles.length === 0) {\n return createEmptyMetadataResults();\n }\n\n const formData = await buildFormDataFromFiles(\n imageInputFiles,\n strapi.config.get('server.absoluteUrl'),\n strapi.log\n );\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for media metadata generation', {\n aiServerUrl,\n imageCount: imageFiles.length,\n });\n\n const res = await fetch(`${aiServerUrl}/media-library/generate-metadata`, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const errorText = await res.text();\n throw Error(`AI metadata generation failed`, { cause: errorText });\n }\n\n const responseSchema = z.object({\n results: z.array(\n z.object({\n altText: z.string(),\n caption: z.string(),\n })\n ),\n });\n\n const { results } = responseSchema.parse(await res.json());\n strapi.log.http(`AI generated metadata successfully for ${results.length} files`);\n\n // Create sparse array with results at original indices\n // Example: files=[img1, pdf, img2] -> imageFiles=[{img1, index:0}, {img2, index:2}]\n // AI results=[meta1, meta2] -> sparse=[meta1, null, meta2]\n // This ensures metadata[i] corresponds to files[i], with null for non-images\n return imageFiles.reduce((sparseResults, { originalIndex }, resultIndex) => {\n sparseResults[originalIndex] = results[resultIndex];\n return sparseResults;\n }, createEmptyMetadataResults());\n },\n };\n};\n\nexport { createAIMetadataService };\n"],"names":["SUPPORTED_IMAGE_TYPES","AI_METADATA_SUPPORTED_IMAGE_TYPES","isSupportedImage","file","isAIMetadataSupportedMime","mime","chunk","items","size","chunks","i","length","push","slice","createAIMetadataService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","isEnabled","ai","admin","settings","plugin","service","getSettings","aiMetadata","countImagesWithoutMetadata","imagesWithoutMetadataCountPromise","db","query","count","where","$in","$or","alternativeText","$null","caption","totalImagesPromise","imagesWithoutMetadataCount","totalImages","Promise","all","updateFilesWithAIMetadata","files","metadataResults","user","uploadService","map","index","updateData","altText","Object","keys","updateFileInfo","id","undefined","processExistingFiles","jobId","jobService","getService","updateJob","status","findMany","completedAt","Date","processFiles","error","log","Error","message","String","generateForFiles","fileIds","normalisedIds","Number","uniqueIds","Set","filesById","Map","resultsById","images","forEach","get","set","imageChunk","AI_METADATA_CHUNK_SIZE","imageFiles","originalIndex","filter","startsWith","imageInputFiles","thumbnail","formats","filepath","url","mimetype","originalFilename","name","provider","createEmptyMetadataResults","Array","from","formData","buildFormDataFromFiles","config","token","tokenData","getAiToken","cause","http","imageCount","res","fetch","method","body","headers","Authorization","ok","errorText","text","responseSchema","z","object","results","array","string","parse","json","reduce","sparseResults","resultIndex"],"mappings":"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"}
1
+ {"version":3,"file":"ai-metadata.js","sources":["../../../server/src/services/ai-metadata.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { z } from 'zod';\nimport { InputFile, File } from '../types';\nimport { Settings } from '../controllers/validation/admin/settings';\nimport { getService } from '../utils';\nimport { buildFormDataFromFiles } from '../utils/images';\nimport { AI_METADATA_CHUNK_SIZE, AI_METADATA_SUPPORTED_IMAGE_TYPES } from '../constants';\n\nimport { isAIMetadataSupportedMime } from '../../../shared/constants';\n\nimport type { GenerateAIMetadata } from '../../../shared/contracts/files';\n\nexport type AIMetadataFileResult = GenerateAIMetadata.FileResult;\n\n/**\n * Supported image types for AI metadata generation. Lives in `shared/` so the\n * admin panel gates the bulk action on exactly what the provider accepts.\n */\nconst SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;\n\nconst isSupportedImage = (file: File): boolean => isAIMetadataSupportedMime(file.mime);\n\nconst chunk = <T>(items: T[], size: number): T[][] => {\n const chunks: T[][] = [];\n\n for (let i = 0; i < items.length; i += size) {\n chunks.push(items.slice(i, i + size));\n }\n\n return chunks;\n};\n\nconst createAIMetadataService = ({ strapi }: { strapi: Core.Strapi }) => {\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return {\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings: Settings = await strapi.plugin('upload').service('upload').getSettings();\n return settings.aiMetadata ?? true;\n },\n\n async countImagesWithoutMetadata() {\n const imagesWithoutMetadataCountPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n const totalImagesPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n },\n });\n\n const [imagesWithoutMetadataCount, totalImages] = await Promise.all([\n imagesWithoutMetadataCountPromise,\n totalImagesPromise,\n ]);\n\n return { imagesWithoutMetadataCount, totalImages };\n },\n\n /**\n * Update files with AI-generated metadata\n * Shared logic used by both upload flow and retroactive processing\n */\n async updateFilesWithAIMetadata(\n files: File[],\n metadataResults: Array<{ altText: string; caption: string } | null>,\n user: { id: string | number }\n ) {\n const uploadService = strapi.plugin('upload').service('upload');\n\n await Promise.all(\n files.map(async (file, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n // Only update fields that are missing (null or empty string)\n const updateData: { alternativeText?: string; caption?: string } = {};\n\n if (!file.alternativeText || file.alternativeText === '') {\n updateData.alternativeText = aiMetadata.altText;\n }\n\n if (!file.caption || file.caption === '') {\n updateData.caption = aiMetadata.caption;\n }\n\n // Only update if there are fields to update\n if (Object.keys(updateData).length > 0) {\n await uploadService.updateFileInfo(file.id, updateData, { user });\n\n // Update in-memory file object (needed for upload flow response)\n if (updateData.alternativeText !== undefined) {\n file.alternativeText = updateData.alternativeText;\n }\n if (updateData.caption !== undefined) {\n file.caption = updateData.caption;\n }\n }\n }\n })\n );\n },\n\n /**\n * Process existing files with job tracking for progress updates\n */\n async processExistingFiles(jobId: number, user: { id: string | number }): Promise<void> {\n const jobService = getService('aiMetadataJobs');\n\n try {\n // Mark as processing\n await jobService.updateJob(jobId, { status: 'processing' });\n\n // Query all images without metadata\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n if (files.length === 0) {\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n return;\n }\n\n // Process all files at once\n const metadataResults = await this.processFiles(files);\n await this.updateFilesWithAIMetadata(files, metadataResults, user);\n\n // Mark as completed\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n } catch (error) {\n strapi.log.error('AI metadata job failed', {\n jobId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n await jobService.updateJob(jobId, {\n status: 'failed',\n completedAt: new Date(),\n });\n }\n },\n\n /**\n * Generate AI metadata for an explicit selection of files, synchronously.\n *\n * Unlike `processExistingFiles`, this does not create a job and does not\n * filter on missing metadata — the selection is what the user asked for.\n * Existing alt text / captions are still preserved by\n * `updateFilesWithAIMetadata`, so a file that already has both is reported\n * as `success` without being modified.\n *\n * Images are processed in sequential chunks so one failing chunk only\n * affects its own files; every other chunk still runs.\n *\n * @experimental\n */\n async generateForFiles(\n fileIds: Array<number | string>,\n user: { id: string | number }\n ): Promise<AIMetadataFileResult[]> {\n // `yup.strapiID()` accepts both numbers and numeric strings without\n // coercing, so normalise here — otherwise a request sending `[\"1\"]`\n // would never match the numeric ids coming back from the database.\n const normalisedIds = fileIds.map(Number);\n const uniqueIds = [...new Set(normalisedIds)];\n\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: { id: { $in: uniqueIds } },\n });\n\n const filesById = new Map(files.map((file) => [file.id, file]));\n\n // Keyed by input id so the response order matches the request order.\n const resultsById = new Map<number, AIMetadataFileResult>();\n const images: File[] = [];\n\n uniqueIds.forEach((id) => {\n const file = filesById.get(id);\n\n if (!file) {\n resultsById.set(id, { id, status: 'error', error: 'File not found' });\n return;\n }\n\n // Only the formats the AI provider understands are sent; anything else\n // (non-images, but also exotic image formats like SVG or TIFF) is\n // reported as skipped rather than failed.\n if (!isSupportedImage(file)) {\n resultsById.set(id, { id, status: 'skipped' });\n return;\n }\n\n images.push(file);\n });\n\n for (const imageChunk of chunk(images, AI_METADATA_CHUNK_SIZE)) {\n try {\n const metadataResults = await this.processFiles(imageChunk);\n await this.updateFilesWithAIMetadata(imageChunk, metadataResults, user);\n\n imageChunk.forEach((file, index) => {\n resultsById.set(file.id, {\n id: file.id,\n status: metadataResults[index] ? 'success' : 'error',\n ...(metadataResults[index]\n ? {}\n : { error: 'AI metadata generation returned no result' }),\n });\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'AI metadata generation failed';\n\n strapi.log.error('AI metadata generation failed for a chunk of files', {\n fileIds: imageChunk.map((file) => file.id),\n message,\n });\n\n imageChunk.forEach((file) => {\n resultsById.set(file.id, { id: file.id, status: 'error', error: message });\n });\n }\n }\n\n return normalisedIds.map(\n (id) => resultsById.get(id) ?? { id, status: 'error', error: 'File not processed' }\n );\n },\n\n /**\n * Processes provided files for AI metadata generation\n */\n async processFiles(files: File[]): Promise<Array<{ altText: string; caption: string } | null>> {\n if (!(await this.isEnabled()) || !aiServerUrl) {\n throw new Error('AI Metadata service is not enabled');\n }\n\n // Filter for image files only and track their original positions\n // We need to maintain the original indices so we can map AI results back correctly\n const imageFiles = files\n .map((file, index) => ({ file, originalIndex: index }))\n .filter(({ file }) => file.mime?.startsWith('image/'));\n\n // Convert filtered image files to InputFile format (uses thumbnails when available)\n const imageInputFiles = imageFiles.map(({ file }) => {\n const thumbnail = (file.formats as any)?.thumbnail;\n return {\n filepath: thumbnail?.url || file.url || '',\n mimetype: file.mime,\n originalFilename: file.name,\n size: thumbnail?.size || file.size,\n provider: file.provider,\n } as InputFile;\n });\n const createEmptyMetadataResults = (): Array<{ altText: string; caption: string } | null> =>\n Array.from({ length: files.length }, () => null);\n\n // If no image files, return sparse array with all nulls to avoid calling the AI server\n // This maintains the same array length as input files for proper index alignment\n if (imageFiles.length === 0) {\n return createEmptyMetadataResults();\n }\n\n const formData = await buildFormDataFromFiles(\n imageInputFiles,\n strapi.config.get('server.absoluteUrl'),\n strapi.log\n );\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for media metadata generation', {\n aiServerUrl,\n imageCount: imageFiles.length,\n });\n\n const res = await fetch(`${aiServerUrl}/media-library/generate-metadata`, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const errorText = await res.text();\n throw Error(`AI metadata generation failed`, { cause: errorText });\n }\n\n const responseSchema = z.object({\n results: z.array(\n z.object({\n altText: z.string(),\n caption: z.string(),\n })\n ),\n });\n\n const { results } = responseSchema.parse(await res.json());\n strapi.log.http(`AI generated metadata successfully for ${results.length} files`);\n\n // Create sparse array with results at original indices\n // Example: files=[img1, pdf, img2] -> imageFiles=[{img1, index:0}, {img2, index:2}]\n // AI results=[meta1, meta2] -> sparse=[meta1, null, meta2]\n // This ensures metadata[i] corresponds to files[i], with null for non-images\n return imageFiles.reduce((sparseResults, { originalIndex }, resultIndex) => {\n sparseResults[originalIndex] = results[resultIndex];\n return sparseResults;\n }, createEmptyMetadataResults());\n },\n };\n};\n\nexport { createAIMetadataService };\n"],"names":["SUPPORTED_IMAGE_TYPES","AI_METADATA_SUPPORTED_IMAGE_TYPES","isSupportedImage","file","isAIMetadataSupportedMime","mime","chunk","items","size","chunks","i","length","push","slice","createAIMetadataService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","isEnabled","ai","admin","settings","plugin","service","getSettings","aiMetadata","countImagesWithoutMetadata","imagesWithoutMetadataCountPromise","db","query","count","where","$in","$or","alternativeText","$null","caption","totalImagesPromise","imagesWithoutMetadataCount","totalImages","Promise","all","updateFilesWithAIMetadata","files","metadataResults","user","uploadService","map","index","updateData","altText","Object","keys","updateFileInfo","id","undefined","processExistingFiles","jobId","jobService","getService","updateJob","status","findMany","completedAt","Date","processFiles","error","log","Error","message","String","generateForFiles","fileIds","normalisedIds","Number","uniqueIds","Set","filesById","Map","resultsById","images","forEach","get","set","imageChunk","AI_METADATA_CHUNK_SIZE","imageFiles","originalIndex","filter","startsWith","imageInputFiles","thumbnail","formats","filepath","url","mimetype","originalFilename","name","provider","createEmptyMetadataResults","Array","from","formData","buildFormDataFromFiles","config","token","tokenData","getAiToken","cause","http","imageCount","res","fetch","method","body","headers","Authorization","ok","errorText","text","responseSchema","z","object","results","array","string","parse","json","reduce","sparseResults","resultIndex"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-metadata.mjs","sources":["../../../server/src/services/ai-metadata.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { z } from 'zod';\nimport { InputFile, File } from '../types';\nimport { Settings } from '../controllers/validation/admin/settings';\nimport { getService } from '../utils';\nimport { buildFormDataFromFiles } from '../utils/images';\nimport { AI_METADATA_CHUNK_SIZE, AI_METADATA_SUPPORTED_IMAGE_TYPES } from '../constants';\n\nimport { isAIMetadataSupportedMime } from '../../../shared/constants';\n\nimport type { UnstableGenerateAIMetadata } from '../../../shared/contracts/files';\n\nexport type AIMetadataFileResult = UnstableGenerateAIMetadata.FileResult;\n\n/**\n * Supported image types for AI metadata generation. Lives in `shared/` so the\n * admin panel gates the bulk action on exactly what the provider accepts.\n */\nconst SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;\n\nconst isSupportedImage = (file: File): boolean => isAIMetadataSupportedMime(file.mime);\n\nconst chunk = <T>(items: T[], size: number): T[][] => {\n const chunks: T[][] = [];\n\n for (let i = 0; i < items.length; i += size) {\n chunks.push(items.slice(i, i + size));\n }\n\n return chunks;\n};\n\nconst createAIMetadataService = ({ strapi }: { strapi: Core.Strapi }) => {\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return {\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings: Settings = await strapi.plugin('upload').service('upload').getSettings();\n return settings.aiMetadata ?? true;\n },\n\n async countImagesWithoutMetadata() {\n const imagesWithoutMetadataCountPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n const totalImagesPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n },\n });\n\n const [imagesWithoutMetadataCount, totalImages] = await Promise.all([\n imagesWithoutMetadataCountPromise,\n totalImagesPromise,\n ]);\n\n return { imagesWithoutMetadataCount, totalImages };\n },\n\n /**\n * Update files with AI-generated metadata\n * Shared logic used by both upload flow and retroactive processing\n */\n async updateFilesWithAIMetadata(\n files: File[],\n metadataResults: Array<{ altText: string; caption: string } | null>,\n user: { id: string | number }\n ) {\n const uploadService = strapi.plugin('upload').service('upload');\n\n await Promise.all(\n files.map(async (file, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n // Only update fields that are missing (null or empty string)\n const updateData: { alternativeText?: string; caption?: string } = {};\n\n if (!file.alternativeText || file.alternativeText === '') {\n updateData.alternativeText = aiMetadata.altText;\n }\n\n if (!file.caption || file.caption === '') {\n updateData.caption = aiMetadata.caption;\n }\n\n // Only update if there are fields to update\n if (Object.keys(updateData).length > 0) {\n await uploadService.updateFileInfo(file.id, updateData, { user });\n\n // Update in-memory file object (needed for upload flow response)\n if (updateData.alternativeText !== undefined) {\n file.alternativeText = updateData.alternativeText;\n }\n if (updateData.caption !== undefined) {\n file.caption = updateData.caption;\n }\n }\n }\n })\n );\n },\n\n /**\n * Process existing files with job tracking for progress updates\n */\n async processExistingFiles(jobId: number, user: { id: string | number }): Promise<void> {\n const jobService = getService('aiMetadataJobs');\n\n try {\n // Mark as processing\n await jobService.updateJob(jobId, { status: 'processing' });\n\n // Query all images without metadata\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n if (files.length === 0) {\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n return;\n }\n\n // Process all files at once\n const metadataResults = await this.processFiles(files);\n await this.updateFilesWithAIMetadata(files, metadataResults, user);\n\n // Mark as completed\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n } catch (error) {\n strapi.log.error('AI metadata job failed', {\n jobId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n await jobService.updateJob(jobId, {\n status: 'failed',\n completedAt: new Date(),\n });\n }\n },\n\n /**\n * Generate AI metadata for an explicit selection of files, synchronously.\n *\n * Unlike `processExistingFiles`, this does not create a job and does not\n * filter on missing metadata — the selection is what the user asked for.\n * Existing alt text / captions are still preserved by\n * `updateFilesWithAIMetadata`, so a file that already has both is reported\n * as `success` without being modified.\n *\n * Images are processed in sequential chunks so one failing chunk only\n * affects its own files; every other chunk still runs.\n *\n * @experimental\n */\n async generateForFiles(\n fileIds: Array<number | string>,\n user: { id: string | number }\n ): Promise<AIMetadataFileResult[]> {\n // `yup.strapiID()` accepts both numbers and numeric strings without\n // coercing, so normalise here — otherwise a request sending `[\"1\"]`\n // would never match the numeric ids coming back from the database.\n const normalisedIds = fileIds.map(Number);\n const uniqueIds = [...new Set(normalisedIds)];\n\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: { id: { $in: uniqueIds } },\n });\n\n const filesById = new Map(files.map((file) => [file.id, file]));\n\n // Keyed by input id so the response order matches the request order.\n const resultsById = new Map<number, AIMetadataFileResult>();\n const images: File[] = [];\n\n uniqueIds.forEach((id) => {\n const file = filesById.get(id);\n\n if (!file) {\n resultsById.set(id, { id, status: 'error', error: 'File not found' });\n return;\n }\n\n // Only the formats the AI provider understands are sent; anything else\n // (non-images, but also exotic image formats like SVG or TIFF) is\n // reported as skipped rather than failed.\n if (!isSupportedImage(file)) {\n resultsById.set(id, { id, status: 'skipped' });\n return;\n }\n\n images.push(file);\n });\n\n for (const imageChunk of chunk(images, AI_METADATA_CHUNK_SIZE)) {\n try {\n const metadataResults = await this.processFiles(imageChunk);\n await this.updateFilesWithAIMetadata(imageChunk, metadataResults, user);\n\n imageChunk.forEach((file, index) => {\n resultsById.set(file.id, {\n id: file.id,\n status: metadataResults[index] ? 'success' : 'error',\n ...(metadataResults[index]\n ? {}\n : { error: 'AI metadata generation returned no result' }),\n });\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'AI metadata generation failed';\n\n strapi.log.error('AI metadata generation failed for a chunk of files', {\n fileIds: imageChunk.map((file) => file.id),\n message,\n });\n\n imageChunk.forEach((file) => {\n resultsById.set(file.id, { id: file.id, status: 'error', error: message });\n });\n }\n }\n\n return normalisedIds.map(\n (id) => resultsById.get(id) ?? { id, status: 'error', error: 'File not processed' }\n );\n },\n\n /**\n * Processes provided files for AI metadata generation\n */\n async processFiles(files: File[]): Promise<Array<{ altText: string; caption: string } | null>> {\n if (!(await this.isEnabled()) || !aiServerUrl) {\n throw new Error('AI Metadata service is not enabled');\n }\n\n // Filter for image files only and track their original positions\n // We need to maintain the original indices so we can map AI results back correctly\n const imageFiles = files\n .map((file, index) => ({ file, originalIndex: index }))\n .filter(({ file }) => file.mime?.startsWith('image/'));\n\n // Convert filtered image files to InputFile format (uses thumbnails when available)\n const imageInputFiles = imageFiles.map(({ file }) => {\n const thumbnail = (file.formats as any)?.thumbnail;\n return {\n filepath: thumbnail?.url || file.url || '',\n mimetype: file.mime,\n originalFilename: file.name,\n size: thumbnail?.size || file.size,\n provider: file.provider,\n } as InputFile;\n });\n const createEmptyMetadataResults = (): Array<{ altText: string; caption: string } | null> =>\n Array.from({ length: files.length }, () => null);\n\n // If no image files, return sparse array with all nulls to avoid calling the AI server\n // This maintains the same array length as input files for proper index alignment\n if (imageFiles.length === 0) {\n return createEmptyMetadataResults();\n }\n\n const formData = await buildFormDataFromFiles(\n imageInputFiles,\n strapi.config.get('server.absoluteUrl'),\n strapi.log\n );\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for media metadata generation', {\n aiServerUrl,\n imageCount: imageFiles.length,\n });\n\n const res = await fetch(`${aiServerUrl}/media-library/generate-metadata`, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const errorText = await res.text();\n throw Error(`AI metadata generation failed`, { cause: errorText });\n }\n\n const responseSchema = z.object({\n results: z.array(\n z.object({\n altText: z.string(),\n caption: z.string(),\n })\n ),\n });\n\n const { results } = responseSchema.parse(await res.json());\n strapi.log.http(`AI generated metadata successfully for ${results.length} files`);\n\n // Create sparse array with results at original indices\n // Example: files=[img1, pdf, img2] -> imageFiles=[{img1, index:0}, {img2, index:2}]\n // AI results=[meta1, meta2] -> sparse=[meta1, null, meta2]\n // This ensures metadata[i] corresponds to files[i], with null for non-images\n return imageFiles.reduce((sparseResults, { originalIndex }, resultIndex) => {\n sparseResults[originalIndex] = results[resultIndex];\n return sparseResults;\n }, createEmptyMetadataResults());\n },\n };\n};\n\nexport { createAIMetadataService };\n"],"names":["SUPPORTED_IMAGE_TYPES","AI_METADATA_SUPPORTED_IMAGE_TYPES","isSupportedImage","file","isAIMetadataSupportedMime","mime","chunk","items","size","chunks","i","length","push","slice","createAIMetadataService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","isEnabled","ai","admin","settings","plugin","service","getSettings","aiMetadata","countImagesWithoutMetadata","imagesWithoutMetadataCountPromise","db","query","count","where","$in","$or","alternativeText","$null","caption","totalImagesPromise","imagesWithoutMetadataCount","totalImages","Promise","all","updateFilesWithAIMetadata","files","metadataResults","user","uploadService","map","index","updateData","altText","Object","keys","updateFileInfo","id","undefined","processExistingFiles","jobId","jobService","getService","updateJob","status","findMany","completedAt","Date","processFiles","error","log","Error","message","String","generateForFiles","fileIds","normalisedIds","Number","uniqueIds","Set","filesById","Map","resultsById","images","forEach","get","set","imageChunk","AI_METADATA_CHUNK_SIZE","imageFiles","originalIndex","filter","startsWith","imageInputFiles","thumbnail","formats","filepath","url","mimetype","originalFilename","name","provider","createEmptyMetadataResults","Array","from","formData","buildFormDataFromFiles","config","token","tokenData","getAiToken","cause","http","imageCount","res","fetch","method","body","headers","Authorization","ok","errorText","text","responseSchema","z","object","results","array","string","parse","json","reduce","sparseResults","resultIndex"],"mappings":"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"}
1
+ {"version":3,"file":"ai-metadata.mjs","sources":["../../../server/src/services/ai-metadata.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { z } from 'zod';\nimport { InputFile, File } from '../types';\nimport { Settings } from '../controllers/validation/admin/settings';\nimport { getService } from '../utils';\nimport { buildFormDataFromFiles } from '../utils/images';\nimport { AI_METADATA_CHUNK_SIZE, AI_METADATA_SUPPORTED_IMAGE_TYPES } from '../constants';\n\nimport { isAIMetadataSupportedMime } from '../../../shared/constants';\n\nimport type { GenerateAIMetadata } from '../../../shared/contracts/files';\n\nexport type AIMetadataFileResult = GenerateAIMetadata.FileResult;\n\n/**\n * Supported image types for AI metadata generation. Lives in `shared/` so the\n * admin panel gates the bulk action on exactly what the provider accepts.\n */\nconst SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;\n\nconst isSupportedImage = (file: File): boolean => isAIMetadataSupportedMime(file.mime);\n\nconst chunk = <T>(items: T[], size: number): T[][] => {\n const chunks: T[][] = [];\n\n for (let i = 0; i < items.length; i += size) {\n chunks.push(items.slice(i, i + size));\n }\n\n return chunks;\n};\n\nconst createAIMetadataService = ({ strapi }: { strapi: Core.Strapi }) => {\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return {\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings: Settings = await strapi.plugin('upload').service('upload').getSettings();\n return settings.aiMetadata ?? true;\n },\n\n async countImagesWithoutMetadata() {\n const imagesWithoutMetadataCountPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n const totalImagesPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n },\n });\n\n const [imagesWithoutMetadataCount, totalImages] = await Promise.all([\n imagesWithoutMetadataCountPromise,\n totalImagesPromise,\n ]);\n\n return { imagesWithoutMetadataCount, totalImages };\n },\n\n /**\n * Update files with AI-generated metadata\n * Shared logic used by both upload flow and retroactive processing\n */\n async updateFilesWithAIMetadata(\n files: File[],\n metadataResults: Array<{ altText: string; caption: string } | null>,\n user: { id: string | number }\n ) {\n const uploadService = strapi.plugin('upload').service('upload');\n\n await Promise.all(\n files.map(async (file, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n // Only update fields that are missing (null or empty string)\n const updateData: { alternativeText?: string; caption?: string } = {};\n\n if (!file.alternativeText || file.alternativeText === '') {\n updateData.alternativeText = aiMetadata.altText;\n }\n\n if (!file.caption || file.caption === '') {\n updateData.caption = aiMetadata.caption;\n }\n\n // Only update if there are fields to update\n if (Object.keys(updateData).length > 0) {\n await uploadService.updateFileInfo(file.id, updateData, { user });\n\n // Update in-memory file object (needed for upload flow response)\n if (updateData.alternativeText !== undefined) {\n file.alternativeText = updateData.alternativeText;\n }\n if (updateData.caption !== undefined) {\n file.caption = updateData.caption;\n }\n }\n }\n })\n );\n },\n\n /**\n * Process existing files with job tracking for progress updates\n */\n async processExistingFiles(jobId: number, user: { id: string | number }): Promise<void> {\n const jobService = getService('aiMetadataJobs');\n\n try {\n // Mark as processing\n await jobService.updateJob(jobId, { status: 'processing' });\n\n // Query all images without metadata\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n if (files.length === 0) {\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n return;\n }\n\n // Process all files at once\n const metadataResults = await this.processFiles(files);\n await this.updateFilesWithAIMetadata(files, metadataResults, user);\n\n // Mark as completed\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n } catch (error) {\n strapi.log.error('AI metadata job failed', {\n jobId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n await jobService.updateJob(jobId, {\n status: 'failed',\n completedAt: new Date(),\n });\n }\n },\n\n /**\n * Generate AI metadata for an explicit selection of files, synchronously.\n *\n * Unlike `processExistingFiles`, this does not create a job and does not\n * filter on missing metadata — the selection is what the user asked for.\n * Existing alt text / captions are still preserved by\n * `updateFilesWithAIMetadata`, so a file that already has both is reported\n * as `success` without being modified.\n *\n * Images are processed in sequential chunks so one failing chunk only\n * affects its own files; every other chunk still runs.\n *\n * @experimental\n */\n async generateForFiles(\n fileIds: Array<number | string>,\n user: { id: string | number }\n ): Promise<AIMetadataFileResult[]> {\n // `yup.strapiID()` accepts both numbers and numeric strings without\n // coercing, so normalise here — otherwise a request sending `[\"1\"]`\n // would never match the numeric ids coming back from the database.\n const normalisedIds = fileIds.map(Number);\n const uniqueIds = [...new Set(normalisedIds)];\n\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: { id: { $in: uniqueIds } },\n });\n\n const filesById = new Map(files.map((file) => [file.id, file]));\n\n // Keyed by input id so the response order matches the request order.\n const resultsById = new Map<number, AIMetadataFileResult>();\n const images: File[] = [];\n\n uniqueIds.forEach((id) => {\n const file = filesById.get(id);\n\n if (!file) {\n resultsById.set(id, { id, status: 'error', error: 'File not found' });\n return;\n }\n\n // Only the formats the AI provider understands are sent; anything else\n // (non-images, but also exotic image formats like SVG or TIFF) is\n // reported as skipped rather than failed.\n if (!isSupportedImage(file)) {\n resultsById.set(id, { id, status: 'skipped' });\n return;\n }\n\n images.push(file);\n });\n\n for (const imageChunk of chunk(images, AI_METADATA_CHUNK_SIZE)) {\n try {\n const metadataResults = await this.processFiles(imageChunk);\n await this.updateFilesWithAIMetadata(imageChunk, metadataResults, user);\n\n imageChunk.forEach((file, index) => {\n resultsById.set(file.id, {\n id: file.id,\n status: metadataResults[index] ? 'success' : 'error',\n ...(metadataResults[index]\n ? {}\n : { error: 'AI metadata generation returned no result' }),\n });\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'AI metadata generation failed';\n\n strapi.log.error('AI metadata generation failed for a chunk of files', {\n fileIds: imageChunk.map((file) => file.id),\n message,\n });\n\n imageChunk.forEach((file) => {\n resultsById.set(file.id, { id: file.id, status: 'error', error: message });\n });\n }\n }\n\n return normalisedIds.map(\n (id) => resultsById.get(id) ?? { id, status: 'error', error: 'File not processed' }\n );\n },\n\n /**\n * Processes provided files for AI metadata generation\n */\n async processFiles(files: File[]): Promise<Array<{ altText: string; caption: string } | null>> {\n if (!(await this.isEnabled()) || !aiServerUrl) {\n throw new Error('AI Metadata service is not enabled');\n }\n\n // Filter for image files only and track their original positions\n // We need to maintain the original indices so we can map AI results back correctly\n const imageFiles = files\n .map((file, index) => ({ file, originalIndex: index }))\n .filter(({ file }) => file.mime?.startsWith('image/'));\n\n // Convert filtered image files to InputFile format (uses thumbnails when available)\n const imageInputFiles = imageFiles.map(({ file }) => {\n const thumbnail = (file.formats as any)?.thumbnail;\n return {\n filepath: thumbnail?.url || file.url || '',\n mimetype: file.mime,\n originalFilename: file.name,\n size: thumbnail?.size || file.size,\n provider: file.provider,\n } as InputFile;\n });\n const createEmptyMetadataResults = (): Array<{ altText: string; caption: string } | null> =>\n Array.from({ length: files.length }, () => null);\n\n // If no image files, return sparse array with all nulls to avoid calling the AI server\n // This maintains the same array length as input files for proper index alignment\n if (imageFiles.length === 0) {\n return createEmptyMetadataResults();\n }\n\n const formData = await buildFormDataFromFiles(\n imageInputFiles,\n strapi.config.get('server.absoluteUrl'),\n strapi.log\n );\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for media metadata generation', {\n aiServerUrl,\n imageCount: imageFiles.length,\n });\n\n const res = await fetch(`${aiServerUrl}/media-library/generate-metadata`, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const errorText = await res.text();\n throw Error(`AI metadata generation failed`, { cause: errorText });\n }\n\n const responseSchema = z.object({\n results: z.array(\n z.object({\n altText: z.string(),\n caption: z.string(),\n })\n ),\n });\n\n const { results } = responseSchema.parse(await res.json());\n strapi.log.http(`AI generated metadata successfully for ${results.length} files`);\n\n // Create sparse array with results at original indices\n // Example: files=[img1, pdf, img2] -> imageFiles=[{img1, index:0}, {img2, index:2}]\n // AI results=[meta1, meta2] -> sparse=[meta1, null, meta2]\n // This ensures metadata[i] corresponds to files[i], with null for non-images\n return imageFiles.reduce((sparseResults, { originalIndex }, resultIndex) => {\n sparseResults[originalIndex] = results[resultIndex];\n return sparseResults;\n }, createEmptyMetadataResults());\n },\n };\n};\n\nexport { createAIMetadataService };\n"],"names":["SUPPORTED_IMAGE_TYPES","AI_METADATA_SUPPORTED_IMAGE_TYPES","isSupportedImage","file","isAIMetadataSupportedMime","mime","chunk","items","size","chunks","i","length","push","slice","createAIMetadataService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","isEnabled","ai","admin","settings","plugin","service","getSettings","aiMetadata","countImagesWithoutMetadata","imagesWithoutMetadataCountPromise","db","query","count","where","$in","$or","alternativeText","$null","caption","totalImagesPromise","imagesWithoutMetadataCount","totalImages","Promise","all","updateFilesWithAIMetadata","files","metadataResults","user","uploadService","map","index","updateData","altText","Object","keys","updateFileInfo","id","undefined","processExistingFiles","jobId","jobService","getService","updateJob","status","findMany","completedAt","Date","processFiles","error","log","Error","message","String","generateForFiles","fileIds","normalisedIds","Number","uniqueIds","Set","filesById","Map","resultsById","images","forEach","get","set","imageChunk","AI_METADATA_CHUNK_SIZE","imageFiles","originalIndex","filter","startsWith","imageInputFiles","thumbnail","formats","filepath","url","mimetype","originalFilename","name","provider","createEmptyMetadataResults","Array","from","formData","buildFormDataFromFiles","config","token","tokenData","getAiToken","cause","http","imageCount","res","fetch","method","body","headers","Authorization","ok","errorText","text","responseSchema","z","object","results","array","string","parse","json","reduce","sparseResults","resultIndex"],"mappings":"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"}
@@ -3,18 +3,39 @@ declare const _default: {
3
3
  find(ctx: Context): Promise<any>;
4
4
  findOne(ctx: Context): Promise<void>;
5
5
  destroy(ctx: Context): Promise<void>;
6
- getAIMetadataCount(ctx: Context): Promise<any>;
7
- generateAIMetadata(ctx: Context): Promise<any>;
8
6
  /**
9
- * Generate AI metadata for an explicit selection of files, synchronously.
7
+ * `GET /upload/ai-metadata-jobs/pending-count`
8
+ *
9
+ * How many images a backfill job would have to process, i.e. those still
10
+ * missing AI metadata, alongside the total image count.
11
+ */
12
+ getAIMetadataPendingCount(ctx: Context): Promise<any>;
13
+ /**
14
+ * `POST /upload/ai-metadata-jobs`
10
15
  *
11
- * Unlike `generateAIMetadata`, no job is created: the request resolves once
12
- * every file has been processed and reports the outcome per file, so a single
13
- * bad id or a non-image in the selection never fails the whole batch.
16
+ * Create a backfill job that generates AI metadata for every image still
17
+ * missing it, and return the job so the client can poll it. Processing runs
18
+ * detached from this request; see `generateAIMetadata` for the synchronous
19
+ * counterpart that works on an explicit selection.
20
+ */
21
+ createAIMetadataJob(ctx: Context): Promise<any>;
22
+ /**
23
+ * `POST /upload/actions/generate-ai-metadata`
24
+ *
25
+ * Generate AI metadata for the explicit selection of files in the body,
26
+ * synchronously: the request resolves once every file has been processed and
27
+ * reports the outcome per file, so a single bad id or a non-image in the
28
+ * selection never fails the whole batch.
29
+ *
30
+ * For the whole-library backfill, see `createAIMetadataJob`.
31
+ */
32
+ generateAIMetadata(ctx: Context): Promise<any>;
33
+ /**
34
+ * `GET /upload/ai-metadata-jobs/latest`
14
35
  *
15
- * @experimental
36
+ * The most recent still-active backfill job, so a client that reloads mid-run
37
+ * can pick the progress bar back up. 404s when nothing is running.
16
38
  */
17
- unstable_generateAIMetadata(ctx: Context): Promise<any>;
18
39
  getLatestAIMetadataJob(ctx: Context): Promise<any>;
19
40
  };
20
41
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"admin-file.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/admin-file.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;cAQjB,OAAO;iBAuCJ,OAAO;iBAiBP,OAAO;4BAmBI,OAAO;4BAwCP,OAAO;IA4DrC;;;;;;;;OAQG;qCACoC,OAAO;gCA2BZ,OAAO;;AApN3C,wBAkOE"}
1
+ {"version":3,"file":"admin-file.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/admin-file.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;cAQjB,OAAO;iBAuCJ,OAAO;iBAiBP,OAAO;IAmB1B;;;;;OAKG;mCACkC,OAAO;IAwC5C;;;;;;;OAOG;6BAC4B,OAAO;IA4DtC;;;;;;;;;OASG;4BAC2B,OAAO;IA2BrC;;;;;OAKG;gCAC+B,OAAO;;AAzO3C,wBAuPE"}
@@ -1,11 +1,26 @@
1
1
  import type { Context } from 'koa';
2
2
  declare const _default: {
3
3
  bulkUpdateFileInfo(ctx: Context): Promise<void>;
4
+ /**
5
+ * `PUT /upload/files/:id`
6
+ *
7
+ * Update the editable metadata (`fileInfo`) of an existing file. Also reached
8
+ * through the `POST /upload` multiplexer, which delegates here with the id in
9
+ * `ctx.query` — hence the dual read below, route params winning.
10
+ */
4
11
  updateFileInfo(ctx: Context): Promise<void>;
12
+ /**
13
+ * `POST /upload/files/:id/replace`
14
+ *
15
+ * Replace the binary content of an existing file. Also reached through the
16
+ * `POST /upload` multiplexer, which delegates here with the id in `ctx.query`
17
+ * — hence the dual read below, route params winning.
18
+ */
5
19
  replaceFile(ctx: Context): Promise<void>;
6
20
  uploadFiles(ctx: Context): Promise<any>;
7
21
  /**
8
- * @experimental
22
+ * `POST /upload/files`
23
+ *
9
24
  * Upload a single file and return the created File.
10
25
  *
11
26
  * Accepts one file per request (multipart `files` + `fileInfo`) and returns a
@@ -13,9 +28,10 @@ declare const _default: {
13
28
  * generation inline — that responsibility is decoupled and will be handled by a
14
29
  * background job. Auth and permission checks mirror `POST /upload`.
15
30
  */
16
- unstable_uploadFile(ctx: Context): Promise<any>;
31
+ uploadFile(ctx: Context): Promise<any>;
17
32
  /**
18
- * @experimental
33
+ * `POST /upload/actions/upload-from-urls`
34
+ *
19
35
  * Upload files from URLs with SSE streaming for per-file progress
20
36
  *
21
37
  * Accepts JSON body with URLs and fetches them server-side.
@@ -26,7 +42,7 @@ declare const _default: {
26
42
  * - file:error — when a URL fetch or upload fails
27
43
  * - stream:complete — final summary with all results
28
44
  */
29
- unstable_uploadFromUrls(ctx: Context): Promise<any>;
45
+ uploadFromUrls(ctx: Context): Promise<any>;
30
46
  upload(ctx: Context): Promise<void>;
31
47
  };
32
48
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"admin-upload.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/admin-upload.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;4BAWH,OAAO;wBA+BX,OAAO;qBA6BV,OAAO;qBA2DP,OAAO;IA0E9B;;;;;;;;OAQG;6BAC4B,OAAO;IAsEtC;;;;;;;;;;;OAWG;iCACgC,OAAO;gBAmIxB,OAAO;;AAha3B,wBAgbE"}
1
+ {"version":3,"file":"admin-upload.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/admin-upload.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;4BAWH,OAAO;IA+BrC;;;;;;OAMG;wBACuB,OAAO;IA8BjC;;;;;;OAMG;qBACoB,OAAO;qBA4DP,OAAO;IA0E9B;;;;;;;;;OASG;oBACmB,OAAO;IAsE7B;;;;;;;;;;;;OAYG;wBACuB,OAAO;gBAmIf,OAAO;;AAlb3B,wBAkcE"}
@@ -3,9 +3,9 @@ export declare const controllers: {
3
3
  find(ctx: import("koa").Context): Promise<any>;
4
4
  findOne(ctx: import("koa").Context): Promise<void>;
5
5
  destroy(ctx: import("koa").Context): Promise<void>;
6
- getAIMetadataCount(ctx: import("koa").Context): Promise<any>;
6
+ getAIMetadataPendingCount(ctx: import("koa").Context): Promise<any>;
7
+ createAIMetadataJob(ctx: import("koa").Context): Promise<any>;
7
8
  generateAIMetadata(ctx: import("koa").Context): Promise<any>;
8
- unstable_generateAIMetadata(ctx: import("koa").Context): Promise<any>;
9
9
  getLatestAIMetadataJob(ctx: import("koa").Context): Promise<any>;
10
10
  };
11
11
  'admin-folder': {
@@ -28,8 +28,8 @@ export declare const controllers: {
28
28
  updateFileInfo(ctx: import("koa").Context): Promise<void>;
29
29
  replaceFile(ctx: import("koa").Context): Promise<void>;
30
30
  uploadFiles(ctx: import("koa").Context): Promise<any>;
31
- unstable_uploadFile(ctx: import("koa").Context): Promise<any>;
32
- unstable_uploadFromUrls(ctx: import("koa").Context): Promise<any>;
31
+ uploadFile(ctx: import("koa").Context): Promise<any>;
32
+ uploadFromUrls(ctx: import("koa").Context): Promise<any>;
33
33
  upload(ctx: import("koa").Context): Promise<void>;
34
34
  };
35
35
  'content-api': ({ strapi }: {
@@ -64,9 +64,9 @@ declare const _default: () => {
64
64
  find(ctx: import("koa").Context): Promise<any>;
65
65
  findOne(ctx: import("koa").Context): Promise<void>;
66
66
  destroy(ctx: import("koa").Context): Promise<void>;
67
- getAIMetadataCount(ctx: import("koa").Context): Promise<any>;
67
+ getAIMetadataPendingCount(ctx: import("koa").Context): Promise<any>;
68
+ createAIMetadataJob(ctx: import("koa").Context): Promise<any>;
68
69
  generateAIMetadata(ctx: import("koa").Context): Promise<any>;
69
- unstable_generateAIMetadata(ctx: import("koa").Context): Promise<any>;
70
70
  getLatestAIMetadataJob(ctx: import("koa").Context): Promise<any>;
71
71
  };
72
72
  'admin-folder': {
@@ -89,8 +89,8 @@ declare const _default: () => {
89
89
  updateFileInfo(ctx: import("koa").Context): Promise<void>;
90
90
  replaceFile(ctx: import("koa").Context): Promise<void>;
91
91
  uploadFiles(ctx: import("koa").Context): Promise<any>;
92
- unstable_uploadFile(ctx: import("koa").Context): Promise<any>;
93
- unstable_uploadFromUrls(ctx: import("koa").Context): Promise<any>;
92
+ uploadFile(ctx: import("koa").Context): Promise<any>;
93
+ uploadFromUrls(ctx: import("koa").Context): Promise<any>;
94
94
  upload(ctx: import("koa").Context): Promise<void>;
95
95
  };
96
96
  'content-api': ({ strapi }: {
@@ -1 +1 @@
1
- {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../../server/src/routes/admin.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;CAoSlB,CAAC"}
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../../server/src/routes/admin.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;CAoTlB,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { Core } from '@strapi/types';
2
2
  import { File } from '../types';
3
- import type { UnstableGenerateAIMetadata } from '../../../shared/contracts/files';
4
- export type AIMetadataFileResult = UnstableGenerateAIMetadata.FileResult;
3
+ import type { GenerateAIMetadata } from '../../../shared/contracts/files';
4
+ export type AIMetadataFileResult = GenerateAIMetadata.FileResult;
5
5
  declare const createAIMetadataService: ({ strapi }: {
6
6
  strapi: Core.Strapi;
7
7
  }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"ai-metadata.d.ts","sourceRoot":"","sources":["../../../../server/src/services/ai-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAa,IAAI,EAAE,MAAM,UAAU,CAAC;AAQ3C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAElF,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,CAAC,UAAU,CAAC;AAoBzE,QAAA,MAAM,uBAAuB,GAAI,YAAY;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE;;;;;;IA2ChE;;;OAGG;qCAEM,IAAI,EAAE,mBACI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,QAC7D;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE;IAoC/B;;OAEG;gCAC+B,MAAM,QAAQ;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDvF;;;;;;;;;;;;;OAaG;8BAEQ,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,QACzB;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAqElC;;OAEG;wBACuB,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAuFjG,CAAC;AAEF,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
1
+ {"version":3,"file":"ai-metadata.d.ts","sourceRoot":"","sources":["../../../../server/src/services/ai-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAa,IAAI,EAAE,MAAM,UAAU,CAAC;AAQ3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,UAAU,CAAC;AAoBjE,QAAA,MAAM,uBAAuB,GAAI,YAAY;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE;;;;;;IA2ChE;;;OAGG;qCAEM,IAAI,EAAE,mBACI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,QAC7D;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE;IAoC/B;;OAEG;gCAC+B,MAAM,QAAQ;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDvF;;;;;;;;;;;;;OAaG;8BAEQ,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,QACzB;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAqElC;;OAEG;wBACuB,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAuFjG,CAAC;AAEF,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
@@ -8,46 +8,24 @@ export interface AIMetadataJob {
8
8
  completedAt?: Date;
9
9
  }
10
10
  /**
11
- * GET /upload/actions/generate-ai-metadata/latest
11
+ * GET /upload/ai-metadata-jobs/latest
12
12
  *
13
- * Return the latest AI metadata job
13
+ * The most recent still-active backfill job. 404s when nothing is running, so
14
+ * there is no `null` on the wire — callers get an error response instead.
14
15
  */
15
16
  export declare namespace GetLatestAIMetadataJob {
16
17
  interface Request {
17
18
  query?: {};
18
19
  }
19
20
  interface Response {
20
- data: AIMetadataJob | null;
21
+ data: AIMetadataJob;
21
22
  }
22
23
  }
23
24
  /**
24
- * POST /upload/actions/generate-ai-metadata
25
- *
26
- * Start a new AI metadata generation job
25
+ * The other two job endpoints — `POST /upload/ai-metadata-jobs` and
26
+ * `GET /upload/ai-metadata-jobs/pending-count` — are declared in `./files.ts`
27
+ * as `CreateAIMetadataJob` and `GetAIMetadataPendingCount`. They used to be
28
+ * duplicated here under different names and with response shapes that had
29
+ * drifted from what the controllers actually return; `./files.ts` is the one
30
+ * that matched, so it is the single source of truth for both.
27
31
  */
28
- export declare namespace StartAIMetadataJob {
29
- interface Request {
30
- body?: {};
31
- }
32
- interface Response {
33
- data: {
34
- jobId: number;
35
- status: string;
36
- };
37
- }
38
- }
39
- /**
40
- * GET /upload/actions/generate-ai-metadata/count
41
- *
42
- * Return count of images without metadata
43
- */
44
- export declare namespace GetAIMetadataCount {
45
- interface Request {
46
- query?: {};
47
- }
48
- interface Response {
49
- data: {
50
- count: number;
51
- };
52
- }
53
- }
@@ -1 +1 @@
1
- {"version":3,"file":"ai-metadata-jobs.d.ts","sourceRoot":"","sources":["../../../shared/contracts/ai-metadata-jobs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC9C,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,WAAW,sBAAsB,CAAC;IAC9C,UAAiB,OAAO;QACtB,KAAK,CAAC,EAAE,EAAE,CAAC;KACZ;IAED,UAAiB,QAAQ;QACvB,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;KAC5B;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,WAAW,kBAAkB,CAAC;IAC1C,UAAiB,OAAO;QACtB,IAAI,CAAC,EAAE,EAAE,CAAC;KACX;IAED,UAAiB,QAAQ;QACvB,IAAI,EAAE;YACJ,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,WAAW,kBAAkB,CAAC;IAC1C,UAAiB,OAAO;QACtB,KAAK,CAAC,EAAE,EAAE,CAAC;KACZ;IAED,UAAiB,QAAQ;QACvB,IAAI,EAAE;YACJ,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;KACH;CACF"}
1
+ {"version":3,"file":"ai-metadata-jobs.d.ts","sourceRoot":"","sources":["../../../shared/contracts/ai-metadata-jobs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC9C,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,CAAC,OAAO,WAAW,sBAAsB,CAAC;IAC9C,UAAiB,OAAO;QACtB,KAAK,CAAC,EAAE,EAAE,CAAC;KACZ;IAED,UAAiB,QAAQ;QACvB,IAAI,EAAE,aAAa,CAAC;KACrB;CACF;AAED;;;;;;;GAOG"}
@@ -201,12 +201,12 @@ export declare namespace CreateFile {
201
201
  }
202
202
  }
203
203
  /**
204
- * POST /upload/unstable/upload-file - Upload a single file
204
+ * POST /upload/files - Upload a single file
205
205
  *
206
206
  * Accepts one file per request (multipart `files` + `fileInfo`) and returns the
207
207
  * single created `File`. Does not run inline AI metadata generation.
208
208
  */
209
- export declare namespace UnstableCreateFile {
209
+ export declare namespace UploadFile {
210
210
  interface Request {
211
211
  body: FormData;
212
212
  }
@@ -216,7 +216,7 @@ export declare namespace UnstableCreateFile {
216
216
  }
217
217
  }
218
218
  /**
219
- * POST /upload/unstable/stream-from-urls - Stream upload files with partial success support
219
+ * POST /upload/actions/upload-from-urls - Stream upload files with partial success support
220
220
  *
221
221
  * Still used by the URL upload flow (`uploadFromUrls`).
222
222
  */
@@ -234,7 +234,7 @@ export declare namespace CreateFilesStream {
234
234
  }
235
235
  }
236
236
  /**
237
- * POST /upload/unstable/stream-from-urls - SSE streaming event types
237
+ * POST /upload/actions/upload-from-urls - SSE streaming event types
238
238
  *
239
239
  * The endpoint streams Server-Sent Events as each file is processed.
240
240
  * The final `stream:complete` event carries the same shape as CreateFilesStream.Response.
@@ -306,9 +306,9 @@ export declare namespace BulkUpdateFiles {
306
306
  }
307
307
  }
308
308
  /**
309
- * GET /upload/actions/generate-ai-metadata/count - Get count of images without metadata
309
+ * GET /upload/ai-metadata-jobs/pending-count - Get count of images without metadata
310
310
  */
311
- export declare namespace GetAIMetadataCount {
311
+ export declare namespace GetAIMetadataPendingCount {
312
312
  interface Request {
313
313
  query: {};
314
314
  }
@@ -321,9 +321,9 @@ export declare namespace GetAIMetadataCount {
321
321
  }
322
322
  }
323
323
  /**
324
- * POST /upload/actions/generate-ai-metadata - Start AI metadata generation job
324
+ * POST /upload/ai-metadata-jobs - Create a backfill job over every image missing metadata
325
325
  */
326
- export declare namespace GenerateAIMetadata {
326
+ export declare namespace CreateAIMetadataJob {
327
327
  interface Request {
328
328
  body: {};
329
329
  }
@@ -339,14 +339,14 @@ export declare namespace GenerateAIMetadata {
339
339
  }
340
340
  }
341
341
  /**
342
- * POST /upload/unstable/generate-ai-metadata - Generate AI metadata for selected files
342
+ * POST /upload/actions/generate-ai-metadata - Generate AI metadata for selected files
343
343
  *
344
344
  * Synchronous (no job): generates and persists alt text / caption for the given
345
345
  * files and reports the outcome per file. Non-images are `skipped`; ids that no
346
346
  * longer exist and files whose generation failed are reported as `error` rather
347
347
  * than failing the whole request.
348
348
  */
349
- export declare namespace UnstableGenerateAIMetadata {
349
+ export declare namespace GenerateAIMetadata {
350
350
  type FileStatus = 'success' | 'skipped' | 'error';
351
351
  interface FileResult {
352
352
  id: number;
@@ -1 +1 @@
1
- {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../shared/contracts/files.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../shared/contracts/files.ts"],"names":[],"mappings":"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"}