create-forgeon 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli/add-help.mjs +1 -0
- package/src/cli/add-options.mjs +6 -0
- package/src/cli/add-options.test.mjs +2 -0
- package/src/modules/dependencies.mjs +31 -0
- package/src/modules/dependencies.test.mjs +207 -5
- package/src/modules/executor.mjs +14 -0
- package/src/modules/executor.test.mjs +719 -14
- package/src/modules/files-access.mjs +437 -0
- package/src/modules/files-image.mjs +531 -0
- package/src/modules/files-local.mjs +221 -0
- package/src/modules/files-quotas.mjs +381 -0
- package/src/modules/files-s3.mjs +266 -0
- package/src/modules/files.mjs +527 -0
- package/src/modules/queue.mjs +410 -0
- package/src/modules/registry.mjs +93 -3
- package/src/run-add-module.mjs +89 -2
- package/templates/module-fragments/files/00_title.md +1 -0
- package/templates/module-fragments/files/10_overview.md +17 -0
- package/templates/module-fragments/files/20_scope.md +13 -0
- package/templates/module-fragments/files/90_status_implemented.md +3 -0
- package/templates/module-fragments/files-access/00_title.md +1 -0
- package/templates/module-fragments/files-access/10_overview.md +9 -0
- package/templates/module-fragments/files-access/20_scope.md +20 -0
- package/templates/module-fragments/files-access/90_status_implemented.md +3 -0
- package/templates/module-fragments/files-image/00_title.md +1 -0
- package/templates/module-fragments/files-image/10_overview.md +10 -0
- package/templates/module-fragments/files-image/20_scope.md +20 -0
- package/templates/module-fragments/files-image/90_status_implemented.md +3 -0
- package/templates/module-fragments/files-local/00_title.md +1 -0
- package/templates/module-fragments/files-local/10_overview.md +9 -0
- package/templates/module-fragments/files-local/20_scope.md +10 -0
- package/templates/module-fragments/files-local/90_status_implemented.md +3 -0
- package/templates/module-fragments/files-quotas/00_title.md +1 -0
- package/templates/module-fragments/files-quotas/10_overview.md +9 -0
- package/templates/module-fragments/files-quotas/20_scope.md +20 -0
- package/templates/module-fragments/files-quotas/90_status_implemented.md +3 -0
- package/templates/module-fragments/files-s3/00_title.md +1 -0
- package/templates/module-fragments/files-s3/10_overview.md +17 -0
- package/templates/module-fragments/files-s3/20_scope.md +11 -0
- package/templates/module-fragments/files-s3/90_status_implemented.md +5 -0
- package/templates/module-fragments/queue/20_scope.md +8 -7
- package/templates/module-fragments/queue/90_status_implemented.md +3 -0
- package/templates/module-presets/files/apps/api/prisma/migrations/20260306_files_file_record/migration.sql +30 -0
- package/templates/module-presets/files/apps/api/prisma/migrations/20260306_files_file_variant/migration.sql +55 -0
- package/templates/module-presets/files/packages/files/package.json +24 -0
- package/templates/module-presets/files/packages/files/src/dto/create-file.dto.ts +30 -0
- package/templates/module-presets/files/packages/files/src/files-config.loader.ts +21 -0
- package/templates/module-presets/files/packages/files/src/files-config.module.ts +12 -0
- package/templates/module-presets/files/packages/files/src/files-config.service.ts +32 -0
- package/templates/module-presets/files/packages/files/src/files-env.schema.ts +30 -0
- package/templates/module-presets/files/packages/files/src/files.controller.ts +89 -0
- package/templates/module-presets/files/packages/files/src/files.service.ts +744 -0
- package/templates/module-presets/files/packages/files/src/files.types.ts +35 -0
- package/templates/module-presets/files/packages/files/src/forgeon-files.module.ts +12 -0
- package/templates/module-presets/files/packages/files/src/index.ts +9 -0
- package/templates/module-presets/files/packages/files/tsconfig.json +9 -0
- package/templates/module-presets/files-access/packages/files-access/package.json +17 -0
- package/templates/module-presets/files-access/packages/files-access/src/files-access.service.ts +59 -0
- package/templates/module-presets/files-access/packages/files-access/src/files-access.subject.ts +45 -0
- package/templates/module-presets/files-access/packages/files-access/src/files-access.types.ts +14 -0
- package/templates/module-presets/files-access/packages/files-access/src/forgeon-files-access.module.ts +8 -0
- package/templates/module-presets/files-access/packages/files-access/src/index.ts +4 -0
- package/templates/module-presets/files-access/packages/files-access/tsconfig.json +9 -0
- package/templates/module-presets/files-image/packages/files-image/package.json +21 -0
- package/templates/module-presets/files-image/packages/files-image/src/files-image-config.loader.ts +32 -0
- package/templates/module-presets/files-image/packages/files-image/src/files-image-config.module.ts +11 -0
- package/templates/module-presets/files-image/packages/files-image/src/files-image-config.service.ts +55 -0
- package/templates/module-presets/files-image/packages/files-image/src/files-image-env.schema.ts +28 -0
- package/templates/module-presets/files-image/packages/files-image/src/files-image.service.ts +420 -0
- package/templates/module-presets/files-image/packages/files-image/src/files-image.types.ts +18 -0
- package/templates/module-presets/files-image/packages/files-image/src/forgeon-files-image.module.ts +10 -0
- package/templates/module-presets/files-image/packages/files-image/src/index.ts +7 -0
- package/templates/module-presets/files-image/packages/files-image/tsconfig.json +9 -0
- package/templates/module-presets/files-local/packages/files-local/package.json +19 -0
- package/templates/module-presets/files-local/packages/files-local/src/files-local-config.loader.ts +13 -0
- package/templates/module-presets/files-local/packages/files-local/src/files-local-config.module.ts +12 -0
- package/templates/module-presets/files-local/packages/files-local/src/files-local-config.service.ts +11 -0
- package/templates/module-presets/files-local/packages/files-local/src/files-local-env.schema.ts +13 -0
- package/templates/module-presets/files-local/packages/files-local/src/index.ts +4 -0
- package/templates/module-presets/files-local/packages/files-local/tsconfig.json +9 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/package.json +20 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas-config.loader.ts +22 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas-config.module.ts +11 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas-config.service.ts +27 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas-env.schema.ts +15 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas.service.ts +118 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas.types.ts +22 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/src/forgeon-files-quotas.module.ts +11 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/src/index.ts +7 -0
- package/templates/module-presets/files-quotas/packages/files-quotas/tsconfig.json +9 -0
- package/templates/module-presets/files-s3/packages/files-s3/package.json +20 -0
- package/templates/module-presets/files-s3/packages/files-s3/src/files-s3-config.loader.ts +57 -0
- package/templates/module-presets/files-s3/packages/files-s3/src/files-s3-config.module.ts +12 -0
- package/templates/module-presets/files-s3/packages/files-s3/src/files-s3-config.service.ts +44 -0
- package/templates/module-presets/files-s3/packages/files-s3/src/files-s3-env.schema.ts +51 -0
- package/templates/module-presets/files-s3/packages/files-s3/src/index.ts +4 -0
- package/templates/module-presets/files-s3/packages/files-s3/tsconfig.json +9 -0
- package/templates/module-presets/queue/packages/queue/package.json +21 -0
- package/templates/module-presets/queue/packages/queue/src/forgeon-queue.module.ts +10 -0
- package/templates/module-presets/queue/packages/queue/src/index.ts +6 -0
- package/templates/module-presets/queue/packages/queue/src/queue-config.loader.ts +24 -0
- package/templates/module-presets/queue/packages/queue/src/queue-config.module.ts +10 -0
- package/templates/module-presets/queue/packages/queue/src/queue-config.service.ts +69 -0
- package/templates/module-presets/queue/packages/queue/src/queue-env.schema.ts +17 -0
- package/templates/module-presets/queue/packages/queue/src/queue.service.ts +88 -0
- package/templates/module-presets/queue/packages/queue/tsconfig.json +9 -0
- package/templates/module-fragments/queue/90_status_planned.md +0 -3
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type StoredFileInput = {
|
|
2
|
+
originalName: string;
|
|
3
|
+
mimeType: string;
|
|
4
|
+
size: number;
|
|
5
|
+
buffer: Buffer;
|
|
6
|
+
ownerType?: string;
|
|
7
|
+
ownerId?: string;
|
|
8
|
+
visibility?: string;
|
|
9
|
+
createdById?: string;
|
|
10
|
+
auditContext?: {
|
|
11
|
+
requestId?: string | null;
|
|
12
|
+
ip?: string | null;
|
|
13
|
+
userId?: string | null;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type FileVariantKey = 'original' | 'preview';
|
|
18
|
+
|
|
19
|
+
export type FileRecordDto = {
|
|
20
|
+
id: string;
|
|
21
|
+
publicId: string;
|
|
22
|
+
storageKey: string;
|
|
23
|
+
originalName: string;
|
|
24
|
+
mimeType: string;
|
|
25
|
+
size: number;
|
|
26
|
+
storageDriver: string;
|
|
27
|
+
ownerType: string;
|
|
28
|
+
ownerId: string | null;
|
|
29
|
+
visibility: string;
|
|
30
|
+
createdById: string | null;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
url: string;
|
|
34
|
+
availableVariants: FileVariantKey[];
|
|
35
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { FilesController } from './files.controller';
|
|
3
|
+
import { FilesConfigModule } from './files-config.module';
|
|
4
|
+
import { FilesService } from './files.service';
|
|
5
|
+
|
|
6
|
+
@Module({
|
|
7
|
+
imports: [FilesConfigModule],
|
|
8
|
+
controllers: [FilesController],
|
|
9
|
+
providers: [FilesService],
|
|
10
|
+
exports: [FilesConfigModule, FilesService],
|
|
11
|
+
})
|
|
12
|
+
export class ForgeonFilesModule {}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './dto/create-file.dto';
|
|
2
|
+
export * from './files.controller';
|
|
3
|
+
export * from './forgeon-files.module';
|
|
4
|
+
export * from './files-config.loader';
|
|
5
|
+
export * from './files-config.module';
|
|
6
|
+
export * from './files-config.service';
|
|
7
|
+
export * from './files-env.schema';
|
|
8
|
+
export * from './files.service';
|
|
9
|
+
export * from './files.types';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forgeon/files-access",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p tsconfig.json"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@nestjs/common": "^11.0.1"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^22.10.7",
|
|
15
|
+
"typescript": "^5.7.3"
|
|
16
|
+
}
|
|
17
|
+
}
|
package/templates/module-presets/files-access/packages/files-access/src/files-access.service.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ForbiddenException, Injectable } from '@nestjs/common';
|
|
2
|
+
import type { FilesAccessRecord, FilesAccessSubject } from './files-access.types';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
5
|
+
export class FilesAccessService {
|
|
6
|
+
can(action: 'read' | 'delete', record: FilesAccessRecord, subject: FilesAccessSubject): boolean {
|
|
7
|
+
if (subject.permissions.includes('files.manage')) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const isOwner =
|
|
12
|
+
subject.actorId !== null &&
|
|
13
|
+
record.ownerType === 'user' &&
|
|
14
|
+
record.ownerId !== null &&
|
|
15
|
+
record.ownerId === subject.actorId;
|
|
16
|
+
|
|
17
|
+
if (isOwner) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (action === 'read' && record.visibility === 'public') {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
canRead(record: FilesAccessRecord, subject: FilesAccessSubject): boolean {
|
|
29
|
+
return this.can('read', record, subject);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
canDelete(record: FilesAccessRecord, subject: FilesAccessSubject): boolean {
|
|
33
|
+
return this.can('delete', record, subject);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
assertCanRead(record: FilesAccessRecord, subject: FilesAccessSubject): void {
|
|
37
|
+
if (!this.canRead(record, subject)) {
|
|
38
|
+
throw new ForbiddenException({
|
|
39
|
+
message: 'You do not have permission to read this file.',
|
|
40
|
+
details: {
|
|
41
|
+
required: 'owner or files.manage or public visibility',
|
|
42
|
+
action: 'read',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
assertCanDelete(record: FilesAccessRecord, subject: FilesAccessSubject): void {
|
|
49
|
+
if (!this.canDelete(record, subject)) {
|
|
50
|
+
throw new ForbiddenException({
|
|
51
|
+
message: 'You do not have permission to delete this file.',
|
|
52
|
+
details: {
|
|
53
|
+
required: 'owner or files.manage',
|
|
54
|
+
action: 'delete',
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
package/templates/module-presets/files-access/packages/files-access/src/files-access.subject.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { FilesAccessSubject } from './files-access.types';
|
|
2
|
+
|
|
3
|
+
type HeaderValue = string | string[] | undefined;
|
|
4
|
+
|
|
5
|
+
type RequestLike = {
|
|
6
|
+
user?: {
|
|
7
|
+
sub?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
};
|
|
10
|
+
headers?: Record<string, HeaderValue>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function getHeaderValue(headers: Record<string, HeaderValue> | undefined, key: string): string | null {
|
|
14
|
+
if (!headers) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const value = headers[key];
|
|
18
|
+
if (Array.isArray(value)) {
|
|
19
|
+
return value.length > 0 ? value[0] : null;
|
|
20
|
+
}
|
|
21
|
+
if (typeof value !== 'string') {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function extractFilesAccessSubject(request: RequestLike): FilesAccessSubject {
|
|
28
|
+
const actorId =
|
|
29
|
+
request.user?.sub ??
|
|
30
|
+
request.user?.id ??
|
|
31
|
+
getHeaderValue(request.headers, 'x-forgeon-user-id') ??
|
|
32
|
+
null;
|
|
33
|
+
|
|
34
|
+
const permissionsRaw = getHeaderValue(request.headers, 'x-forgeon-permissions');
|
|
35
|
+
const permissions =
|
|
36
|
+
permissionsRaw
|
|
37
|
+
?.split(',')
|
|
38
|
+
.map((item) => item.trim())
|
|
39
|
+
.filter(Boolean) ?? [];
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
actorId,
|
|
43
|
+
permissions,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type FilesAccessAction = 'read' | 'delete';
|
|
2
|
+
|
|
3
|
+
export type FilesAccessVisibility = 'private' | 'owner' | 'group' | 'public' | string;
|
|
4
|
+
|
|
5
|
+
export type FilesAccessRecord = {
|
|
6
|
+
ownerType: string;
|
|
7
|
+
ownerId: string | null;
|
|
8
|
+
visibility: FilesAccessVisibility;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type FilesAccessSubject = {
|
|
12
|
+
actorId: string | null;
|
|
13
|
+
permissions: string[];
|
|
14
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forgeon/files-image",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p tsconfig.json"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@nestjs/common": "^11.0.1",
|
|
12
|
+
"@nestjs/config": "^4.0.0",
|
|
13
|
+
"file-type": "^19.6.0",
|
|
14
|
+
"sharp": "^0.34.2",
|
|
15
|
+
"zod": "^3.24.2"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^22.10.7",
|
|
19
|
+
"typescript": "^5.7.3"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/templates/module-presets/files-image/packages/files-image/src/files-image-config.loader.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { registerAs } from '@nestjs/config';
|
|
2
|
+
import { parseFilesImageEnv } from './files-image-env.schema';
|
|
3
|
+
|
|
4
|
+
export const FILES_IMAGE_CONFIG_NAMESPACE = 'filesImage';
|
|
5
|
+
|
|
6
|
+
export interface FilesImageConfigValues {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
stripMetadata: boolean;
|
|
9
|
+
maxWidth: number;
|
|
10
|
+
maxHeight: number;
|
|
11
|
+
maxPixels: number;
|
|
12
|
+
maxFrames: number;
|
|
13
|
+
processTimeoutMs: number;
|
|
14
|
+
allowedMimeTypes: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const filesImageConfig = registerAs(
|
|
18
|
+
FILES_IMAGE_CONFIG_NAMESPACE,
|
|
19
|
+
(): FilesImageConfigValues => {
|
|
20
|
+
const env = parseFilesImageEnv(process.env);
|
|
21
|
+
return {
|
|
22
|
+
enabled: env.FILES_IMAGE_ENABLED,
|
|
23
|
+
stripMetadata: env.FILES_IMAGE_STRIP_METADATA,
|
|
24
|
+
maxWidth: env.FILES_IMAGE_MAX_WIDTH,
|
|
25
|
+
maxHeight: env.FILES_IMAGE_MAX_HEIGHT,
|
|
26
|
+
maxPixels: env.FILES_IMAGE_MAX_PIXELS,
|
|
27
|
+
maxFrames: env.FILES_IMAGE_MAX_FRAMES,
|
|
28
|
+
processTimeoutMs: env.FILES_IMAGE_PROCESS_TIMEOUT_MS,
|
|
29
|
+
allowedMimeTypes: env.FILES_IMAGE_ALLOWED_MIME_TYPES,
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
);
|
package/templates/module-presets/files-image/packages/files-image/src/files-image-config.module.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { ConfigModule } from '@nestjs/config';
|
|
3
|
+
import { filesImageConfig } from './files-image-config.loader';
|
|
4
|
+
import { FilesImageConfigService } from './files-image-config.service';
|
|
5
|
+
|
|
6
|
+
@Module({
|
|
7
|
+
imports: [ConfigModule.forFeature(filesImageConfig)],
|
|
8
|
+
providers: [FilesImageConfigService],
|
|
9
|
+
exports: [FilesImageConfigService],
|
|
10
|
+
})
|
|
11
|
+
export class FilesImageConfigModule {}
|
package/templates/module-presets/files-image/packages/files-image/src/files-image-config.service.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
3
|
+
import {
|
|
4
|
+
FILES_IMAGE_CONFIG_NAMESPACE,
|
|
5
|
+
FilesImageConfigValues,
|
|
6
|
+
} from './files-image-config.loader';
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class FilesImageConfigService {
|
|
10
|
+
constructor(private readonly configService: ConfigService) {}
|
|
11
|
+
|
|
12
|
+
get enabled(): boolean {
|
|
13
|
+
return this.configService.getOrThrow<boolean>(`${FILES_IMAGE_CONFIG_NAMESPACE}.enabled`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get stripMetadata(): boolean {
|
|
17
|
+
return this.configService.getOrThrow<boolean>(`${FILES_IMAGE_CONFIG_NAMESPACE}.stripMetadata`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get maxWidth(): FilesImageConfigValues['maxWidth'] {
|
|
21
|
+
return this.configService.getOrThrow<FilesImageConfigValues['maxWidth']>(
|
|
22
|
+
`${FILES_IMAGE_CONFIG_NAMESPACE}.maxWidth`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get maxHeight(): FilesImageConfigValues['maxHeight'] {
|
|
27
|
+
return this.configService.getOrThrow<FilesImageConfigValues['maxHeight']>(
|
|
28
|
+
`${FILES_IMAGE_CONFIG_NAMESPACE}.maxHeight`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get maxPixels(): FilesImageConfigValues['maxPixels'] {
|
|
33
|
+
return this.configService.getOrThrow<FilesImageConfigValues['maxPixels']>(
|
|
34
|
+
`${FILES_IMAGE_CONFIG_NAMESPACE}.maxPixels`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get maxFrames(): FilesImageConfigValues['maxFrames'] {
|
|
39
|
+
return this.configService.getOrThrow<FilesImageConfigValues['maxFrames']>(
|
|
40
|
+
`${FILES_IMAGE_CONFIG_NAMESPACE}.maxFrames`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get processTimeoutMs(): FilesImageConfigValues['processTimeoutMs'] {
|
|
45
|
+
return this.configService.getOrThrow<FilesImageConfigValues['processTimeoutMs']>(
|
|
46
|
+
`${FILES_IMAGE_CONFIG_NAMESPACE}.processTimeoutMs`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get allowedMimeTypes(): FilesImageConfigValues['allowedMimeTypes'] {
|
|
51
|
+
return this.configService.getOrThrow<FilesImageConfigValues['allowedMimeTypes']>(
|
|
52
|
+
`${FILES_IMAGE_CONFIG_NAMESPACE}.allowedMimeTypes`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
package/templates/module-presets/files-image/packages/files-image/src/files-image-env.schema.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const filesImageEnvSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
FILES_IMAGE_ENABLED: z.coerce.boolean().default(true),
|
|
6
|
+
FILES_IMAGE_STRIP_METADATA: z.coerce.boolean().default(true),
|
|
7
|
+
FILES_IMAGE_MAX_WIDTH: z.coerce.number().int().positive().default(4096),
|
|
8
|
+
FILES_IMAGE_MAX_HEIGHT: z.coerce.number().int().positive().default(4096),
|
|
9
|
+
FILES_IMAGE_MAX_PIXELS: z.coerce.number().int().positive().default(16777216),
|
|
10
|
+
FILES_IMAGE_MAX_FRAMES: z.coerce.number().int().positive().default(1),
|
|
11
|
+
FILES_IMAGE_PROCESS_TIMEOUT_MS: z.coerce.number().int().positive().default(5000),
|
|
12
|
+
FILES_IMAGE_ALLOWED_MIME_TYPES: z
|
|
13
|
+
.string()
|
|
14
|
+
.default('image/jpeg,image/png,image/webp')
|
|
15
|
+
.transform((value) =>
|
|
16
|
+
value
|
|
17
|
+
.split(',')
|
|
18
|
+
.map((item) => item.trim())
|
|
19
|
+
.filter(Boolean),
|
|
20
|
+
),
|
|
21
|
+
})
|
|
22
|
+
.passthrough();
|
|
23
|
+
|
|
24
|
+
export type FilesImageEnv = z.infer<typeof filesImageEnvSchema>;
|
|
25
|
+
|
|
26
|
+
export function parseFilesImageEnv(input: Record<string, unknown>): FilesImageEnv {
|
|
27
|
+
return filesImageEnvSchema.parse(input);
|
|
28
|
+
}
|