Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ generated: true
---
## S3AssetStorageStrategy

<GenerationInfo sourceFile="packages/asset-server-plugin/src/config/s3-asset-storage-strategy.ts" sourceLine="155" packageName="@vendure/asset-server-plugin" />
<GenerationInfo sourceFile="packages/asset-server-plugin/src/config/s3-asset-storage-strategy.ts" sourceLine="156" packageName="@vendure/asset-server-plugin" />

An [AssetStorageStrategy](/reference/typescript-api/assets/asset-storage-strategy#assetstoragestrategy) which uses [Amazon S3](https://aws.amazon.com/s3/) object storage service.
To us this strategy you must first have access to an AWS account.
Expand Down Expand Up @@ -86,7 +86,7 @@ class S3AssetStorageStrategy implements AssetStorageStrategy {
</div>
## S3Config

<GenerationInfo sourceFile="packages/asset-server-plugin/src/config/s3-asset-storage-strategy.ts" sourceLine="19" packageName="@vendure/asset-server-plugin" />
<GenerationInfo sourceFile="packages/asset-server-plugin/src/config/s3-asset-storage-strategy.ts" sourceLine="20" packageName="@vendure/asset-server-plugin" />

Configuration for connecting to AWS S3.

Expand Down Expand Up @@ -133,7 +133,7 @@ Using type `any` in order to avoid the need to include `aws-sdk` dependency in g
</div>
## configureS3AssetStorage

<GenerationInfo sourceFile="packages/asset-server-plugin/src/config/s3-asset-storage-strategy.ts" sourceLine="119" packageName="@vendure/asset-server-plugin" />
<GenerationInfo sourceFile="packages/asset-server-plugin/src/config/s3-asset-storage-strategy.ts" sourceLine="120" packageName="@vendure/asset-server-plugin" />

Returns a configured instance of the [S3AssetStorageStrategy](/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy#s3assetstoragestrategy) which can then be passed to the [AssetServerOptions](/reference/core-plugins/asset-server-plugin/asset-server-options#assetserveroptions)`storageStrategyFactory` property.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "TelemetryService"
generated: true
---
<GenerationInfo sourceFile="packages/core/src/telemetry/telemetry.service.ts" sourceLine="41" packageName="@vendure/core" since="3.6.0" />
<GenerationInfo sourceFile="packages/core/src/telemetry/telemetry.service.ts" sourceLine="44" packageName="@vendure/core" since="3.6.0" />

The TelemetryService collects anonymous usage data on Vendure application startup
and sends it to the Vendure telemetry endpoint. This data helps the Vendure team
Expand Down
4 changes: 2 additions & 2 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3352,7 +3352,7 @@
"title": "TelemetryService",
"slug": "telemetry-service",
"file": "docs/reference/typescript-api/telemetry/telemetry-service.mdx",
"lastModified": "2026-04-20T16:08:16+02:00"
"lastModified": "2026-07-08T09:33:32Z"
},
{
"title": "WrappedMethodArgs",
Expand Down Expand Up @@ -3548,7 +3548,7 @@
"title": "S3AssetStorageStrategy",
"slug": "s3asset-storage-strategy",
"file": "docs/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy.mdx",
"lastModified": "2026-04-20T16:08:16+02:00"
"lastModified": "2026-07-08T09:33:32Z"
},
{
"title": "SharpAssetPreviewStrategy",
Expand Down
129 changes: 129 additions & 0 deletions packages/core/src/telemetry/collectors/config.collector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -690,5 +690,134 @@ describe('ConfigCollector', () => {
expect(result.hasCustomFulfillmentProcess).toBe(false);
});
});

describe('API / security posture', () => {
beforeEach(() => {
mockConfigService.apiOptions = {
introspection: false,
adminApiPlayground: true,
shopApiPlayground: false,
adminApiDebug: false,
shopApiDebug: false,
trustProxy: true,
cors: { origin: '*', credentials: true },
} as any;
mockConfigService.authOptions = {
...mockConfigService.authOptions,
tokenMethod: ['cookie', 'bearer'],
requireVerification: false,
disableAuth: true,
superadminCredentials: { identifier: 'superadmin', password: 'superadmin' },
cookieOptions: { secure: true, sameSite: 'strict' },
};
mockConfigService.settingsStoreFields = {
dashboard: [{ name: 'a' }, { name: 'b' }],
theme: [{ name: 'c' }],
} as any;
});

it('reduces api/auth posture to booleans and short enums', () => {
const result = collector.collect();

expect(result.apiIntrospectionEnabled).toBe(false);
expect(result.apiPlaygroundEnabled).toBe(true);
expect(result.apiDebugEnabled).toBe(false);
expect(result.trustProxyEnabled).toBe(true);
expect(result.corsWildcardOrigin).toBe(true);
expect(result.tokenMethods).toEqual(['cookie', 'bearer']);
expect(result.requireVerification).toBe(false);
expect(result.authDisabled).toBe(true);
expect(result.cookieSecure).toBe(true);
expect(result.cookieSameSite).toBe('strict');
expect(result.settingsStoreFieldCount).toBe(3);
});

it('introspection defaults to enabled when not explicitly disabled', () => {
mockConfigService.apiOptions = {} as any;
expect(collector.collect().apiIntrospectionEnabled).toBe(true);
});

it('treats cors: true as a wildcard origin', () => {
mockConfigService.apiOptions = { cors: true } as any;
expect(collector.collect().corsWildcardOrigin).toBe(true);
});

it('reports corsWildcardOrigin false when cors is disabled', () => {
mockConfigService.apiOptions = { cors: false } as any;
expect(collector.collect().corsWildcardOrigin).toBe(false);
});

it('reports corsWildcardOrigin false for a specific origin', () => {
mockConfigService.apiOptions = {
cors: { origin: 'https://example.com' },
} as any;
expect(collector.collect().corsWildcardOrigin).toBe(false);
});

it('normalizes a single tokenMethod string to an array', () => {
mockConfigService.authOptions = { tokenMethod: 'bearer' } as any;
expect(collector.collect().tokenMethods).toEqual(['bearer']);
});

it('detects the default superadmin credentials', () => {
expect(collector.collect().defaultSuperadminCredentials).toBe(true);
});

it('returns false and never reads the actual values for changed credentials', () => {
mockConfigService.authOptions = {
...mockConfigService.authOptions,
superadminCredentials: { identifier: 'admin', password: 'hunter2' },
};
expect(collector.collect().defaultSuperadminCredentials).toBe(false);
});
});

describe('customizedStrategies', () => {
it('flags only single-strategy fields that differ from the default config', () => {
mockConfigService.assetOptions = {
// Differs from the default NoAssetStorageStrategy
assetStorageStrategy: { constructor: { name: 'S3AssetStorageStrategy' } },
// Matches the default
assetNamingStrategy: { constructor: { name: 'DefaultAssetNamingStrategy' } },
assetPreviewStrategy: { constructor: { name: 'NoAssetPreviewStrategy' } },
} as any;

const result = collector.collect();

expect(result.customizedStrategies).toContain('assetOptions.assetStorageStrategy');
expect(result.customizedStrategies).not.toContain('assetOptions.assetNamingStrategy');
expect(result.customizedStrategies).not.toContain('assetOptions.assetPreviewStrategy');
});

it('emits dotted paths, never strategy class names', () => {
mockConfigService.assetOptions = {
assetStorageStrategy: { constructor: { name: 'SecretInternalStorageStrategy' } },
} as any;

const paths = collector.collect().customizedStrategies ?? [];

expect(paths).toContain('assetOptions.assetStorageStrategy');
for (const path of paths) {
expect(path).not.toContain('SecretInternalStorageStrategy');
}
});

it('returns an empty array when no strategies are customized', () => {
// The base mock uses default-equivalent strategies for the fields it defines
mockConfigService.assetOptions = {
assetStorageStrategy: { constructor: { name: 'NoAssetStorageStrategy' } },
} as any;
mockConfigService.entityOptions = {
entityIdStrategy: { constructor: { name: 'AutoIncrementIdStrategy' } },
moneyStrategy: { constructor: { name: 'DefaultMoneyStrategy' } },
} as any;
mockConfigService.orderOptions = { orderSellerStrategy: undefined, process: [] } as any;
mockConfigService.taxOptions = {} as any;
mockConfigService.systemOptions = {} as any;
mockConfigService.jobQueueOptions = {} as any;

expect(collector.collect().customizedStrategies).toEqual([]);
});
});
});
});
Loading
Loading