diff --git a/packages/asset-server-plugin/src/common.ts b/packages/asset-server-plugin/src/common.ts new file mode 100644 index 0000000000..3d8777e4a2 --- /dev/null +++ b/packages/asset-server-plugin/src/common.ts @@ -0,0 +1,22 @@ +import { REQUEST_CONTEXT_KEY } from '@vendure/core/dist/common/constants'; +import { Request } from 'express'; + +import { AssetServerOptions } from './types'; + +export function getAssetUrlPrefixFn(options: AssetServerOptions) { + const { assetUrlPrefix, route } = options; + if (assetUrlPrefix == null) { + return (request: Request, identifier: string) => + `${request.protocol}://${request.get('host')}/${route}/`; + } + if (typeof assetUrlPrefix === 'string') { + return (...args: any[]) => assetUrlPrefix; + } + if (typeof assetUrlPrefix === 'function') { + return (request: Request, identifier: string) => { + const ctx = (request as any)[REQUEST_CONTEXT_KEY]; + return assetUrlPrefix(ctx, identifier); + }; + } + throw new Error(`The assetUrlPrefix option was of an unexpected type: ${JSON.stringify(assetUrlPrefix)}`); +} diff --git a/packages/asset-server-plugin/src/default-asset-storage-strategy-factory.ts b/packages/asset-server-plugin/src/default-asset-storage-strategy-factory.ts index ecd962b8d8..4b79ba60a5 100644 --- a/packages/asset-server-plugin/src/default-asset-storage-strategy-factory.ts +++ b/packages/asset-server-plugin/src/default-asset-storage-strategy-factory.ts @@ -1,5 +1,6 @@ import { Request } from 'express'; +import { getAssetUrlPrefixFn } from './common'; import { LocalAssetStorageStrategy } from './local-asset-storage-strategy'; import { AssetServerOptions } from './types'; @@ -8,11 +9,12 @@ import { AssetServerOptions } from './types'; */ export function defaultAssetStorageStrategyFactory(options: AssetServerOptions) { const { assetUrlPrefix, assetUploadDir, route } = options; + const prefixFn = getAssetUrlPrefixFn(options); const toAbsoluteUrlFn = (request: Request, identifier: string): string => { if (!identifier) { return ''; } - const prefix = assetUrlPrefix || `${request.protocol}://${request.get('host')}/${route}/`; + const prefix = prefixFn(request, identifier); return identifier.startsWith(prefix) ? identifier : `${prefix}${identifier}`; }; return new LocalAssetStorageStrategy(assetUploadDir, toAbsoluteUrlFn); diff --git a/packages/asset-server-plugin/src/s3-asset-storage-strategy.ts b/packages/asset-server-plugin/src/s3-asset-storage-strategy.ts index c65097ec82..5be2e86f83 100644 --- a/packages/asset-server-plugin/src/s3-asset-storage-strategy.ts +++ b/packages/asset-server-plugin/src/s3-asset-storage-strategy.ts @@ -3,6 +3,7 @@ import { Request } from 'express'; import * as path from 'path'; import { Readable, Stream } from 'stream'; +import { getAssetUrlPrefixFn } from './common'; import { loggerCtx } from './constants'; import { AssetServerOptions } from './types'; @@ -94,11 +95,12 @@ export interface S3Config { export function configureS3AssetStorage(s3Config: S3Config) { return (options: AssetServerOptions) => { const { assetUrlPrefix, route } = options; + const prefixFn = getAssetUrlPrefixFn(options); const toAbsoluteUrlFn = (request: Request, identifier: string): string => { if (!identifier) { return ''; } - const prefix = assetUrlPrefix || `${request.protocol}://${request.get('host')}/${route}/`; + const prefix = prefixFn(request, identifier); return identifier.startsWith(prefix) ? identifier : `${prefix}${identifier}`; }; return new S3AssetStorageStrategy(s3Config, toAbsoluteUrlFn); diff --git a/packages/asset-server-plugin/src/types.ts b/packages/asset-server-plugin/src/types.ts index 6d4e2d5da4..825ab4be0b 100644 --- a/packages/asset-server-plugin/src/types.ts +++ b/packages/asset-server-plugin/src/types.ts @@ -1,4 +1,4 @@ -import { AssetNamingStrategy, AssetStorageStrategy } from '@vendure/core'; +import { AssetNamingStrategy, AssetStorageStrategy, RequestContext } from '@vendure/core'; /** * @description @@ -56,13 +56,15 @@ export interface AssetServerOptions { assetUploadDir: string; // TODO: this is strategy-specific and should be moved out of the global options /** * @description - * The complete URL prefix of the asset files. For example, "https://demo.vendure.io/assets/" + * The complete URL prefix of the asset files. For example, "https://demo.vendure.io/assets/". A + * function can also be provided to handle more complex cases, such as serving multiple domains + * from a single server. In this case, the function should return a string url prefix. * * If not provided, the plugin will attempt to guess based off the incoming * request and the configured route. However, in all but the simplest cases, * this guess may not yield correct results. */ - assetUrlPrefix?: string; + assetUrlPrefix?: string | ((ctx: RequestContext, identifier: string) => string); /** * @description * The max width in pixels of a generated preview image.