because I got bored of customising my CV for every job
1import { type DynamicModule, Module, type Type } from "@nestjs/common";
2import { DiskFileStorage } from "./disk-file-storage";
3import { FILE_STORAGE } from "./file-storage.interface";
4import { R2FileStorage, type R2FileStorageConfig } from "./r2-file-storage";
5
6type DiskConfig = { driver: "disk"; baseDir: string };
7type R2Config = { driver: "r2" } & R2FileStorageConfig;
8export type FileStorageModuleConfig = DiskConfig | R2Config;
9
10/**
11 * Implement this interface to provide FileStorage configuration
12 * via NestJS DI. Register it with `FileStorageModule.forRootAsync()`.
13 */
14export interface FileStorageConfigProvider {
15 createFileStorageConfig(): FileStorageModuleConfig;
16}
17
18export const FILE_STORAGE_CONFIG_PROVIDER = Symbol("FILE_STORAGE_CONFIG_PROVIDER");
19
20@Module({})
21export class FileStorageModule {
22 /**
23 * Static configuration — pass the config directly.
24 */
25 static forRoot(config: FileStorageModuleConfig): DynamicModule {
26 return {
27 module: FileStorageModule,
28 providers: [
29 {
30 provide: FILE_STORAGE,
31 useFactory: () => createStorage(config),
32 },
33 ],
34 exports: [FILE_STORAGE],
35 global: true,
36 };
37 }
38
39 /**
40 * Async configuration — provide a class that implements
41 * `FileStorageConfigProvider`. The class can inject ConfigService
42 * or any other NestJS provider.
43 */
44 static forRootAsync(options: {
45 imports?: Type[];
46 useClass: Type<FileStorageConfigProvider>;
47 }): DynamicModule {
48 return {
49 module: FileStorageModule,
50 imports: options.imports ?? [],
51 providers: [
52 {
53 provide: FILE_STORAGE_CONFIG_PROVIDER,
54 useClass: options.useClass,
55 },
56 {
57 provide: FILE_STORAGE,
58 useFactory: (provider: FileStorageConfigProvider) =>
59 createStorage(provider.createFileStorageConfig()),
60 inject: [FILE_STORAGE_CONFIG_PROVIDER],
61 },
62 ],
63 exports: [FILE_STORAGE],
64 global: true,
65 };
66 }
67}
68
69const createStorage = (config: FileStorageModuleConfig) =>
70 config.driver === "r2"
71 ? new R2FileStorage(config)
72 : new DiskFileStorage(config.baseDir);