From 8b0cb7e447478fd5c88e293fb2154e5702383db7 Mon Sep 17 00:00:00 2001 From: Wesley Finck Date: Thu, 19 Mar 2026 16:19:21 -0700 Subject: [PATCH] only notify early testers about connections --- .../ConnectionCreatedEventHandler.ts | 51 ++++++++++++++++++- src/shared/constants/featureFlags.ts | 21 ++++++++ .../processes/InMemoryEventWorkerProcess.ts | 2 + .../processes/NotificationWorkerProcess.ts | 2 + src/webapp/lib/serverFeatureFlags.ts | 22 ++------ 5 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 src/shared/constants/featureFlags.ts diff --git a/src/modules/notifications/application/eventHandlers/ConnectionCreatedEventHandler.ts b/src/modules/notifications/application/eventHandlers/ConnectionCreatedEventHandler.ts index 0d45f31f..861ad91c 100644 --- a/src/modules/notifications/application/eventHandlers/ConnectionCreatedEventHandler.ts +++ b/src/modules/notifications/application/eventHandlers/ConnectionCreatedEventHandler.ts @@ -5,6 +5,13 @@ import { NotificationService } from '../../domain/services/NotificationService'; import { IConnectionRepository } from '../../../cards/domain/IConnectionRepository'; import { ICardQueryRepository } from '../../../cards/domain/ICardQueryRepository'; import { CuratorId } from '../../../cards/domain/value-objects/CuratorId'; +import { EnvironmentConfigService } from '../../../../shared/infrastructure/config/EnvironmentConfigService'; +import { IIdentityResolutionService } from '../../../atproto/domain/services/IIdentityResolutionService'; +import { DIDOrHandle } from '../../../atproto/domain/DIDOrHandle'; +import { + TEAM_HANDLES, + EARLY_TESTERS_HANDLES, +} from '../../../../shared/constants/featureFlags'; export class ConnectionCreatedEventHandler implements IEventHandler @@ -13,6 +20,8 @@ export class ConnectionCreatedEventHandler private notificationService: NotificationService, private connectionRepository: IConnectionRepository, private cardQueryRepository: ICardQueryRepository, + private environmentConfigService: EnvironmentConfigService, + private identityResolutionService: IIdentityResolutionService, ) {} async handle(event: ConnectionCreatedEvent): Promise> { @@ -84,8 +93,46 @@ export class ConnectionCreatedEventHandler }); } - // Create notifications for each unique recipient - const notificationPromises = Array.from(recipientUserIds).map( + // Filter recipients based on environment + let filteredRecipientUserIds = Array.from(recipientUserIds); + + // In production, only notify team and early testers + const isProduction = + this.environmentConfigService.get().environment === 'prod'; + if (isProduction) { + const allowedHandles = new Set([ + ...TEAM_HANDLES, + ...EARLY_TESTERS_HANDLES, + ]); + + // Filter to only allowed recipients + const filteredRecipients = await Promise.all( + filteredRecipientUserIds.map(async (recipientUserId) => { + const didOrHandleResult = DIDOrHandle.create(recipientUserId); + if (didOrHandleResult.isErr()) { + return null; + } + + const handleResult = + await this.identityResolutionService.resolveToHandle( + didOrHandleResult.value, + ); + if (handleResult.isErr()) { + return null; + } + + const handle = handleResult.value.value; + return allowedHandles.has(handle) ? recipientUserId : null; + }), + ); + + filteredRecipientUserIds = filteredRecipients.filter( + (id): id is string => id !== null, + ); + } + + // Create notifications for each filtered recipient + const notificationPromises = filteredRecipientUserIds.map( async (recipientUserId) => { const recipientIdResult = CuratorId.create(recipientUserId); if (recipientIdResult.isErr()) { diff --git a/src/shared/constants/featureFlags.ts b/src/shared/constants/featureFlags.ts new file mode 100644 index 00000000..cdd3c63d --- /dev/null +++ b/src/shared/constants/featureFlags.ts @@ -0,0 +1,21 @@ +export const TEAM_HANDLES = new Set([ + 'wesleyfinck.org', + 'ronentk.me', + 'pouriade.com', +]); + +export const EARLY_TESTERS_HANDLES = new Set([ + 'bmann.ca', + 'tynanpurdy.com', + 'erlend.sh', + 'tgoerke.bsky.social', + 'psingletary.com', + 'hilarybaumann.com', + 'cosmik.network', + 'semble.so', + 'atproto.science', + 'chrisshank.com', + 'jasmine-pyz.bsky.social', + 'uppy-hacker.bsky.social', + 'joelchan86.bsky.social', +]); diff --git a/src/shared/infrastructure/processes/InMemoryEventWorkerProcess.ts b/src/shared/infrastructure/processes/InMemoryEventWorkerProcess.ts index 3ff0ced9..765631ac 100644 --- a/src/shared/infrastructure/processes/InMemoryEventWorkerProcess.ts +++ b/src/shared/infrastructure/processes/InMemoryEventWorkerProcess.ts @@ -113,6 +113,8 @@ export class InMemoryEventWorkerProcess implements IProcess { services.notificationService, repositories.connectionRepository, repositories.cardQueryRepository, + this.configService, + services.identityResolutionService, ); // Register feed handlers diff --git a/src/shared/infrastructure/processes/NotificationWorkerProcess.ts b/src/shared/infrastructure/processes/NotificationWorkerProcess.ts index 8bcc5c3b..8296a545 100644 --- a/src/shared/infrastructure/processes/NotificationWorkerProcess.ts +++ b/src/shared/infrastructure/processes/NotificationWorkerProcess.ts @@ -92,6 +92,8 @@ export class NotificationWorkerProcess extends BaseWorkerProcess { services.notificationService, repositories.connectionRepository, repositories.cardQueryRepository, + this.configService, + services.identityResolutionService, ); await subscriber.subscribe( diff --git a/src/webapp/lib/serverFeatureFlags.ts b/src/webapp/lib/serverFeatureFlags.ts index b91594e2..d22822de 100644 --- a/src/webapp/lib/serverFeatureFlags.ts +++ b/src/webapp/lib/serverFeatureFlags.ts @@ -1,22 +1,8 @@ import { getServerAuthStatus } from './serverAuth'; - -const TEAM_HANDLES = new Set(['wesleyfinck.org', 'ronentk.me', 'pouriade.com']); - -const EARLY_TESTERS_HANDLES = new Set([ - 'bmann.ca', - 'tynanpurdy.com', - 'erlend.sh', - 'tgoerke.bsky.social', - 'psingletary.com', - 'hilarybaumann.com', - 'cosmik.network', - 'semble.so', - 'atproto.science', - 'chrisshank.com', - 'jasmine-pyz.bsky.social', - 'uppy-hacker.bsky.social', - 'joelchan86.bsky.social', -]); +import { + TEAM_HANDLES, + EARLY_TESTERS_HANDLES, +} from '../../shared/constants/featureFlags'; export async function getServerFeatureFlags() { const { user } = await getServerAuthStatus(); -- 2.51.2