import { Module } from "@nestjs/common"; import { APP_GUARD, APP_INTERCEPTOR } from "@nestjs/core"; import { HealthModule } from "./modules/health/health.module.js"; import { AuthModule } from "./modules/auth/auth.module.js"; import { UsersModule } from "./modules/users/users.module.js"; import { SessionsModule } from "./modules/sessions/sessions.module.js"; import { WorkspacesModule } from "./modules/workspaces/workspaces.module.js"; import { TeamsModule } from "./modules/teams/teams.module.js"; import { PagesModule } from "./modules/pages/pages.module.js"; import { TasksModule } from "./modules/tasks/tasks.module.js"; import { BlocksModule } from "./modules/blocks/blocks.module.js"; import { DatabasesModule } from "./modules/databases/databases.module.js"; import { FilesModule } from "./modules/files/files.module.js"; import { CommentsModule } from "./modules/comments/comments.module.js"; import { SearchModule } from "./modules/search/search.module.js"; import { NotificationsModule } from "./modules/notifications/notifications.module.js"; import { ShareModule } from "./modules/share/share.module.js"; import { ApiKeysModule } from "./modules/api-keys/api-keys.module.js"; import { AuditModule } from "./modules/audit/audit.module.js"; import { WebhooksModule } from "./modules/webhooks/webhooks.module.js"; import { AutomationsModule } from "./modules/automations/automations.module.js"; import { AiModule } from "./modules/ai/ai.module.js"; import { IntegrationsModule } from "./modules/integrations/integrations.module.js"; import { OauthModule } from "./modules/oauth/oauth.module.js"; import { FormsModule } from "./modules/forms/forms.module.js"; import { OrgsModule } from "./modules/orgs/orgs.module.js"; import { SsoModule } from "./modules/sso/sso.module.js"; import { ScimModule } from "./modules/scim/scim.module.js"; import { OrgModule } from "./modules/org/org.module.js"; import { InternalBlocksModule } from "./modules/internal/internal.module.js"; import { DocsModule } from "./modules/docs/docs.module.js"; import { CoreModule } from "./common/core.module.js"; import { AuthGuard } from "./common/guards/auth.guard.js"; import { RateLimitGuard } from "./common/guards/rate-limit.guard.js"; import { IdempotencyInterceptor } from "./common/middleware/idempotency.js"; import { BigIntSerializationInterceptor } from "./common/interceptors/bigint-serialization.interceptor.js"; import { ActorContextInterceptor } from "./common/interceptors/actor-context.interceptor.js"; /** * Root module. The shared cross-cutting services (Prisma, Redis, EventBus, * Audit, Email) live in the `@Global()` {@link CoreModule} (TASK-0100 S0): * they must be global because NO feature module imports the root — a plain * root-level provider is invisible to feature-module scope, which broke DI * under the tsc runtime (boot failure) and masked itself as `undefined` * injections under tsx/vitest (no `design:paramtypes` metadata). The two * global guards run on every request in order: auth → rate limit, and the * global idempotency interceptor (TASK-0095 R1 — honors the client's * `Idempotency-Key` on authenticated mutations, replaying the stored 24 h * response for a seen key) runs after the guard. */ @Module({ imports: [ CoreModule, HealthModule, AuthModule, UsersModule, SessionsModule, WorkspacesModule, TeamsModule, PagesModule, TasksModule, BlocksModule, DatabasesModule, FilesModule, CommentsModule, SearchModule, NotificationsModule, ShareModule, ApiKeysModule, AuditModule, WebhooksModule, AutomationsModule, AiModule, IntegrationsModule, OauthModule, FormsModule, OrgsModule, SsoModule, ScimModule, OrgModule, InternalBlocksModule, DocsModule, ], providers: [ AuthGuard, RateLimitGuard, ActorContextInterceptor, IdempotencyInterceptor, BigIntSerializationInterceptor, { provide: APP_GUARD, useExisting: AuthGuard }, { provide: APP_GUARD, useExisting: RateLimitGuard }, // Order = nesting (listed first = OUTERMOST): actor-context binds the // request's `req.auth` into the AsyncLocalStorage actor context BEFORE // anything inner runs (TASK-0127 — `assertCan`/`assertRole` apply the // API-key scope rules from that context); idempotency next (its replay // stores the body the handler produced); BigInt conversion innermost so // the stored idempotency body is already JSON-safe. See the // interceptors' class docs for the replay-correctness argument. { provide: APP_INTERCEPTOR, useExisting: ActorContextInterceptor }, { provide: APP_INTERCEPTOR, useExisting: IdempotencyInterceptor }, { provide: APP_INTERCEPTOR, useExisting: BigIntSerializationInterceptor }, ], }) export class AppModule {}