From a159a68e2ce0a3de9135a306d2a96e8833bcb6b2 Mon Sep 17 00:00:00 2001 From: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Date: Wed, 13 May 2026 12:08:42 +0200 Subject: [PATCH] `[twenty-server]` no floating promises lint rule (#20499) ## Introduction That's an audit + RFC ## Fire-and-forget (`void`) -- Intentional, correct These are telemetry, metrics, and audit logging in hot paths or non-critical contexts. `void` is the right choice. | File | What was voided | |---|---| | `sign-in-up.service.ts` | `metricsService.incrementCounter` (sign-up metric) + `auditService.insertWorkspaceEvent` (workspace created) | | `use-graphql-error-handler.hook.ts` | 5x `metricsService.incrementCounter` (GraphQL operation metrics) | | `bullmq.driver.ts` | 2x `metricsService.incrementCounter` (job completed/failed metrics) | | `call-webhook.job.ts` | 2x `auditService.insertWorkspaceEvent` + 1x `metricsService.incrementCounter` | | `custom-domain-manager.service.ts` | `analytics.insertWorkspaceEvent` (domain activation event) | | `logic-function-executor.service.ts` | `auditService.insertWorkspaceEvent` (function execution) | | `workflow-runner.workspace-service.ts` | `metricsService.incrementCounter` (throttle metric) | | `cleaner.workspace-service.ts` | `metricsService.incrementCounter` (deleted workspace metric) | | `stream-agent-chat.job.ts` | Detached IIFE for streaming chunks (intentional concurrent pipeline) | | `workspace-auth-context.middleware.ts` | `withWorkspaceAuthContext(...)` (AsyncLocalStorage, returns void anyway) | ## Top-level script entry points (`void bootstrap()`) These are module-level calls where the promise has no consumer. `void` makes the lint rule happy and documents the intent. | File | What changed | |---|---| | `main.ts` | `void bootstrap()` | | `command.ts` | `void bootstrap()` | | `queue-worker.ts` | `void bootstrap()` | | `truncate-db.ts` | `void dropSchemasSequentially()` | | `codegen/index.ts` | `void generateTests(forceArg)` | ## Now properly awaited -- Real bug fixes These were floating promises that could silently fail, lose data, or cause race conditions. | File | What was fixed | |---|---| | `billing-sync-plans-data.command.ts` | `meters.map(async ...)` wrapped in `Promise.all` -- was returning before upserts finished | | `cache-storage.service.ts` | `setAdd` and `setPop` had `.then()` chains that weren't returned/awaited | | `create-audit-log-from-internal-event.ts` | 4x `auditService.createObjectEvent` now awaited inside a job | | `cleaner.workspace-service.ts` | 2x `emailService.send(...)` now awaited -- emails could silently fail | | `agent-async-executor.service.ts` | `calculateAndBillUsage` + `billNativeWebSearchUsage` in `finally` block now awaited | | `repair-tool-call.util.ts` | `calculateAndBillUsage` now awaited | | `agent-title-generation.service.ts` | `calculateAndBillUsage` now awaited | | `chat-execution.service.ts` | `billNativeWebSearchUsage` now awaited | | `ai-generate-text.controller.ts` | `calculateAndBillUsage` in `finally` block now awaited | | `agent-turn.resolver.ts` | `messageQueueService.add(...)` now awaited | | `command.ts` | `app.close()` now awaited (was exiting before graceful shutdown) | | `i18n.service.ts` | `loadTranslations()` in `onModuleInit` now awaited | | `workspace-query-hook.explorer.ts` | `explore()` in `onModuleInit` now awaited | | `message-queue.explorer.ts` | `handleProcessorGroupCollection` in `onModuleInit` now awaited | | `ai-billing.service.spec.ts` | Test now properly `await`s the async call | | `messaging-messages-import.service.spec.ts` | `expect(...)` now properly `await`ed for async assertion | | `archive.finalize()` (3 files) | Voided -- promise resolution already handled by `pipeline()` / `on('end')` | ## Impersonation & security audit trail -- Upgraded from `void` to `await` These were previously fire-and-forget but are security/compliance-critical events that must be reliably persisted. | File | What was fixed | |---|---| | `impersonation.service.ts` | 4x `auditService.insertWorkspaceEvent` now awaited (impersonation attempt, token generation attempt/success/failure) | | `auth.resolver.ts` | 5x `auditService.insertWorkspaceEvent` now awaited (impersonation token exchange attempt/success/failure at server and workspace levels) | | `auth.service.ts` | 2x `analytics.insertWorkspaceEvent` now awaited (impersonation attempted/issued) | ## Billing audit -- Upgraded from `void` to `await` Payment events should be reliably persisted for financial/compliance reporting. | File | What was fixed | |---|---| | `billing-webhook-invoice.service.ts` | `auditService.insertWorkspaceEvent(PAYMENT_RECEIVED_EVENT)` now awaited inside Stripe webhook handler | ## Fire-and-forget with proper error handling -- Upgraded from bare `void` These remain non-blocking but now catch and log errors instead of risking unhandled rejections. | File | What was fixed | |---|---| | `logic-function-executor.service.ts` | `applicationLogsService.writeLogs` now uses `.catch()` instead of bare `void` -- user-facing logs should surface errors | ## Systemic infrastructure fixes | File | What was fixed | |---|---| | `metrics.service.ts` | `incrementCounter`: Redis cache write (`metricsCacheService.updateCounter`) now uses `.catch()` internally instead of raw `await` -- prevents unhandled rejections across all `void metricsService.incrementCounter(...)` call sites when Redis is unhealthy | | `audit.service.ts` | `preventIfDisabled`: made properly `async` with `await` and consistent `Promise<{ success: boolean }>` return type. Removed broken `catch` that returned an `AuditException` as a value (wrong constructor args, unreachable dead code). Removed unused `AuditException` import | ## Fixed in this session (beyond original PR) | File | What changed | |---|---| | `telemetry.listener.ts` | Removed misleading `Promise.all` + `void` combo; replaced with simple `for...of` + `void` | | `message-queue.explorer.ts` | Changed from `void` to `await` so startup crashes on registration failure | --- packages/twenty-server/.oxlintrc.json | 4 +++ packages/twenty-server/src/command/command.ts | 4 +-- .../src/database/scripts/truncate-db.ts | 2 +- .../listeners/telemetry.listener.ts | 8 ++--- .../workspace-query-hook.explorer.ts | 4 +-- .../create-audit-log-from-internal-event.ts | 8 ++--- .../audit/services/audit.service.ts | 21 ++++++------ .../engine/core-modules/auth/auth.resolver.ts | 10 +++--- .../workspace-auth-context.middleware.ts | 2 +- .../auth/services/auth.service.ts | 4 +-- .../auth/services/sign-in-up.service.ts | 4 +-- .../billing-webhook-invoice.service.ts | 2 +- .../billing-sync-plans-data.command.ts | 30 ++++++++-------- .../services/cache-storage.service.ts | 34 +++++++++---------- .../services/custom-domain-manager.service.ts | 2 +- .../hooks/use-graphql-error-handler.hook.ts | 12 ++++--- .../engine/core-modules/i18n/i18n.service.ts | 2 +- .../services/impersonation.service.ts | 8 ++--- .../constants/yarn-install/index.mjs | 2 +- .../drivers/lambda.driver.ts | 2 +- .../utils/create-zip-file.ts | 2 +- .../logic-function-executor.service.ts | 6 ++-- .../message-queue/drivers/bullmq.driver.ts | 6 ++-- .../message-queue-driver.interface.ts | 9 ++--- .../message-queue/drivers/sync.driver.ts | 3 +- .../message-queue/message-queue.explorer.ts | 2 +- .../services/message-queue.service.ts | 4 +-- .../core-modules/metrics/metrics.service.ts | 6 +++- .../services/agent-async-executor.service.ts | 4 +-- .../resolvers/agent-turn.resolver.ts | 2 +- .../ai-agent/utils/repair-tool-call.util.ts | 2 +- .../__tests__/ai-billing.service.spec.ts | 4 +-- .../ai/ai-chat/jobs/stream-agent-chat.job.ts | 2 +- .../agent-title-generation.service.ts | 2 +- .../services/chat-execution.service.ts | 2 +- .../ai-generate-text.controller.ts | 2 +- .../webhook/jobs/call-webhook.job.ts | 6 ++-- .../services/cleaner.workspace-service.ts | 18 +++++----- packages/twenty-server/src/main.ts | 2 +- .../messaging-messages-import.service.spec.ts | 2 +- .../workflow-runner.workspace-service.ts | 2 +- .../src/queue-worker/queue-worker.ts | 2 +- .../test/integration/graphql/codegen/index.ts | 2 +- 43 files changed, 135 insertions(+), 122 deletions(-) diff --git a/packages/twenty-server/.oxlintrc.json b/packages/twenty-server/.oxlintrc.json index baef322f64..8973834fac 100644 --- a/packages/twenty-server/.oxlintrc.json +++ b/packages/twenty-server/.oxlintrc.json @@ -2,6 +2,9 @@ "$schema": "./node_modules/oxlint/configuration_schema.json", "plugins": ["typescript", "import", "unicorn"], "jsPlugins": ["../twenty-oxlint-rules/dist/oxlint-plugin.mjs"], + "options": { + "typeAware": true + }, "categories": { "correctness": "off" }, @@ -53,6 +56,7 @@ }], "typescript/no-empty-function": "off", "typescript/no-explicit-any": "warn", + "typescript/no-floating-promises": "error", "typescript/no-unused-vars": ["warn", { "vars": "all", "varsIgnorePattern": "^_", diff --git a/packages/twenty-server/src/command/command.ts b/packages/twenty-server/src/command/command.ts index 7e0e28a267..e2685a2e62 100644 --- a/packages/twenty-server/src/command/command.ts +++ b/packages/twenty-server/src/command/command.ts @@ -31,6 +31,6 @@ async function bootstrap() { await CommandFactory.runApplication(app); - app.close(); + await app.close(); } -bootstrap(); +void bootstrap(); diff --git a/packages/twenty-server/src/database/scripts/truncate-db.ts b/packages/twenty-server/src/database/scripts/truncate-db.ts index 6c31792c52..fbd7566f47 100644 --- a/packages/twenty-server/src/database/scripts/truncate-db.ts +++ b/packages/twenty-server/src/database/scripts/truncate-db.ts @@ -41,4 +41,4 @@ async function dropSchemasSequentially() { } } -dropSchemasSequentially(); +void dropSchemasSequentially(); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener.ts index 6eaed92666..d7458d8efe 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener.ts @@ -4,9 +4,9 @@ import { OnCustomBatchEvent } from 'src/engine/api/graphql/graphql-query-runner/ import { USER_SIGNUP_EVENT_NAME } from 'src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants'; import { AuditService } from 'src/engine/core-modules/audit/services/audit.service'; import { USER_SIGNUP_EVENT } from 'src/engine/core-modules/audit/utils/events/workspace-event/user/user-signup'; +import { TelemetryEventType } from 'src/engine/core-modules/telemetry/telemetry-event.type'; import { TelemetryService } from 'src/engine/core-modules/telemetry/telemetry.service'; import { CustomWorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/custom-workspace-batch-event.type'; -import { TelemetryEventType } from 'src/engine/core-modules/telemetry/telemetry-event.type'; @Injectable() export class TelemetryListener { @@ -20,14 +20,14 @@ export class TelemetryListener { payload: CustomWorkspaceEventBatch, ) { await Promise.all( - payload.events.map(async (eventPayload) => { + payload.events.map(async (eventPayload) => this.auditService .createContext({ userId: eventPayload.userId, workspaceId: payload.workspaceId, }) - .insertWorkspaceEvent(USER_SIGNUP_EVENT, {}); - }), + .insertWorkspaceEvent(USER_SIGNUP_EVENT, {}), + ), ); await this.telemetryService.publish({ diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer.ts index 703af060fb..f7ba0d4733 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer.ts @@ -41,8 +41,8 @@ export class WorkspaceQueryHookExplorer implements OnModuleInit { private readonly workspaceQueryHookStorage: WorkspaceQueryHookStorage, ) {} - onModuleInit() { - this.explore(); + async onModuleInit() { + await this.explore(); } async explore() { diff --git a/packages/twenty-server/src/engine/core-modules/audit/jobs/create-audit-log-from-internal-event.ts b/packages/twenty-server/src/engine/core-modules/audit/jobs/create-audit-log-from-internal-event.ts index 71d3afb464..b6435a8dfb 100644 --- a/packages/twenty-server/src/engine/core-modules/audit/jobs/create-audit-log-from-internal-event.ts +++ b/packages/twenty-server/src/engine/core-modules/audit/jobs/create-audit-log-from-internal-event.ts @@ -35,25 +35,25 @@ export class CreateAuditLogFromInternalEvent { // Since these are object record events, we use createObjectEvent if (workspaceEventBatch.name.endsWith('.updated')) { - auditService.createObjectEvent(OBJECT_RECORD_UPDATED_EVENT, { + await auditService.createObjectEvent(OBJECT_RECORD_UPDATED_EVENT, { ...eventProperties, recordId: eventData.recordId, objectMetadataId: workspaceEventBatch.objectMetadata.id, }); } else if (workspaceEventBatch.name.endsWith('.created')) { - auditService.createObjectEvent(OBJECT_RECORD_CREATED_EVENT, { + await auditService.createObjectEvent(OBJECT_RECORD_CREATED_EVENT, { ...eventProperties, recordId: eventData.recordId, objectMetadataId: workspaceEventBatch.objectMetadata.id, }); } else if (workspaceEventBatch.name.endsWith('.deleted')) { - auditService.createObjectEvent(OBJECT_RECORD_DELETED_EVENT, { + await auditService.createObjectEvent(OBJECT_RECORD_DELETED_EVENT, { ...eventProperties, recordId: eventData.recordId, objectMetadataId: workspaceEventBatch.objectMetadata.id, }); } else if (workspaceEventBatch.name.endsWith('.upserted')) { - auditService.createObjectEvent(OBJECT_RECORD_UPSERTED_EVENT, { + await auditService.createObjectEvent(OBJECT_RECORD_UPSERTED_EVENT, { ...eventProperties, recordId: eventData.recordId, objectMetadataId: workspaceEventBatch.objectMetadata.id, diff --git a/packages/twenty-server/src/engine/core-modules/audit/services/audit.service.ts b/packages/twenty-server/src/engine/core-modules/audit/services/audit.service.ts index 24b78880dc..89539f29bd 100644 --- a/packages/twenty-server/src/engine/core-modules/audit/services/audit.service.ts +++ b/packages/twenty-server/src/engine/core-modules/audit/services/audit.service.ts @@ -1,10 +1,6 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { ClickHouseService } from 'src/database/clickHouse/clickHouse.service'; -import { - AuditException, - AuditExceptionCode, -} from 'src/engine/core-modules/audit/audit.exception'; import { type TrackEventName, type TrackEventProperties, @@ -18,6 +14,8 @@ import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twent @Injectable() export class AuditService { + private readonly logger = new Logger(AuditService.name); + constructor( private readonly twentyConfigService: TwentyConfigService, private readonly clickHouseService: ClickHouseService, @@ -82,16 +80,19 @@ export class AuditService { }; } - private preventIfDisabled( + private async preventIfDisabled( sendEventOrPageviewFunction: () => Promise<{ success: boolean }>, - ) { + ): Promise<{ success: boolean }> { if (!this.twentyConfigService.get('CLICKHOUSE_URL')) { return { success: true }; } + try { - return sendEventOrPageviewFunction(); - } catch (err) { - return new AuditException(err, AuditExceptionCode.INVALID_INPUT); + return await sendEventOrPageviewFunction(); + } catch (error) { + this.logger.error('Failed to persist audit event to ClickHouse', error); + + return { success: false }; } } } diff --git a/packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts b/packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts index 5c300c8597..cf4d212d94 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/auth.resolver.ts @@ -711,7 +711,7 @@ export class AuthResolver { userId: impersonatorUserWorkspace.user.id, }); - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: `${isServerLevelImpersonation ? 'server' : 'workspace'}.impersonation.token_exchange_attempt`, message: `Impersonation token exchange attempt for ${targetUserEmail} by ${impersonatorUserWorkspace.user.id}`, }); @@ -722,7 +722,7 @@ export class AuthResolver { if (isServerLevelImpersonation) { if (!hasServerLevelImpersonatePermission) { - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: 'server.impersonation.token_exchange_failed', message: `Server level impersonation not allowed for ${targetUserEmail} by userId ${impersonatorUserWorkspace.user.id}`, }); @@ -733,7 +733,7 @@ export class AuthResolver { ); } - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: `server.impersonation.token_exchange_success`, message: `Impersonation token exchanged for ${targetUserEmail} by userId ${impersonatorUserWorkspace.user.id}`, }); @@ -755,7 +755,7 @@ export class AuthResolver { }); if (!hasWorkspaceLevelImpersonatePermission) { - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: 'workspace.impersonation.token_exchange_failed', message: `Impersonation not allowed for ${targetUserEmail} by userId ${impersonatorUserWorkspace.user.id}`, }); @@ -765,7 +765,7 @@ export class AuthResolver { ); } - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: 'workspace.impersonation.token_exchange_success', message: `Impersonation token exchanged for ${targetUserEmail} by userId ${impersonatorUserWorkspace.user.id}`, }); diff --git a/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts b/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts index 23c87cd7d8..bb1c0a992c 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts @@ -28,7 +28,7 @@ export class WorkspaceAuthContextMiddleware implements NestMiddleware { applyWorkspaceSentryContext(authContext); - withWorkspaceAuthContext(authContext, () => { + void withWorkspaceAuthContext(authContext, () => { next(); }); } diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/auth.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/auth.service.ts index c08d1c6b2a..14f4a10d0a 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/auth.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/auth.service.ts @@ -432,7 +432,7 @@ export class AuthService { userId: _impersonatorUserId, }); - analytics.insertWorkspaceEvent('Monitoring', { + await analytics.insertWorkspaceEvent('Monitoring', { eventName: 'workspace.impersonation.attempted', message: `correlationId=${correlationId}; impersonatorUserWorkspaceId=${impersonatorUserWorkspaceId}; targetUserWorkspaceId=${impersonatedUserWorkspaceId}; workspaceId=${workspaceId}`, }); @@ -458,7 +458,7 @@ export class AuthService { true, ); - analytics.insertWorkspaceEvent('Monitoring', { + await analytics.insertWorkspaceEvent('Monitoring', { eventName: 'workspace.impersonation.issued', message: `correlationId=${correlationId}; impersonatorUserWorkspaceId=${impersonatorUserWorkspaceId}; targetUserWorkspaceId=${impersonatedUserWorkspaceId}; workspaceId=${workspaceId}`, }); diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts index 0a6bef8389..116d681a2e 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts @@ -384,7 +384,7 @@ export class SignInUpService { undefined, ); - this.metricsService.incrementCounter({ + void this.metricsService.incrementCounter({ key: MetricsKeys.SignUpSuccess, shouldStoreInCache: false, }); @@ -597,7 +597,7 @@ export class SignInUpService { await queryRunner.commitTransaction(); - this.auditService + void this.auditService .createContext({ workspaceId }) .insertWorkspaceEvent(WORKSPACE_CREATED_EVENT, {}); diff --git a/packages/twenty-server/src/engine/core-modules/billing-webhook/services/billing-webhook-invoice.service.ts b/packages/twenty-server/src/engine/core-modules/billing-webhook/services/billing-webhook-invoice.service.ts index 1e106838a1..78756dcb3f 100644 --- a/packages/twenty-server/src/engine/core-modules/billing-webhook/services/billing-webhook-invoice.service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing-webhook/services/billing-webhook-invoice.service.ts @@ -228,7 +228,7 @@ export class BillingWebhookInvoiceService { if (isDefined(billingCustomer)) { await this.delaySuspendedWorkspaceCleanup(billingCustomer); - this.auditService + await this.auditService .createContext({ workspaceId: billingCustomer.workspaceId }) .insertWorkspaceEvent(PAYMENT_RECEIVED_EVENT, { amountPaid: data.object.amount_paid, diff --git a/packages/twenty-server/src/engine/core-modules/billing/commands/billing-sync-plans-data.command.ts b/packages/twenty-server/src/engine/core-modules/billing/commands/billing-sync-plans-data.command.ts index 0874bdeb83..7aaa8785cb 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/commands/billing-sync-plans-data.command.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/commands/billing-sync-plans-data.command.ts @@ -46,21 +46,23 @@ export class BillingSyncPlansDataCommand extends MigrationCommandRunner { meters: Stripe.Billing.Meter[], options: MigrationCommandOptions, ) { - meters.map(async (meter) => { - try { - if (!options.dryRun) { - await this.billingMeterRepository.upsert( - transformStripeMeterToDatabaseMeter(meter), - { - conflictPaths: ['stripeMeterId'], - }, - ); + await Promise.all( + meters.map(async (meter) => { + try { + if (!options.dryRun) { + await this.billingMeterRepository.upsert( + transformStripeMeterToDatabaseMeter(meter), + { + conflictPaths: ['stripeMeterId'], + }, + ); + } + this.logger.log(`Upserted meter: ${meter.id}`); + } catch (error) { + this.logger.error(`Error upserting meter ${meter.id}: ${error}`); } - this.logger.log(`Upserted meter: ${meter.id}`); - } catch (error) { - this.logger.error(`Error upserting meter ${meter.id}: ${error}`); - } - }); + }), + ); } private async upsertProductRepositoryData( diff --git a/packages/twenty-server/src/engine/core-modules/cache-storage/services/cache-storage.service.ts b/packages/twenty-server/src/engine/core-modules/cache-storage/services/cache-storage.service.ts index c914368a6d..86545a983f 100644 --- a/packages/twenty-server/src/engine/core-modules/cache-storage/services/cache-storage.service.ts +++ b/packages/twenty-server/src/engine/core-modules/cache-storage/services/cache-storage.service.ts @@ -97,13 +97,13 @@ export class CacheStorageService { return; } - this.get(key).then((res: string[]) => { - if (res) { - this.set(key, [...res, ...value], ttl); - } else { - this.set(key, value, ttl); - } - }); + const res = await this.get(key); + + if (res) { + await this.set(key, [...res, ...value], ttl); + } else { + await this.set(key, value, ttl); + } } async setRemove(key: string, values: string[]): Promise { @@ -146,15 +146,15 @@ export class CacheStorageService { ); } - return this.get(key).then((res: string[]) => { - if (res) { - this.set(key, res.slice(0, -size)); + const res = await this.get(key); - return res.slice(-size); - } + if (res) { + await this.set(key, res.slice(0, -size)); - return []; - }); + return res.slice(-size); + } + + return []; } async getSetLength(key: string) { @@ -164,9 +164,9 @@ export class CacheStorageService { ); } - return this.get(key).then((res: string[]) => { - return res.length; - }); + const res = await this.get(key); + + return res?.length ?? 0; } async setMembers(key: string): Promise { diff --git a/packages/twenty-server/src/engine/core-modules/domain/custom-domain-manager/services/custom-domain-manager.service.ts b/packages/twenty-server/src/engine/core-modules/domain/custom-domain-manager/services/custom-domain-manager.service.ts index f1428159bd..30756864a2 100644 --- a/packages/twenty-server/src/engine/core-modules/domain/custom-domain-manager/services/custom-domain-manager.service.ts +++ b/packages/twenty-server/src/engine/core-modules/domain/custom-domain-manager/services/custom-domain-manager.service.ts @@ -114,7 +114,7 @@ export class CustomDomainManagerService { workspaceId: workspace.id, }); - analytics.insertWorkspaceEvent( + void analytics.insertWorkspaceEvent( workspace.isCustomDomainEnabled ? CUSTOM_DOMAIN_ACTIVATED_EVENT : CUSTOM_DOMAIN_DEACTIVATED_EVENT, diff --git a/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts b/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts index 957b34e4ba..87f643c158 100644 --- a/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts +++ b/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts @@ -116,7 +116,7 @@ export const useGraphQLErrorHandlerHook = < setResult, }) => { if (!result.errors || result.errors.length === 0) { - options.metricsService.incrementCounter({ + void options.metricsService.incrementCounter({ key: MetricsKeys.GraphqlOperation200, }); @@ -178,9 +178,11 @@ export const useGraphQLErrorHandlerHook = < } if (metricKey) { - options.metricsService.incrementCounter({ key: metricKey }); + void options.metricsService.incrementCounter({ + key: metricKey, + }); } else { - options.metricsService.incrementCounter({ + void options.metricsService.incrementCounter({ key: MetricsKeys.GraphqlOperationUnknown, }); } @@ -280,7 +282,7 @@ export const useGraphQLErrorHandlerHook = < isDefined(currentMetadataVersion) && requestMetadataVersion !== `${currentMetadataVersion}` ) { - options.metricsService.incrementCounter({ + void options.metricsService.incrementCounter({ key: MetricsKeys.SchemaVersionMismatch, }); @@ -310,7 +312,7 @@ export const useGraphQLErrorHandlerHook = < isDefined(backendMajor) && frontEndMajor < backendMajor ) { - options.metricsService.incrementCounter({ + void options.metricsService.incrementCounter({ key: MetricsKeys.AppVersionMismatch, }); throw new GraphQLError(APP_VERSION_MISMATCH_ERROR, { diff --git a/packages/twenty-server/src/engine/core-modules/i18n/i18n.service.ts b/packages/twenty-server/src/engine/core-modules/i18n/i18n.service.ts index 4c8ca4e78d..42d26eea97 100644 --- a/packages/twenty-server/src/engine/core-modules/i18n/i18n.service.ts +++ b/packages/twenty-server/src/engine/core-modules/i18n/i18n.service.ts @@ -113,6 +113,6 @@ export class I18nService implements OnModuleInit { } async onModuleInit() { - this.loadTranslations(); + await this.loadTranslations(); } } diff --git a/packages/twenty-server/src/engine/core-modules/impersonation/services/impersonation.service.ts b/packages/twenty-server/src/engine/core-modules/impersonation/services/impersonation.service.ts index b1b32bb039..0581783623 100644 --- a/packages/twenty-server/src/engine/core-modules/impersonation/services/impersonation.service.ts +++ b/packages/twenty-server/src/engine/core-modules/impersonation/services/impersonation.service.ts @@ -159,13 +159,13 @@ export class ImpersonationService { userId: impersonatorUserWorkspace.userId, }); - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: `${impersonationLevel}.impersonation.attempt`, message: `Impersonation attempt: targetUserId=${toImpersonateUserWorkspace.user.id}, workspaceId=${toImpersonateUserWorkspace.workspace.id}, impersonatorUserId=${impersonatorUserWorkspace.user.id}`, }); try { - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: `${impersonationLevel}.impersonation.login_token_attempt`, message: `Impersonation token generation attempt for user ${toImpersonateUserWorkspace.user.id}`, }); @@ -179,7 +179,7 @@ export class ImpersonationService { }, ); - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: `${impersonationLevel}.impersonation.login_token_generated`, message: `Impersonation token generated successfully for user ${toImpersonateUserWorkspace.user.id}`, }); @@ -194,7 +194,7 @@ export class ImpersonationService { loginToken, }; } catch { - auditService.insertWorkspaceEvent(MONITORING_EVENT, { + await auditService.insertWorkspaceEvent(MONITORING_EVENT, { eventName: `${impersonationLevel}.impersonation.login_token_failed`, message: `Impersonation token generation failed for targetUserId=${toImpersonateUserWorkspace.user.id}`, }); diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/yarn-install/index.mjs b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/yarn-install/index.mjs index 50d71b2d65..f2fc9c9ce3 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/yarn-install/index.mjs +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/yarn-install/index.mjs @@ -72,7 +72,7 @@ const createZip = async (buildDir, zipPath) => { const p = pipeline(archive, output); archive.directory(buildDir, false); - archive.finalize(); + void archive.finalize(); return p; }; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver.ts index 6a15eaf237..11e53b3e26 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver.ts @@ -807,7 +807,7 @@ export class LambdaDriver implements LogicFunctionDriver { await new Promise((resolve, reject) => { archive.on('end', resolve); archive.on('error', reject); - archive.finalize(); + void archive.finalize(); }); return Buffer.concat(chunks); diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/create-zip-file.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/create-zip-file.ts index 994f546a42..e6fe0b827a 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/create-zip-file.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/create-zip-file.ts @@ -15,7 +15,7 @@ export const createZipFile = async ( const p = pipeline(archive, output); archive.directory(sourceDir, false); - archive.finalize(); + void archive.finalize(); return p; }; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts index 6af78e674e..8a14f825f6 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts @@ -332,7 +332,9 @@ export class LogicFunctionExecutorService { executionId, })); - this.applicationLogsService.writeLogs(logEntries); + void this.applicationLogsService.writeLogs(logEntries).catch((error) => { + this.logger.error('Failed to persist application logs', error); + }); await this.subscriptionService.publish({ channel: SubscriptionChannel.LOGIC_FUNCTION_LOGS_CHANNEL, @@ -349,7 +351,7 @@ export class LogicFunctionExecutorService { }, }); - this.auditService + void this.auditService .createContext({ workspaceId, }) diff --git a/packages/twenty-server/src/engine/core-modules/message-queue/drivers/bullmq.driver.ts b/packages/twenty-server/src/engine/core-modules/message-queue/drivers/bullmq.driver.ts index dedb66ac09..0830a90188 100644 --- a/packages/twenty-server/src/engine/core-modules/message-queue/drivers/bullmq.driver.ts +++ b/packages/twenty-server/src/engine/core-modules/message-queue/drivers/bullmq.driver.ts @@ -92,7 +92,7 @@ export class BullMQDriver ]); } - async work( + work( queueName: MessageQueue, handler: (job: MessageQueueJob) => Promise, options?: MessageQueueWorkerOptions, @@ -136,7 +136,7 @@ export class BullMQDriver ); this.workerMap[queueName].on('completed', (job) => { - this.metricsService.incrementCounter({ + void this.metricsService.incrementCounter({ key: MetricsKeys.JobCompleted, attributes: { queue: queueName, job_name: job?.name ?? '' }, shouldStoreInCache: false, @@ -148,7 +148,7 @@ export class BullMQDriver return; } - this.metricsService.incrementCounter({ + void this.metricsService.incrementCounter({ key: MetricsKeys.JobFailed, attributes: { queue: queueName, diff --git a/packages/twenty-server/src/engine/core-modules/message-queue/drivers/interfaces/message-queue-driver.interface.ts b/packages/twenty-server/src/engine/core-modules/message-queue/drivers/interfaces/message-queue-driver.interface.ts index 6c8c68087a..117c4d7ade 100644 --- a/packages/twenty-server/src/engine/core-modules/message-queue/drivers/interfaces/message-queue-driver.interface.ts +++ b/packages/twenty-server/src/engine/core-modules/message-queue/drivers/interfaces/message-queue-driver.interface.ts @@ -14,13 +14,11 @@ export interface MessageQueueDriver { data: T, options?: QueueJobOptions, ): Promise; - // @ts-expect-error legacy noImplicitAny work( queueName: MessageQueue, handler: ({ data, id }: { data: T; id: string }) => Promise | void, options?: MessageQueueWorkerOptions, - ); - // @ts-expect-error legacy noImplicitAny + ): void; addCron({ queueName, jobName, @@ -33,8 +31,7 @@ export interface MessageQueueDriver { data: T; options: QueueCronJobOptions; jobId?: string; - }); - // @ts-expect-error legacy noImplicitAny + }): Promise; removeCron({ queueName, jobName, @@ -43,6 +40,6 @@ export interface MessageQueueDriver { queueName: MessageQueue; jobName: string; jobId?: string; - }); + }): Promise; register?(queueName: MessageQueue): void; } diff --git a/packages/twenty-server/src/engine/core-modules/message-queue/drivers/sync.driver.ts b/packages/twenty-server/src/engine/core-modules/message-queue/drivers/sync.driver.ts index 195b2c3090..a5db485ef9 100644 --- a/packages/twenty-server/src/engine/core-modules/message-queue/drivers/sync.driver.ts +++ b/packages/twenty-server/src/engine/core-modules/message-queue/drivers/sync.driver.ts @@ -8,6 +8,7 @@ import { import { type MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; +// Synchronous driver for tests and local dev export class SyncDriver implements MessageQueueDriver { private readonly logger = new Logger(SyncDriver.name); private workersMap: { @@ -50,7 +51,7 @@ export class SyncDriver implements MessageQueueDriver { work( queueName: MessageQueue, handler: (job: MessageQueueJob) => Promise | void, - ) { + ): void { this.logger.log(`Registering handler for queue: ${queueName}`); this.workersMap[queueName] = handler; } diff --git a/packages/twenty-server/src/engine/core-modules/message-queue/message-queue.explorer.ts b/packages/twenty-server/src/engine/core-modules/message-queue/message-queue.explorer.ts index cda7ea2661..fe90a46de3 100644 --- a/packages/twenty-server/src/engine/core-modules/message-queue/message-queue.explorer.ts +++ b/packages/twenty-server/src/engine/core-modules/message-queue/message-queue.explorer.ts @@ -132,7 +132,7 @@ export class MessageQueueExplorer implements OnModuleInit { } } - private async handleProcessorGroupCollection( + private handleProcessorGroupCollection( processorGroupCollection: ProcessorGroup[], queue: MessageQueueService, options?: MessageQueueWorkerOptions, diff --git a/packages/twenty-server/src/engine/core-modules/message-queue/services/message-queue.service.ts b/packages/twenty-server/src/engine/core-modules/message-queue/services/message-queue.service.ts index c966303596..9f13086e33 100644 --- a/packages/twenty-server/src/engine/core-modules/message-queue/services/message-queue.service.ts +++ b/packages/twenty-server/src/engine/core-modules/message-queue/services/message-queue.service.ts @@ -72,7 +72,7 @@ export class MessageQueueService { work( handler: (job: MessageQueueJob) => Promise | void, options?: MessageQueueWorkerOptions, - ) { - return this.driver.work(this.queueName, handler, options); + ): void { + this.driver.work(this.queueName, handler, options); } } diff --git a/packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts b/packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts index 16657e8ce7..6b912c789e 100644 --- a/packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts +++ b/packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts @@ -98,7 +98,11 @@ export class MetricsService { counter.add(1, attributes); if (shouldStoreInCache && eventId) { - await this.metricsCacheService.updateCounter(key, [eventId]); + try { + await this.metricsCacheService.updateCounter(key, [eventId]); + } catch (error) { + this.logger.error(`Failed to update metrics cache for ${key}`, error); + } } if (isDefined(debugLog)) { diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/services/agent-async-executor.service.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/services/agent-async-executor.service.ts index 35cbb9ef73..f0fca5e6d6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/services/agent-async-executor.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/services/agent-async-executor.service.ts @@ -307,7 +307,7 @@ export class AgentAsyncExecutorService { AiExceptionCode.AGENT_EXECUTION_FAILED, ); } finally { - this.aiBillingService.calculateAndBillUsage( + void this.aiBillingService.calculateAndBillUsage( agent?.modelId ?? AUTO_SELECT_SMART_MODEL_ID, { usage: accumulatedUsage, cacheCreationTokens }, workspaceId, @@ -316,7 +316,7 @@ export class AgentAsyncExecutorService { userWorkspaceId, ); - this.aiBillingService.billNativeWebSearchUsage( + void this.aiBillingService.billNativeWebSearchUsage( nativeWebSearchCallCount, workspaceId, userWorkspaceId, diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-monitor/resolvers/agent-turn.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-monitor/resolvers/agent-turn.resolver.ts index 4c9cd71efb..bbdaa5a750 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-monitor/resolvers/agent-turn.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-monitor/resolvers/agent-turn.resolver.ts @@ -80,7 +80,7 @@ export class AgentTurnResolver { }); const savedTurn = await this.turnRepository.save(turn); - this.messageQueueService.add<{ + await this.messageQueueService.add<{ turnId: string; threadId: string; agentId: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/repair-tool-call.util.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/repair-tool-call.util.ts index 5a4af61549..5ded24dbbd 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/repair-tool-call.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/repair-tool-call.util.ts @@ -110,7 +110,7 @@ export const repairToolCall = async ({ ? extractCacheCreationTokensFromSteps(steps) : 0; - billingContext.aiBillingService.calculateAndBillUsage( + void billingContext.aiBillingService.calculateAndBillUsage( billingContext.modelId, { usage, cacheCreationTokens }, billingContext.workspaceId, diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-billing/services/__tests__/ai-billing.service.spec.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-billing/services/__tests__/ai-billing.service.spec.ts index 8e65a733f7..da3136137e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-billing/services/__tests__/ai-billing.service.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-billing/services/__tests__/ai-billing.service.spec.ts @@ -350,8 +350,8 @@ describe('AiBillingService', () => { }); describe('calculateAndBillUsage', () => { - it('should calculate cost and emit billing event when model exists', () => { - service.calculateAndBillUsage( + it('should calculate cost and emit billing event when model exists', async () => { + await service.calculateAndBillUsage( 'gpt-4o', { usage: mockTokenUsage }, 'workspace-1', diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/jobs/stream-agent-chat.job.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/jobs/stream-agent-chat.job.ts index eed7f8dcd2..fd38a26034 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/jobs/stream-agent-chat.job.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/jobs/stream-agent-chat.job.ts @@ -298,7 +298,7 @@ export class StreamAgentChatJob { // Publish all chunks first, then signal completion. This guarantees // message-persisted arrives after every stream-chunk on the client. - (async () => { + void (async () => { try { for await (const chunk of uiStream) { await this.eventPublisherService.publish({ diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/services/agent-title-generation.service.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/services/agent-title-generation.service.ts index 33fb6faee7..100efe760a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/services/agent-title-generation.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/services/agent-title-generation.service.ts @@ -63,7 +63,7 @@ export class AgentTitleGenerationService { ? extractCacheCreationTokensFromSteps(steps) : 0; - this.aiBillingService.calculateAndBillUsage( + void this.aiBillingService.calculateAndBillUsage( defaultModel.modelId, { usage, cacheCreationTokens }, workspaceId, diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/services/chat-execution.service.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/services/chat-execution.service.ts index 27ce4f76ca..e3dc901ee9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/services/chat-execution.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-chat/services/chat-execution.service.ts @@ -315,7 +315,7 @@ export class ChatExecutionService { // billNativeWebSearchUsage short-circuits when count <= 0, so calling // unconditionally is safe regardless of whether native search fired. - this.aiBillingService.billNativeWebSearchUsage( + void this.aiBillingService.billNativeWebSearchUsage( countNativeWebSearchCallsFromSteps(steps), workspace.id, userWorkspaceId, diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-generate-text/controllers/ai-generate-text.controller.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-generate-text/controllers/ai-generate-text.controller.ts index fe24899dc4..7d7eb3c029 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-generate-text/controllers/ai-generate-text.controller.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-generate-text/controllers/ai-generate-text.controller.ts @@ -77,7 +77,7 @@ export class AiGenerateTextController { }; } finally { if (result) { - this.aiBillingService.calculateAndBillUsage( + void this.aiBillingService.calculateAndBillUsage( resolvedModelId, { usage: result.usage, diff --git a/packages/twenty-server/src/engine/metadata-modules/webhook/jobs/call-webhook.job.ts b/packages/twenty-server/src/engine/metadata-modules/webhook/jobs/call-webhook.job.ts index 82da0a4d39..767e208fed 100644 --- a/packages/twenty-server/src/engine/metadata-modules/webhook/jobs/call-webhook.job.ts +++ b/packages/twenty-server/src/engine/metadata-modules/webhook/jobs/call-webhook.job.ts @@ -89,13 +89,13 @@ export class CallWebhookJob { const success = response.status >= 200 && response.status < 300; - auditService.insertWorkspaceEvent(WEBHOOK_RESPONSE_EVENT, { + void auditService.insertWorkspaceEvent(WEBHOOK_RESPONSE_EVENT, { status: response.status, success, ...commonPayload, }); - this.metricsService.incrementCounter({ + void this.metricsService.incrementCounter({ key: MetricsKeys.JobWebhookCallCompleted, shouldStoreInCache: false, }); @@ -105,7 +105,7 @@ export class CallWebhookJob { err.message.includes('internal IP address') && err.message.includes('is not allowed'); - auditService.insertWorkspaceEvent(WEBHOOK_RESPONSE_EVENT, { + void auditService.insertWorkspaceEvent(WEBHOOK_RESPONSE_EVENT, { success: false, ...commonPayload, ...(err.response && { status: err.response.status }), diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/services/cleaner.workspace-service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/services/cleaner.workspace-service.ts index 5b2670f549..52fb5c319c 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/services/cleaner.workspace-service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-cleaner/services/cleaner.workspace-service.ts @@ -134,7 +134,7 @@ export class CleanerWorkspaceService { throw new Error('Workspace member email is missing'); } - this.emailService.send({ + await this.emailService.send({ to: workspaceMember.userEmail, from: `${this.twentyConfigService.get( 'EMAIL_FROM_NAME', @@ -177,18 +177,18 @@ export class CleanerWorkspaceService { if (!dryRun) { for (const workspaceMember of workspaceMembers) { + await this.sendWarningEmail( + workspaceMember, + workspace.displayName, + daysSinceInactive, + ); + await this.userVarsService.set({ userId: workspaceMember.userId, workspaceId: workspace.id, key: USER_WORKSPACE_DELETION_WARNING_SENT_KEY, value: true, }); - - await this.sendWarningEmail( - workspaceMember, - workspace.displayName, - daysSinceInactive, - ); } } } @@ -212,7 +212,7 @@ export class CleanerWorkspaceService { throw new Error('Workspace member email is missing'); } - this.emailService.send({ + await this.emailService.send({ to: workspaceMember.userEmail, from: `${this.twentyConfigService.get( 'EMAIL_FROM_NAME', @@ -356,7 +356,7 @@ export class CleanerWorkspaceService { } await this.workspaceService.deleteWorkspace(workspace.id); - this.metricsService.incrementCounter({ + void this.metricsService.incrementCounter({ key: MetricsKeys.CronJobDeletedWorkspace, shouldStoreInCache: false, }); diff --git a/packages/twenty-server/src/main.ts b/packages/twenty-server/src/main.ts index d1a5b83d24..9b65bfa59e 100644 --- a/packages/twenty-server/src/main.ts +++ b/packages/twenty-server/src/main.ts @@ -93,4 +93,4 @@ const bootstrap = async () => { await app.listen(twentyConfigService.get('NODE_PORT')); }; -bootstrap(); +void bootstrap(); diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-messages-import.service.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-messages-import.service.spec.ts index 1135da8e9f..250661323a 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-messages-import.service.spec.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-messages-import.service.spec.ts @@ -246,7 +246,7 @@ describe('MessagingMessagesImportService', () => { mockMessageChannel.syncStage = MessageChannelSyncStage.MESSAGES_IMPORT_PENDING; - expect( + await expect( service.processMessageBatchImport( mockMessageChannel as MessageChannelEntity, mockConnectedAccount, diff --git a/packages/twenty-server/src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service.ts index a39cd51933..641ba73e81 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service.ts @@ -269,7 +269,7 @@ export class WorkflowRunnerWorkspaceService { return false; } catch { - this.metricsService.incrementCounter({ + void this.metricsService.incrementCounter({ key: MetricsKeys.WorkflowRunThrottled, eventId: workspaceId, }); diff --git a/packages/twenty-server/src/queue-worker/queue-worker.ts b/packages/twenty-server/src/queue-worker/queue-worker.ts index 61ebe2a6b4..68bec8617d 100644 --- a/packages/twenty-server/src/queue-worker/queue-worker.ts +++ b/packages/twenty-server/src/queue-worker/queue-worker.ts @@ -30,4 +30,4 @@ async function bootstrap() { throw err; } } -bootstrap(); +void bootstrap(); diff --git a/packages/twenty-server/test/integration/graphql/codegen/index.ts b/packages/twenty-server/test/integration/graphql/codegen/index.ts index 8229229c4c..5b4c599437 100644 --- a/packages/twenty-server/test/integration/graphql/codegen/index.ts +++ b/packages/twenty-server/test/integration/graphql/codegen/index.ts @@ -212,4 +212,4 @@ const generateTests = async (force = false) => { const forceArg = process.argv.includes('--force'); // Call the function with the parsed argument -generateTests(forceArg); +void generateTests(forceArg);