diff --git a/be/apps/core/src/modules/photo/photo.service.ts b/be/apps/core/src/modules/photo/photo.service.ts index 95f64ca3..6810cf44 100644 --- a/be/apps/core/src/modules/photo/photo.service.ts +++ b/be/apps/core/src/modules/photo/photo.service.ts @@ -7,7 +7,12 @@ import type { StorageConfig, StorageObject, } from '@afilmory/builder' -import { AfilmoryBuilder, processPhotoWithPipeline, thumbnailStoragePlugin } from '@afilmory/builder' +import { + AfilmoryBuilder, + processPhotoWithPipeline, + THUMBNAIL_PLUGIN_SYMBOL, + thumbnailStoragePlugin, +} from '@afilmory/builder' import type { Logger as BuilderLogger } from '@afilmory/builder/logger/index.js' import type { PhotoProcessingLoggers } from '@afilmory/builder/photo/index.js' import { createPhotoProcessingLoggers, setGlobalLoggers } from '@afilmory/builder/photo/index.js' @@ -144,13 +149,11 @@ export class PhotoBuilderService { private ensureThumbnailPlugin(config: BuilderConfig): BuilderConfig { const existingPlugins = config.plugins ?? [] const hasPlugin = existingPlugins.some((entry) => { - if (typeof entry === 'string') { - return entry.includes('thumbnail-storage') - } - if (typeof entry === 'function') { - const fnName = entry.name ?? '' - return fnName.includes('thumbnailStorage') || entry.toString().includes('thumbnail-storage') + // Check for the unique Symbol identifier for reliable detection + if (typeof entry === 'object' && entry !== null && THUMBNAIL_PLUGIN_SYMBOL in entry) { + return true } + // Fallback: check by name property for backward compatibility return entry?.name === 'afilmory:thumbnail-storage' }) diff --git a/packages/builder/src/index.ts b/packages/builder/src/index.ts index 5bc5a854..6811bf01 100644 --- a/packages/builder/src/index.ts +++ b/packages/builder/src/index.ts @@ -23,7 +23,7 @@ export { default as localStoragePlugin } from './plugins/storage/local.js' export type { S3StoragePluginOptions } from './plugins/storage/s3.js' export { default as s3StoragePlugin } from './plugins/storage/s3.js' export type { ThumbnailStoragePluginOptions } from './plugins/thumbnail-storage/index.js' -export { default as thumbnailStoragePlugin } from './plugins/thumbnail-storage/index.js' +export { THUMBNAIL_PLUGIN_SYMBOL, default as thumbnailStoragePlugin } from './plugins/thumbnail-storage/index.js' export type { BuilderPlugin, BuilderPluginConfigEntry, diff --git a/packages/builder/src/plugins/thumbnail-storage/index.ts b/packages/builder/src/plugins/thumbnail-storage/index.ts index fd782326..2f001bc4 100644 --- a/packages/builder/src/plugins/thumbnail-storage/index.ts +++ b/packages/builder/src/plugins/thumbnail-storage/index.ts @@ -2,7 +2,12 @@ import { StorageManager } from '../../storage/index.js' import type { StorageConfig } from '../../storage/interfaces.js' import type { BuilderPlugin } from '../types.js' import type { ThumbnailPluginData } from './shared.js' -import { DEFAULT_CONTENT_TYPE, DEFAULT_DIRECTORY, THUMBNAIL_PLUGIN_DATA_KEY } from './shared.js' +import { + DEFAULT_CONTENT_TYPE, + DEFAULT_DIRECTORY, + THUMBNAIL_PLUGIN_DATA_KEY, + THUMBNAIL_PLUGIN_SYMBOL, +} from './shared.js' const PLUGIN_NAME = 'afilmory:thumbnail-storage' const RUN_STATE_KEY = 'state' @@ -82,8 +87,9 @@ export default function thumbnailStoragePlugin(options: ThumbnailStoragePluginOp let resolved: ResolvedPluginConfig | null = null let externalStorageManager: StorageManager | null = null - return { + const plugin: BuilderPlugin & { [THUMBNAIL_PLUGIN_SYMBOL]: true } = { name: PLUGIN_NAME, + [THUMBNAIL_PLUGIN_SYMBOL]: true, hooks: { onInit: ({ builder, config, logger }) => { const storageConfig = (options.storageConfig ?? config.storage) as StorageConfig @@ -175,6 +181,10 @@ export default function thumbnailStoragePlugin(options: ThumbnailStoragePluginOp }, }, } + + return plugin } export type { ThumbnailStoragePluginOptions } + +export { THUMBNAIL_PLUGIN_SYMBOL } from './shared.js' diff --git a/packages/builder/src/plugins/thumbnail-storage/shared.ts b/packages/builder/src/plugins/thumbnail-storage/shared.ts index 9b4100ba..77fc0600 100644 --- a/packages/builder/src/plugins/thumbnail-storage/shared.ts +++ b/packages/builder/src/plugins/thumbnail-storage/shared.ts @@ -2,6 +2,12 @@ import type { Buffer } from 'node:buffer' export const THUMBNAIL_PLUGIN_DATA_KEY = 'afilmory:thumbnail-storage:data' +/** + * Unique symbol identifier for the thumbnail storage plugin. + * Used for reliable plugin detection without fragile string matching. + */ +export const THUMBNAIL_PLUGIN_SYMBOL = Symbol.for('afilmory:thumbnail-storage') + export interface ThumbnailPluginData { photoId: string fileName: string