@lenne.tech/nest-server 11.32.4 → 11.33.0
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/.claude/rules/architecture.md +16 -0
- package/.claude/rules/configurable-features.md +11 -3
- package/.claude/rules/testing.md +101 -1
- package/CLAUDE.md +5 -0
- package/FRAMEWORK-API.md +58 -3
- package/dist/core/common/helpers/content-disposition.helper.d.ts +1 -0
- package/dist/core/common/helpers/content-disposition.helper.js +14 -0
- package/dist/core/common/helpers/content-disposition.helper.js.map +1 -0
- package/dist/core/common/helpers/file.helper.d.ts +7 -0
- package/dist/core/common/helpers/file.helper.js +21 -4
- package/dist/core/common/helpers/file.helper.js.map +1 -1
- package/dist/core/common/helpers/graceful-shutdown.helper.d.ts +2 -0
- package/dist/core/common/helpers/graceful-shutdown.helper.js +55 -0
- package/dist/core/common/helpers/graceful-shutdown.helper.js.map +1 -0
- package/dist/core/common/helpers/project-name.helper.d.ts +2 -0
- package/dist/core/common/helpers/project-name.helper.js +38 -0
- package/dist/core/common/helpers/project-name.helper.js.map +1 -0
- package/dist/core/common/interfaces/cron-job-config.interface.d.ts +1 -0
- package/dist/core/common/interfaces/server-options.interface.d.ts +39 -0
- package/dist/core/common/services/core-cron-jobs.initializer.d.ts +10 -0
- package/dist/core/common/services/core-cron-jobs.initializer.js +46 -0
- package/dist/core/common/services/core-cron-jobs.initializer.js.map +1 -0
- package/dist/core/common/services/core-cron-jobs.registry.d.ts +8 -0
- package/dist/core/common/services/core-cron-jobs.registry.js +12 -0
- package/dist/core/common/services/core-cron-jobs.registry.js.map +1 -0
- package/dist/core/common/services/core-cron-jobs.service.d.ts +37 -7
- package/dist/core/common/services/core-cron-jobs.service.js +278 -27
- package/dist/core/common/services/core-cron-jobs.service.js.map +1 -1
- package/dist/core/common/services/core-redis-pubsub.d.ts +20 -0
- package/dist/core/common/services/core-redis-pubsub.js +112 -0
- package/dist/core/common/services/core-redis-pubsub.js.map +1 -0
- package/dist/core/common/services/core-redis.service.d.ts +25 -0
- package/dist/core/common/services/core-redis.service.js +154 -0
- package/dist/core/common/services/core-redis.service.js.map +1 -0
- package/dist/core/common/services/core-s3.service.d.ts +51 -0
- package/dist/core/common/services/core-s3.service.js +261 -0
- package/dist/core/common/services/core-s3.service.js.map +1 -0
- package/dist/core/common/services/core-trust-proxy.initializer.d.ts +16 -0
- package/dist/core/common/services/core-trust-proxy.initializer.js +77 -0
- package/dist/core/common/services/core-trust-proxy.initializer.js.map +1 -0
- package/dist/core/common/services/rate-limit-store.d.ts +61 -0
- package/dist/core/common/services/rate-limit-store.js +235 -0
- package/dist/core/common/services/rate-limit-store.js.map +1 -0
- package/dist/core/modules/ai/core-ai-mcp.controller.d.ts +19 -3
- package/dist/core/modules/ai/core-ai-mcp.controller.js +148 -18
- package/dist/core/modules/ai/core-ai-mcp.controller.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai.service.d.ts +7 -2
- package/dist/core/modules/ai/services/core-ai.service.js +24 -20
- package/dist/core/modules/ai/services/core-ai.service.js.map +1 -1
- package/dist/core/modules/auth/core-auth.module.js +4 -1
- package/dist/core/modules/auth/core-auth.module.js.map +1 -1
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.d.ts +1 -1
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js +3 -14
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js.map +1 -1
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.d.ts +12 -10
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js +30 -59
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-email-verification.service.d.ts +8 -2
- package/dist/core/modules/better-auth/core-better-auth-email-verification.service.js +118 -45
- package/dist/core/modules/better-auth/core-better-auth-email-verification.service.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.d.ts +1 -1
- package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.js +2 -11
- package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.d.ts +12 -10
- package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.js +30 -85
- package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-user.mapper.js +0 -1
- package/dist/core/modules/better-auth/core-better-auth-user.mapper.js.map +1 -1
- package/dist/core/modules/file/core-file.controller.d.ts +11 -2
- package/dist/core/modules/file/core-file.controller.js +52 -15
- package/dist/core/modules/file/core-file.controller.js.map +1 -1
- package/dist/core/modules/file/core-file.resolver.d.ts +4 -4
- package/dist/core/modules/file/core-file.resolver.js +23 -16
- package/dist/core/modules/file/core-file.resolver.js.map +1 -1
- package/dist/core/modules/file/core-file.service.d.ts +41 -7
- package/dist/core/modules/file/core-file.service.js +227 -7
- package/dist/core/modules/file/core-file.service.js.map +1 -1
- package/dist/core/modules/file/file-metadata.helper.d.ts +16 -0
- package/dist/core/modules/file/file-metadata.helper.js +33 -0
- package/dist/core/modules/file/file-metadata.helper.js.map +1 -0
- package/dist/core/modules/file/file-roles.helper.d.ts +4 -0
- package/dist/core/modules/file/file-roles.helper.js +53 -0
- package/dist/core/modules/file/file-roles.helper.js.map +1 -0
- package/dist/core/modules/file/file-storage.helper.d.ts +13 -0
- package/dist/core/modules/file/file-storage.helper.js +65 -0
- package/dist/core/modules/file/file-storage.helper.js.map +1 -0
- package/dist/core/modules/file/filesystem-file.helper.d.ts +22 -0
- package/dist/core/modules/file/filesystem-file.helper.js +77 -0
- package/dist/core/modules/file/filesystem-file.helper.js.map +1 -0
- package/dist/core/modules/file/interfaces/file-service-options.interface.d.ts +1 -0
- package/dist/core/modules/file/interfaces/file-upload.interface.d.ts +7 -1
- package/dist/core/modules/file/s3-file.helper.d.ts +37 -0
- package/dist/core/modules/file/s3-file.helper.js +81 -0
- package/dist/core/modules/file/s3-file.helper.js.map +1 -0
- package/dist/core/modules/hub/core-hub.controller.d.ts +8 -8
- package/dist/core/modules/hub/core-hub.controller.js +24 -22
- package/dist/core/modules/hub/core-hub.controller.js.map +1 -1
- package/dist/core/modules/hub/helpers/hub-mask.helper.js +2 -2
- package/dist/core/modules/hub/helpers/hub-mask.helper.js.map +1 -1
- package/dist/core/modules/hub/hub-buffer.d.ts +23 -0
- package/dist/core/modules/hub/hub-buffer.js +101 -0
- package/dist/core/modules/hub/hub-buffer.js.map +1 -0
- package/dist/core/modules/hub/services/core-hub-mailbox.service.d.ts +7 -5
- package/dist/core/modules/hub/services/core-hub-mailbox.service.js +14 -10
- package/dist/core/modules/hub/services/core-hub-mailbox.service.js.map +1 -1
- package/dist/core/modules/hub/services/hub-log-buffer.service.d.ts +5 -2
- package/dist/core/modules/hub/services/hub-log-buffer.service.js +17 -8
- package/dist/core/modules/hub/services/hub-log-buffer.service.js.map +1 -1
- package/dist/core/modules/hub/services/hub-query-profiler.service.d.ts +4 -2
- package/dist/core/modules/hub/services/hub-query-profiler.service.js +13 -7
- package/dist/core/modules/hub/services/hub-query-profiler.service.js.map +1 -1
- package/dist/core/modules/hub/services/hub-trace-buffer.service.d.ts +4 -2
- package/dist/core/modules/hub/services/hub-trace-buffer.service.js +13 -8
- package/dist/core/modules/hub/services/hub-trace-buffer.service.js.map +1 -1
- package/dist/core/modules/migrate/helpers/migration.helper.d.ts +2 -6
- package/dist/core/modules/migrate/helpers/migration.helper.js +4 -4
- package/dist/core/modules/migrate/helpers/migration.helper.js.map +1 -1
- package/dist/core/modules/migrate/migration-runner.d.ts +1 -0
- package/dist/core/modules/migrate/migration-runner.js +4 -0
- package/dist/core/modules/migrate/migration-runner.js.map +1 -1
- package/dist/core/modules/migrate/mongo-state-store.d.ts +1 -0
- package/dist/core/modules/migrate/mongo-state-store.js +98 -9
- package/dist/core/modules/migrate/mongo-state-store.js.map +1 -1
- package/dist/core/modules/system-setup/core-system-setup.service.d.ts +2 -0
- package/dist/core/modules/system-setup/core-system-setup.service.js +31 -1
- package/dist/core/modules/system-setup/core-system-setup.service.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant.guard.d.ts +17 -3
- package/dist/core/modules/tenant/core-tenant.guard.js +92 -15
- package/dist/core/modules/tenant/core-tenant.guard.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant.module.js +3 -4
- package/dist/core/modules/tenant/core-tenant.module.js.map +1 -1
- package/dist/core/modules/tus/core-tus.controller.d.ts +2 -0
- package/dist/core/modules/tus/core-tus.controller.js +29 -3
- package/dist/core/modules/tus/core-tus.controller.js.map +1 -1
- package/dist/core/modules/tus/core-tus.service.d.ts +24 -1
- package/dist/core/modules/tus/core-tus.service.js +182 -28
- package/dist/core/modules/tus/core-tus.service.js.map +1 -1
- package/dist/core/modules/tus/interfaces/tus-config.interface.js +3 -0
- package/dist/core/modules/tus/interfaces/tus-config.interface.js.map +1 -1
- package/dist/core/modules/tus/tus-redis-locker.d.ts +25 -0
- package/dist/core/modules/tus/tus-redis-locker.js +87 -0
- package/dist/core/modules/tus/tus-redis-locker.js.map +1 -0
- package/dist/core/modules/tus/tus.module.d.ts +1 -0
- package/dist/core/modules/tus/tus.module.js +30 -4
- package/dist/core/modules/tus/tus.module.js.map +1 -1
- package/dist/core.module.js +18 -1
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/main.js +2 -1
- package/dist/main.js.map +1 -1
- package/dist/server/modules/file/file.controller.js.map +1 -1
- package/dist/server/modules/file/file.resolver.js +1 -12
- package/dist/server/modules/file/file.resolver.js.map +1 -1
- package/dist/server/modules/file/file.service.d.ts +5 -1
- package/dist/server/modules/file/file.service.js +12 -3
- package/dist/server/modules/file/file.service.js.map +1 -1
- package/dist/server/modules/user/avatar.controller.d.ts +5 -1
- package/dist/server/modules/user/avatar.controller.js +26 -10
- package/dist/server/modules/user/avatar.controller.js.map +1 -1
- package/dist/server/modules/user/user.model.js +3 -2
- package/dist/server/modules/user/user.model.js.map +1 -1
- package/dist/server/modules/user/user.module.js +6 -2
- package/dist/server/modules/user/user.module.js.map +1 -1
- package/dist/server/modules/user/user.service.d.ts +1 -1
- package/dist/server/modules/user/user.service.js +6 -13
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/REQUEST-LIFECYCLE.md +57 -8
- package/docs/security-overrides.md +21 -3
- package/migration-guides/11.32.3-to-11.32.4.md +15 -3
- package/migration-guides/11.32.x-to-11.33.x.md +1551 -0
- package/package.json +74 -42
- package/src/core/common/helpers/content-disposition.helper.ts +90 -0
- package/src/core/common/helpers/file.helper.ts +53 -10
- package/src/core/common/helpers/graceful-shutdown.helper.ts +116 -0
- package/src/core/common/helpers/project-name.helper.ts +71 -0
- package/src/core/common/interfaces/cron-job-config.interface.ts +16 -0
- package/src/core/common/interfaces/server-options.interface.ts +439 -2
- package/src/core/common/services/core-cron-jobs.initializer.ts +39 -0
- package/src/core/common/services/core-cron-jobs.registry.ts +45 -0
- package/src/core/common/services/core-cron-jobs.service.ts +589 -47
- package/src/core/common/services/core-redis-pubsub.ts +183 -0
- package/src/core/common/services/core-redis.service.ts +249 -0
- package/src/core/common/services/core-s3.service.ts +465 -0
- package/src/core/common/services/core-trust-proxy.initializer.ts +112 -0
- package/src/core/common/services/rate-limit-store.ts +492 -0
- package/src/core/modules/ai/README.md +25 -0
- package/src/core/modules/ai/core-ai-mcp.controller.ts +253 -22
- package/src/core/modules/ai/services/core-ai.service.ts +33 -24
- package/src/core/modules/auth/core-auth.module.ts +7 -1
- package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +12 -21
- package/src/core/modules/auth/services/legacy-auth-rate-limiter.service.ts +49 -93
- package/src/core/modules/better-auth/core-better-auth-email-verification.service.ts +202 -66
- package/src/core/modules/better-auth/core-better-auth-rate-limit.middleware.ts +11 -18
- package/src/core/modules/better-auth/core-better-auth-rate-limiter.service.ts +51 -132
- package/src/core/modules/better-auth/core-better-auth-user.mapper.ts +7 -1
- package/src/core/modules/file/INTEGRATION-CHECKLIST.md +108 -0
- package/src/core/modules/file/README.md +277 -53
- package/src/core/modules/file/core-file.controller.ts +168 -12
- package/src/core/modules/file/core-file.resolver.ts +46 -12
- package/src/core/modules/file/core-file.service.ts +482 -16
- package/src/core/modules/file/file-metadata.helper.ts +142 -0
- package/src/core/modules/file/file-roles.helper.ts +110 -0
- package/src/core/modules/file/file-storage.helper.ts +163 -0
- package/src/core/modules/file/filesystem-file.helper.ts +184 -0
- package/src/core/modules/file/interfaces/file-service-options.interface.ts +14 -0
- package/src/core/modules/file/interfaces/file-upload.interface.ts +17 -1
- package/src/core/modules/file/s3-file.helper.ts +209 -0
- package/src/core/modules/hub/README.md +48 -0
- package/src/core/modules/hub/core-hub.controller.ts +18 -16
- package/src/core/modules/hub/helpers/hub-mask.helper.ts +21 -4
- package/src/core/modules/hub/hub-buffer.ts +198 -0
- package/src/core/modules/hub/services/core-hub-mailbox.service.ts +22 -12
- package/src/core/modules/hub/services/hub-log-buffer.service.ts +24 -8
- package/src/core/modules/hub/services/hub-query-profiler.service.ts +9 -6
- package/src/core/modules/hub/services/hub-trace-buffer.service.ts +14 -9
- package/src/core/modules/migrate/README.md +33 -6
- package/src/core/modules/migrate/helpers/migration.helper.ts +13 -6
- package/src/core/modules/migrate/migration-runner.ts +10 -1
- package/src/core/modules/migrate/mongo-state-store.ts +179 -11
- package/src/core/modules/system-setup/README.md +7 -2
- package/src/core/modules/system-setup/core-system-setup.service.ts +95 -1
- package/src/core/modules/tenant/README.md +21 -1
- package/src/core/modules/tenant/core-tenant.guard.ts +135 -14
- package/src/core/modules/tenant/core-tenant.module.ts +8 -4
- package/src/core/modules/tus/INTEGRATION-CHECKLIST.md +93 -21
- package/src/core/modules/tus/README.md +35 -2
- package/src/core/modules/tus/core-tus.controller.ts +64 -12
- package/src/core/modules/tus/core-tus.service.ts +358 -34
- package/src/core/modules/tus/interfaces/tus-config.interface.ts +9 -0
- package/src/core/modules/tus/tus-redis-locker.ts +139 -0
- package/src/core/modules/tus/tus.module.ts +78 -6
- package/src/core.module.ts +26 -1
- package/src/index.ts +10 -0
- package/src/main.ts +7 -1
- package/src/server/modules/file/file.controller.ts +7 -3
- package/src/server/modules/file/file.resolver.ts +5 -17
- package/src/server/modules/file/file.service.ts +42 -3
- package/src/server/modules/user/avatar.controller.ts +39 -9
- package/src/server/modules/user/user.model.ts +9 -3
- package/src/server/modules/user/user.module.ts +12 -3
- package/src/server/modules/user/user.service.ts +20 -17
- package/src/test/README.md +7 -2
- package/src/core/common/helpers/file.helper.spec.ts +0 -145
- package/src/core/common/helpers/logging.helper.spec.ts +0 -61
- package/src/core/common/helpers/process-diagnostics.helper.spec.ts +0 -310
- package/src/core/common/services/brevo.service.spec.ts +0 -266
- package/src/core/modules/file/core-file.controller.spec.ts +0 -164
- package/src/core/modules/hub/core-hub.module.spec.ts +0 -108
- package/src/core/modules/hub/helpers/hub-command-shape.helper.spec.ts +0 -48
- package/src/core/modules/hub/helpers/hub-mask.helper.spec.ts +0 -67
- package/src/core/modules/hub/helpers/hub-mermaid.helper.spec.ts +0 -61
- package/src/core/modules/hub/helpers/hub-shell.helper.spec.ts +0 -106
- package/src/core/modules/hub/hub-config.helper.spec.ts +0 -108
- package/src/core/modules/hub/hub-ring-buffer.spec.ts +0 -95
- package/src/core/modules/hub/services/core-hub-mailbox.service.spec.ts +0 -116
- package/src/core/modules/hub/services/hub-trace-buffer.service.spec.ts +0 -112
- package/src/core/modules/migrate/helpers/migration.helper.spec.ts +0 -85
|
@@ -555,8 +555,21 @@ export interface IBetterAuthRateLimit {
|
|
|
555
555
|
max?: number;
|
|
556
556
|
|
|
557
557
|
/**
|
|
558
|
-
* Maximum number of
|
|
559
|
-
*
|
|
558
|
+
* Maximum number of distinct counters this limiter may hold — the bound on the keyspace a
|
|
559
|
+
* caller can create, since both parts of a counter key are caller-influenced.
|
|
560
|
+
*
|
|
561
|
+
* It means slightly different things per store, because the two have different pressures:
|
|
562
|
+
* - **In-memory store**: live entries in the process. Beyond it, expired entries are evicted
|
|
563
|
+
* first; if everything is still live, new keys fold into shared coarse counters.
|
|
564
|
+
* - **Redis store** (`redis` configured): NEW counters per window, across all replicas. Beyond
|
|
565
|
+
* it, further new keys fold into the same coarse counters until the window rolls over.
|
|
566
|
+
*
|
|
567
|
+
* Either way, saturation degrades towards a COARSER limit — unrelated clients then share a
|
|
568
|
+
* counter and are throttled earlier than their own traffic warrants — never towards no limit.
|
|
569
|
+
*
|
|
570
|
+
* Only Better-Auth exposes this knob. The Legacy Auth limiter has no equivalent config key and
|
|
571
|
+
* uses the same `10000` default on both stores.
|
|
572
|
+
*
|
|
560
573
|
* @default 10000
|
|
561
574
|
*/
|
|
562
575
|
maxEntries?: number;
|
|
@@ -815,6 +828,112 @@ export interface IErrorCode {
|
|
|
815
828
|
autoRegister?: boolean;
|
|
816
829
|
}
|
|
817
830
|
|
|
831
|
+
/**
|
|
832
|
+
* Interface for the file module (GridFS)
|
|
833
|
+
*
|
|
834
|
+
* All three knobs take PLAIN ROLE STRINGS, not `RoleEnum` members, because
|
|
835
|
+
* `@Roles()` itself is `(...roles: string[])`. A project may therefore gate the
|
|
836
|
+
* routes with its own role names (`'company-admin'`, `'editor'`) exactly as it
|
|
837
|
+
* would in a hand-written `@Roles()` call — see `RoleEnum` for the system roles
|
|
838
|
+
* (`S_USER`, `S_VERIFIED`, …) that keep their special meaning.
|
|
839
|
+
*
|
|
840
|
+
* The defaults are deliberately restrictive: a single GridFS bucket is shared by
|
|
841
|
+
* every feature of the consuming project, and the ids identifying its blobs are
|
|
842
|
+
* ObjectIds — not secrets. Widening any of these is a decision the project owner
|
|
843
|
+
* has to make explicitly, and it belongs in `config.env.ts` where it is
|
|
844
|
+
* reviewable, rather than in a decorator override where it is not.
|
|
845
|
+
*
|
|
846
|
+
* ROLES ARE THE COARSE FILTER ONLY. They answer "may this caller reach the
|
|
847
|
+
* route at all", never "may this caller have THIS file". For per-file rules —
|
|
848
|
+
* owner, tenant, published-flag — override `CoreFileService.checkRights()`,
|
|
849
|
+
* which receives the `currentUser` and the resolved file metadata.
|
|
850
|
+
*
|
|
851
|
+
* ⚠ With `multiTenancy` active, a non-system role is validated against
|
|
852
|
+
* `membership.role` rather than `user.roles` (see `CoreTenantGuard`). Since
|
|
853
|
+
* GridFS is accessed through the native driver, `mongooseTenantPlugin` never
|
|
854
|
+
* runs on `fs.files` — the bucket is NOT tenant-scoped. A per-tenant rule must
|
|
855
|
+
* therefore be expressed in `checkRights()`, not by a role name alone.
|
|
856
|
+
*/
|
|
857
|
+
export interface IFileConfig {
|
|
858
|
+
/**
|
|
859
|
+
* Roles allowed to DELETE files (`deleteFile` mutation).
|
|
860
|
+
*
|
|
861
|
+
* Kept separate from `uploadRoles` on purpose: "everyone signed in may upload"
|
|
862
|
+
* is a common and reasonable policy, "everyone signed in may delete anyone's
|
|
863
|
+
* file" almost never is.
|
|
864
|
+
*
|
|
865
|
+
* @default ['admin']
|
|
866
|
+
*/
|
|
867
|
+
deleteRoles?: string[];
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* Roles allowed to DOWNLOAD files and read file info
|
|
871
|
+
* (`GET /files/id/:id`, `GET /files/:filename`, `getFileInfo` query).
|
|
872
|
+
*
|
|
873
|
+
* Note for browser-rendered files: an `<img src>` or `<a href>` cannot send an
|
|
874
|
+
* `Authorization` header, so anything stricter than `S_EVERYONE` only works
|
|
875
|
+
* for those tags when the session travels as a cookie.
|
|
876
|
+
*
|
|
877
|
+
* @default ['admin']
|
|
878
|
+
*/
|
|
879
|
+
downloadRoles?: string[];
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* Storage driver for CoreFileService. Three equivalent options:
|
|
883
|
+
*
|
|
884
|
+
* - `'s3'` — an S3-compatible bucket (needs `s3`). The only driver that
|
|
885
|
+
* survives horizontal scaling.
|
|
886
|
+
* - `'gridfs'` — MongoDB GridFS. No extra infrastructure; bytes share the database.
|
|
887
|
+
* - `'filesystem'` — the local disk (`storageDir`). Pod-local: not shared between
|
|
888
|
+
* replicas and lost on restart unless the path is a mounted volume.
|
|
889
|
+
*
|
|
890
|
+
* **Set explicitly and it is enforced.** If the chosen store is not available,
|
|
891
|
+
* the boot FAILS rather than falling back — a silent fallback would put files
|
|
892
|
+
* in a store the operator does not believe they are in, with no way to tell
|
|
893
|
+
* afterwards which file went where.
|
|
894
|
+
*
|
|
895
|
+
* **Left unset, it is derived**, most capable first:
|
|
896
|
+
* 1. `'s3'` when `s3.bucket` is configured
|
|
897
|
+
* 2. `'gridfs'` when a database is configured
|
|
898
|
+
* 3. `'filesystem'` when neither is
|
|
899
|
+
*
|
|
900
|
+
* A configured-but-unreachable database is an error in its own right (Mongoose
|
|
901
|
+
* fails the boot), never a reason to fall through to the disk.
|
|
902
|
+
*
|
|
903
|
+
* **Metadata always lives in the database**, whichever driver stores the bytes:
|
|
904
|
+
* filename, content type, length and the custom `metadata` a per-file rule
|
|
905
|
+
* reads have to be queryable. Only a project running without a database at all
|
|
906
|
+
* has to keep its own bookkeeping.
|
|
907
|
+
*
|
|
908
|
+
* Orthogonal to the role knobs above: this decides WHERE the bytes live, they
|
|
909
|
+
* decide WHO may reach them. A per-file rule in `checkRights()` works under
|
|
910
|
+
* every driver — `getRawFileInfo()` checks all metadata stores.
|
|
911
|
+
*
|
|
912
|
+
* @default derived — see above
|
|
913
|
+
*/
|
|
914
|
+
storage?: 'filesystem' | 'gridfs' | 's3';
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Directory for the `'filesystem'` storage driver.
|
|
918
|
+
*
|
|
919
|
+
* Relative paths resolve against the process working directory. The directory
|
|
920
|
+
* is created on first write.
|
|
921
|
+
*
|
|
922
|
+
* @default 'uploads/files'
|
|
923
|
+
*/
|
|
924
|
+
storageDir?: string;
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* Roles allowed to UPLOAD files (`uploadFile` / `uploadFiles` mutations).
|
|
928
|
+
*
|
|
929
|
+
* This does NOT cover TUS resumable uploads, which are served by their own
|
|
930
|
+
* controller — configure those via `tus.roles`.
|
|
931
|
+
*
|
|
932
|
+
* @default ['admin']
|
|
933
|
+
*/
|
|
934
|
+
uploadRoles?: string[];
|
|
935
|
+
}
|
|
936
|
+
|
|
818
937
|
/**
|
|
819
938
|
* Interface for JWT configuration (main and refresh)
|
|
820
939
|
*/
|
|
@@ -1792,6 +1911,12 @@ export interface IServerOptions {
|
|
|
1792
1911
|
*/
|
|
1793
1912
|
execAfterInit?: string;
|
|
1794
1913
|
|
|
1914
|
+
/**
|
|
1915
|
+
* Configuration of the file module: where the bytes live (`storage`) and who
|
|
1916
|
+
* may reach them (`downloadRoles` / `uploadRoles` / `deleteRoles`).
|
|
1917
|
+
*/
|
|
1918
|
+
file?: IFileConfig;
|
|
1919
|
+
|
|
1795
1920
|
/**
|
|
1796
1921
|
* Filter configuration and defaults
|
|
1797
1922
|
*/
|
|
@@ -2123,6 +2248,35 @@ export interface IServerOptions {
|
|
|
2123
2248
|
*/
|
|
2124
2249
|
port?: number;
|
|
2125
2250
|
|
|
2251
|
+
/**
|
|
2252
|
+
* Optional central Redis connection used by all distributed features
|
|
2253
|
+
* (rate limiting, cron deduplication, GraphQL subscriptions, caches, Hub collectors).
|
|
2254
|
+
*
|
|
2255
|
+
* Follows the "presence implies enabled" pattern:
|
|
2256
|
+
* - undefined: no Redis — all features fall back to their process-local behavior
|
|
2257
|
+
* - true or {}: enabled with defaults (localhost:6379, db 0)
|
|
2258
|
+
* - { enabled: false, ... }: pre-configured but disabled
|
|
2259
|
+
*
|
|
2260
|
+
* Requires the optional peer dependency `ioredis` to be installed.
|
|
2261
|
+
*
|
|
2262
|
+
* @default undefined (disabled)
|
|
2263
|
+
*/
|
|
2264
|
+
redis?: boolean | IRedisConfig;
|
|
2265
|
+
|
|
2266
|
+
/**
|
|
2267
|
+
* Optional central S3-compatible object storage (AWS S3, MinIO, ...).
|
|
2268
|
+
*
|
|
2269
|
+
* Used by CoreFileService (when `file.storage: 's3'`) and as TUS upload staging.
|
|
2270
|
+
* Follows the "presence implies enabled" pattern; without this config,
|
|
2271
|
+
* files stay in GridFS and TUS stages on local disk as before.
|
|
2272
|
+
*
|
|
2273
|
+
* Requires the optional peer dependency `@aws-sdk/client-s3`
|
|
2274
|
+
* (and `@aws-sdk/s3-request-presigner` for presigned downloads).
|
|
2275
|
+
*
|
|
2276
|
+
* @default undefined (disabled)
|
|
2277
|
+
*/
|
|
2278
|
+
s3?: IS3Config;
|
|
2279
|
+
|
|
2126
2280
|
/**
|
|
2127
2281
|
* Configuration for security pipes and interceptors
|
|
2128
2282
|
*/
|
|
@@ -2391,6 +2545,24 @@ export interface IServerOptions {
|
|
|
2391
2545
|
*/
|
|
2392
2546
|
sha256?: boolean;
|
|
2393
2547
|
|
|
2548
|
+
/**
|
|
2549
|
+
* Delay in milliseconds between receiving a shutdown signal and starting the
|
|
2550
|
+
* NestJS shutdown sequence. Gives load balancers time to deregister the
|
|
2551
|
+
* instance before in-flight connections are drained (zero-downtime deploys).
|
|
2552
|
+
*
|
|
2553
|
+
* Requires `installGracefulShutdown(app)` in main.ts, which REPLACES
|
|
2554
|
+
* `server.enableShutdownHooks()` — keeping both makes Nest close the app in
|
|
2555
|
+
* parallel with the wait, so the delay silently never happens.
|
|
2556
|
+
*
|
|
2557
|
+
* Keep it well below the orchestrator grace period and leave room for the
|
|
2558
|
+
* drain that follows (Compose 10s, Kubernetes 30s, diagnostics watchdog 30s);
|
|
2559
|
+
* exceeding any of them means SIGKILL mid-wait and no shutdown hook runs.
|
|
2560
|
+
* Warns above 10000, capped at 60000.
|
|
2561
|
+
*
|
|
2562
|
+
* @default 0 (no delay)
|
|
2563
|
+
*/
|
|
2564
|
+
shutdownDelayMs?: number;
|
|
2565
|
+
|
|
2394
2566
|
/**
|
|
2395
2567
|
* Configuration for useStaticAssets
|
|
2396
2568
|
*/
|
|
@@ -2458,6 +2630,58 @@ export interface IServerOptions {
|
|
|
2458
2630
|
path?: string;
|
|
2459
2631
|
};
|
|
2460
2632
|
|
|
2633
|
+
/**
|
|
2634
|
+
* Express `trust proxy` setting — how far up the `X-Forwarded-For` chain this app believes.
|
|
2635
|
+
*
|
|
2636
|
+
* **This is what makes `request.ip` correct, and every IP-keyed rate limit depends on it.**
|
|
2637
|
+
* Express derives `req.ip` from the forwarded chain only as far as this setting allows and
|
|
2638
|
+
* otherwise reports the socket peer. Left unset (Express default `false`), an app behind Caddy,
|
|
2639
|
+
* nginx or a Kubernetes ingress sees the PROXY's address on every request — so all clients
|
|
2640
|
+
* collapse onto ONE rate-limit bucket and `auth.rateLimit.max` throttles everybody at once
|
|
2641
|
+
* instead of throttling one attacker. With `redis` configured that limit is enforced exactly
|
|
2642
|
+
* fleet-wide, which makes the collapse total rather than per replica.
|
|
2643
|
+
*
|
|
2644
|
+
* Setting it wrong in the other direction is a bypass: trusting more hops than actually sit in
|
|
2645
|
+
* front of the app lets a client prepend its own `X-Forwarded-For` entry and pick a fresh bucket
|
|
2646
|
+
* per request. Count the hops.
|
|
2647
|
+
*
|
|
2648
|
+
* Accepted values (passed through to `app.set('trust proxy', …)` verbatim):
|
|
2649
|
+
* - `false` — trust nothing, use the socket address (Express default). Also the explicit
|
|
2650
|
+
* "no proxy in front of me" answer, which silences the boot warning below.
|
|
2651
|
+
* - `1` / `2` / … — trust exactly N hops closest to this app. The usual answer: one reverse
|
|
2652
|
+
* proxy is `1`, proxy behind a CDN is `2`.
|
|
2653
|
+
* - `'loopback'` / `'linklocal'` / `'uniquelocal'` — trust those address ranges.
|
|
2654
|
+
* - `'10.0.0.0/8'`, `['loopback', '10.0.0.0/8']` — trust specific addresses or subnets.
|
|
2655
|
+
* - `true` — trust the LEFTMOST entry, i.e. whatever the client sent. Never use this on a
|
|
2656
|
+
* public deployment; it hands every caller its own rate-limit bucket.
|
|
2657
|
+
*
|
|
2658
|
+
* A predicate function is deliberately NOT accepted here, although Express supports one: this
|
|
2659
|
+
* value must survive `NEST_SERVER_CONFIG` / `NSC__*` (JSON) and the ConfigService deep clone,
|
|
2660
|
+
* and hop counts, ranges and subnet lists already cover every real deployment shape. If you do
|
|
2661
|
+
* need a predicate, leave `trustProxy` unset and call `app.set('trust proxy', fn)` in your own
|
|
2662
|
+
* `main.ts` — an unset value is never applied, so nothing overwrites it.
|
|
2663
|
+
*
|
|
2664
|
+
* Applied by `CoreModule` during module init, which happens inside `app.init()` / `app.listen()`
|
|
2665
|
+
* — i.e. AFTER your `main.ts` runs. A configured value therefore takes precedence over an
|
|
2666
|
+
* `app.set('trust proxy', …)` of your own.
|
|
2667
|
+
*
|
|
2668
|
+
* When this is unset and an IP-keyed rate limiter (`auth.rateLimit` / `betterAuth.rateLimit`) is
|
|
2669
|
+
* enabled, the framework logs a warning at boot naming the shared-bucket consequence.
|
|
2670
|
+
*
|
|
2671
|
+
* @default false (Express default — the forwarded chain is not trusted)
|
|
2672
|
+
* @since 11.33.0
|
|
2673
|
+
*
|
|
2674
|
+
* @example
|
|
2675
|
+
* ```typescript
|
|
2676
|
+
* // One reverse proxy (Caddy / nginx / ingress) in front of the app
|
|
2677
|
+
* trustProxy: 1,
|
|
2678
|
+
*
|
|
2679
|
+
* // Nothing in front of the app — explicit, and silences the boot warning
|
|
2680
|
+
* trustProxy: false,
|
|
2681
|
+
* ```
|
|
2682
|
+
*/
|
|
2683
|
+
trustProxy?: boolean | number | string | string[];
|
|
2684
|
+
|
|
2461
2685
|
/**
|
|
2462
2686
|
* TUS resumable upload configuration.
|
|
2463
2687
|
*
|
|
@@ -2488,6 +2712,178 @@ export interface IServerOptions {
|
|
|
2488
2712
|
tus?: boolean | ITusConfig;
|
|
2489
2713
|
}
|
|
2490
2714
|
|
|
2715
|
+
/**
|
|
2716
|
+
* Central Redis connection configuration (see IServerOptions.redis).
|
|
2717
|
+
*
|
|
2718
|
+
* All distributed features share this single configuration. Individual features
|
|
2719
|
+
* automatically use Redis when this is enabled and fall back to their
|
|
2720
|
+
* process-local behavior when it is not.
|
|
2721
|
+
*/
|
|
2722
|
+
export interface IRedisConfig {
|
|
2723
|
+
/**
|
|
2724
|
+
* Redis database index
|
|
2725
|
+
* @default 0
|
|
2726
|
+
*/
|
|
2727
|
+
db?: number;
|
|
2728
|
+
|
|
2729
|
+
/**
|
|
2730
|
+
* Whether Redis is enabled.
|
|
2731
|
+
* Presence of the config object implies true.
|
|
2732
|
+
* @default true (when config object is present)
|
|
2733
|
+
*/
|
|
2734
|
+
enabled?: boolean;
|
|
2735
|
+
|
|
2736
|
+
/**
|
|
2737
|
+
* Redis host
|
|
2738
|
+
* @default 'localhost'
|
|
2739
|
+
*/
|
|
2740
|
+
host?: string;
|
|
2741
|
+
|
|
2742
|
+
/**
|
|
2743
|
+
* Prefix prepended to every framework-managed Redis key
|
|
2744
|
+
* (rate limits, locks, caches, Hub collectors, BullMQ queue prefix).
|
|
2745
|
+
*
|
|
2746
|
+
* Defaults to your own `package.json` name, slugified (`@acme/api` → `acme-api`),
|
|
2747
|
+
* so two applications sharing one Redis do not collide. Set it explicitly only
|
|
2748
|
+
* when sharing IS intended — giving two applications the same prefix makes one
|
|
2749
|
+
* application's BullMQ worker consume the other's scheduled jobs.
|
|
2750
|
+
*
|
|
2751
|
+
* Note: applied by the framework per key — NOT passed as ioredis `keyPrefix`,
|
|
2752
|
+
* which would conflict with BullMQ's own prefix handling.
|
|
2753
|
+
*
|
|
2754
|
+
* @default the slugified `name` from package.json, or 'nest-server' if unreadable
|
|
2755
|
+
*/
|
|
2756
|
+
keyPrefix?: string;
|
|
2757
|
+
|
|
2758
|
+
/**
|
|
2759
|
+
* Additional ioredis options passed through to the client constructor
|
|
2760
|
+
* (e.g. `tls`, `sentinels`, `retryStrategy`).
|
|
2761
|
+
* @default undefined
|
|
2762
|
+
*/
|
|
2763
|
+
options?: Record<string, unknown>;
|
|
2764
|
+
|
|
2765
|
+
/**
|
|
2766
|
+
* Redis password
|
|
2767
|
+
* @default undefined (no auth)
|
|
2768
|
+
*/
|
|
2769
|
+
password?: string;
|
|
2770
|
+
|
|
2771
|
+
/**
|
|
2772
|
+
* Redis port
|
|
2773
|
+
* @default 6379
|
|
2774
|
+
*/
|
|
2775
|
+
port?: number;
|
|
2776
|
+
|
|
2777
|
+
/**
|
|
2778
|
+
* Full Redis connection URL (e.g. 'redis://user:pass@host:6379/0').
|
|
2779
|
+
* Takes precedence over host/port/db/password/username.
|
|
2780
|
+
* @default undefined
|
|
2781
|
+
*/
|
|
2782
|
+
url?: string;
|
|
2783
|
+
|
|
2784
|
+
/**
|
|
2785
|
+
* Redis username (Redis 6+ ACL)
|
|
2786
|
+
* @default undefined
|
|
2787
|
+
*/
|
|
2788
|
+
username?: string;
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
/**
|
|
2792
|
+
* S3-compatible object storage configuration (see IServerOptions.s3).
|
|
2793
|
+
* Works with AWS S3, MinIO, RustFS and other S3-compatible services.
|
|
2794
|
+
*/
|
|
2795
|
+
export interface IS3Config {
|
|
2796
|
+
/**
|
|
2797
|
+
* Access key ID.
|
|
2798
|
+
* Falls back to the AWS SDK default credential chain when omitted
|
|
2799
|
+
* (environment variables, instance profiles, ...).
|
|
2800
|
+
* @default undefined
|
|
2801
|
+
*/
|
|
2802
|
+
accessKeyId?: string;
|
|
2803
|
+
|
|
2804
|
+
/**
|
|
2805
|
+
* Create the configured buckets at startup when they do not exist.
|
|
2806
|
+
*
|
|
2807
|
+
* Off by default: production buckets normally come from infrastructure code, and their
|
|
2808
|
+
* credentials often carry no `CreateBucket` permission. Turn it on for a self-hosted
|
|
2809
|
+
* MinIO/RustFS or a local dev stack. Either way the server verifies the buckets at boot and
|
|
2810
|
+
* logs an actionable error when one is missing, instead of letting the first upload fail with
|
|
2811
|
+
* an opaque 500.
|
|
2812
|
+
*
|
|
2813
|
+
* @default false
|
|
2814
|
+
*/
|
|
2815
|
+
autoCreateBucket?: boolean;
|
|
2816
|
+
|
|
2817
|
+
/**
|
|
2818
|
+
* Bucket for files stored via CoreFileService
|
|
2819
|
+
*/
|
|
2820
|
+
bucket: string;
|
|
2821
|
+
|
|
2822
|
+
/**
|
|
2823
|
+
* Whether S3 is enabled.
|
|
2824
|
+
* Presence of the config object implies true.
|
|
2825
|
+
* @default true (when config object is present)
|
|
2826
|
+
*/
|
|
2827
|
+
enabled?: boolean;
|
|
2828
|
+
|
|
2829
|
+
/**
|
|
2830
|
+
* Custom endpoint URL for S3-compatible services (MinIO, RustFS, ...).
|
|
2831
|
+
* Omit for AWS S3.
|
|
2832
|
+
* @default undefined
|
|
2833
|
+
*/
|
|
2834
|
+
endpoint?: string;
|
|
2835
|
+
|
|
2836
|
+
/**
|
|
2837
|
+
* Use path-style addressing (required by most self-hosted S3 services).
|
|
2838
|
+
* @default false
|
|
2839
|
+
*/
|
|
2840
|
+
forcePathStyle?: boolean;
|
|
2841
|
+
|
|
2842
|
+
/**
|
|
2843
|
+
* Serve downloads as presigned URL redirects instead of streaming
|
|
2844
|
+
* through the API (offloads traffic from the server).
|
|
2845
|
+
* `true` / `{}` enables with defaults.
|
|
2846
|
+
*
|
|
2847
|
+
* The issued URL is a session-less BEARER CAPABILITY: it is authorized once, at issue time, and
|
|
2848
|
+
* afterwards anyone holding the string can download the object until it expires — there is no
|
|
2849
|
+
* revocation short of deleting the object or rotating the signing credentials.
|
|
2850
|
+
* @default false
|
|
2851
|
+
*/
|
|
2852
|
+
presignedDownloads?:
|
|
2853
|
+
| boolean
|
|
2854
|
+
| {
|
|
2855
|
+
/**
|
|
2856
|
+
* Presigned URL validity in seconds.
|
|
2857
|
+
*
|
|
2858
|
+
* Keep it just long enough for a download to START. Values above 900s are accepted but
|
|
2859
|
+
* warned about at boot, and anything above 604800s (the AWS SigV4 maximum, 7 days) is
|
|
2860
|
+
* capped — a longer signature is rejected by S3 rather than honored.
|
|
2861
|
+
* @default 300
|
|
2862
|
+
*/
|
|
2863
|
+
expiresInSeconds?: number;
|
|
2864
|
+
};
|
|
2865
|
+
|
|
2866
|
+
/**
|
|
2867
|
+
* AWS region
|
|
2868
|
+
* @default 'us-east-1'
|
|
2869
|
+
*/
|
|
2870
|
+
region?: string;
|
|
2871
|
+
|
|
2872
|
+
/**
|
|
2873
|
+
* Secret access key.
|
|
2874
|
+
* Falls back to the AWS SDK default credential chain when omitted.
|
|
2875
|
+
* @default undefined
|
|
2876
|
+
*/
|
|
2877
|
+
secretAccessKey?: string;
|
|
2878
|
+
|
|
2879
|
+
/**
|
|
2880
|
+
* Bucket used as staging area for resumable TUS uploads.
|
|
2881
|
+
* Configure a lifecycle rule on this bucket to expire aborted uploads.
|
|
2882
|
+
* @default same as `bucket`
|
|
2883
|
+
*/
|
|
2884
|
+
stagingBucket?: string;
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2491
2887
|
export interface ISystemSetup {
|
|
2492
2888
|
/**
|
|
2493
2889
|
* Whether system setup is enabled.
|
|
@@ -2613,6 +3009,46 @@ export interface ITusConfig {
|
|
|
2613
3009
|
*/
|
|
2614
3010
|
path?: string;
|
|
2615
3011
|
|
|
3012
|
+
/**
|
|
3013
|
+
* Roles allowed to use the tus endpoints (create, write, read offset, terminate).
|
|
3014
|
+
*
|
|
3015
|
+
* Takes plain role strings, like `@Roles()` itself, so a project can use its
|
|
3016
|
+
* own role names here.
|
|
3017
|
+
*
|
|
3018
|
+
* A tus upload writes into the SAME file store that `file.downloadRoles`
|
|
3019
|
+
* guards — GridFS or S3, whichever `file.storage` selects — so leaving this at
|
|
3020
|
+
* `S_EVERYONE` while the download side is restricted means anonymous callers
|
|
3021
|
+
* may write into, and with the termination extension delete from, a store
|
|
3022
|
+
* only privileged callers may read. That asymmetry is rarely intended;
|
|
3023
|
+
* `S_USER` is the safer default for anything reachable from the internet.
|
|
3024
|
+
*
|
|
3025
|
+
* `OPTIONS` is exempt — it is the CORS preflight, which browsers send without
|
|
3026
|
+
* credentials, and it returns only server capabilities.
|
|
3027
|
+
*
|
|
3028
|
+
* @default ['s_user']
|
|
3029
|
+
*/
|
|
3030
|
+
roles?: string[];
|
|
3031
|
+
|
|
3032
|
+
/**
|
|
3033
|
+
* Stage upload chunks in the configured S3 bucket (`IServerOptions.s3`,
|
|
3034
|
+
* `stagingBucket`) instead of local disk, so resumable uploads survive
|
|
3035
|
+
* replica restarts and work without sticky sessions.
|
|
3036
|
+
*
|
|
3037
|
+
* **On by default whenever S3 is usable** — a configured `s3` block with a
|
|
3038
|
+
* `bucket` is enough, no opt-in needed. Set to `false` to force local disk.
|
|
3039
|
+
*
|
|
3040
|
+
* "Usable" is the same test `file.storage`'s automatic default uses: a bucket
|
|
3041
|
+
* must be named. An `s3` block without one is ignored entirely (with a
|
|
3042
|
+
* warning), so staging can never be switched on against a bucket that does
|
|
3043
|
+
* not exist.
|
|
3044
|
+
*
|
|
3045
|
+
* Independent of `file.storage`: chunks may stage in S3 while finished files
|
|
3046
|
+
* are written to GridFS, or the other way round.
|
|
3047
|
+
*
|
|
3048
|
+
* @default true (when S3 is usable)
|
|
3049
|
+
*/
|
|
3050
|
+
s3Staging?: boolean;
|
|
3051
|
+
|
|
2616
3052
|
/**
|
|
2617
3053
|
* Termination extension configuration.
|
|
2618
3054
|
* Allows deleting uploads via DELETE.
|
|
@@ -2622,6 +3058,7 @@ export interface ITusConfig {
|
|
|
2622
3058
|
|
|
2623
3059
|
/**
|
|
2624
3060
|
* Directory for temporary upload chunks.
|
|
3061
|
+
* Only used when uploads are NOT staged in S3 (see `s3Staging`).
|
|
2625
3062
|
* @default 'uploads/tus'
|
|
2626
3063
|
*/
|
|
2627
3064
|
uploadDir?: string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Injectable, OnApplicationShutdown, OnModuleInit, Optional } from '@nestjs/common';
|
|
2
|
+
import { InjectConnection } from '@nestjs/mongoose';
|
|
3
|
+
import { Connection } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { setCronJobsInfrastructure } from './core-cron-jobs.registry';
|
|
6
|
+
import { CoreRedisService } from './core-redis.service';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Populates the cron-jobs infrastructure registry at bootstrap so that
|
|
10
|
+
* CoreCronJobs subclasses get multi-replica deduplication (Redis/BullMQ or
|
|
11
|
+
* Mongo lease) WITHOUT any constructor changes in consumer projects.
|
|
12
|
+
*
|
|
13
|
+
* Registered as a CoreModule provider; consumers never interact with it.
|
|
14
|
+
*/
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class CoreCronJobsInitializer implements OnApplicationShutdown, OnModuleInit {
|
|
17
|
+
constructor(
|
|
18
|
+
@InjectConnection() protected readonly connection: Connection,
|
|
19
|
+
@Optional() protected readonly redisService?: CoreRedisService,
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
onModuleInit(): void {
|
|
23
|
+
setCronJobsInfrastructure({
|
|
24
|
+
connection: this.connection,
|
|
25
|
+
redisService: this.redisService?.enabled ? this.redisService : undefined,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Drop the module-global references again.
|
|
31
|
+
*
|
|
32
|
+
* The registry outlives the application that filled it, so without this a closed app leaves its
|
|
33
|
+
* (now closed) Mongoose connection and Redis service behind for whatever app starts next in the
|
|
34
|
+
* same process — a test suite, or any host that creates more than one application.
|
|
35
|
+
*/
|
|
36
|
+
onApplicationShutdown(): void {
|
|
37
|
+
setCronJobsInfrastructure({});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime registry for the optional cron-job infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* `CoreCronJobs` is abstract and instantiated by the consuming project, so the
|
|
5
|
+
* framework cannot inject the Mongoose connection or `CoreRedisService` into it.
|
|
6
|
+
* Registering them here instead keeps multi-replica deduplication working WITHOUT
|
|
7
|
+
* any change to an existing subclass — the same shape as
|
|
8
|
+
* `core-better-auth.registry.ts`.
|
|
9
|
+
*
|
|
10
|
+
* The file uses only `import type`, which both tsc and SWC erase entirely, so it
|
|
11
|
+
* emits no `require()` at all and is a true leaf: it can never be mid-evaluation
|
|
12
|
+
* when someone imports it (see .claude/rules/architecture.md → "DI Token Placement
|
|
13
|
+
* (SWC-Safe)"). Its exports are hoisted `function` declarations for the same reason.
|
|
14
|
+
*
|
|
15
|
+
* @internal Populated by CoreModule. `CoreCronJobs` reads it lazily on every access,
|
|
16
|
+
* so a registration that happens after the service was constructed still takes effect.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { CoreRedisService } from './core-redis.service';
|
|
20
|
+
import type { Connection } from 'mongoose';
|
|
21
|
+
|
|
22
|
+
export interface CronJobsInfrastructure {
|
|
23
|
+
/** Mongoose connection used for the per-tick MongoDB lease */
|
|
24
|
+
connection?: Connection;
|
|
25
|
+
|
|
26
|
+
/** Central Redis service; enables the BullMQ job-scheduler mode */
|
|
27
|
+
redisService?: CoreRedisService;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let infrastructure: CronJobsInfrastructure = {};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns the registered cron-job infrastructure; empty when nothing was registered.
|
|
34
|
+
*/
|
|
35
|
+
export function getCronJobsInfrastructure(): CronJobsInfrastructure {
|
|
36
|
+
return infrastructure;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Registers the cron-job infrastructure. Pass `{}` to clear it (tests).
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export function setCronJobsInfrastructure(value: CronJobsInfrastructure): void {
|
|
44
|
+
infrastructure = value ?? {};
|
|
45
|
+
}
|