Skip to content

Commit 69bfa29

Browse files
authored
feat: convert websockets to server-side events (#1587)
* refactor: transition from WebSocket to Server-Sent Events (SSE) for real-time updates - Updated documentation and codebase to replace WebSocket references with SSE, enhancing the real-time communication mechanism. - Modified AGENTS.md, README, and various architecture documents to reflect the shift to SSE for Google Calendar sync and event notifications. - Introduced a new feature document for Google Sync and SSE, detailing the architecture and event flow. - Removed obsolete WebSocket code and dependencies from the backend, ensuring a cleaner and more maintainable codebase. - Updated tests and hooks to utilize SSE, ensuring consistent behavior across the application. * chore(deps): update dependencies in yarn.lock - Updated "@adobe/css-tools" to version 4.4.4. - Removed obsolete "socket.io" and "socket.io-client" dependencies. - Updated "@emnapi/core" and "@emnapi/runtime" to version 1.9.1. - Updated "@napi-rs/wasm-runtime" to version 1.1.2 with peer dependencies. - Bumped "@opentelemetry/api" to version 1.9.1 and "@opentelemetry/core" to version 2.6.1. - Updated "@posthog/core" to version 1.24.3 and "@posthog/types" to version 1.364.1. - Updated "@sinclair/typebox" to version 0.34.49 and "@tanstack/react-store" to version 0.9.3. - Updated "@tanstack/store" to version 0.9.3. * feat(webpack): add alias for Server-Sent Events (SSE) module - Introduced an alias for the SSE module in the webpack configuration, enhancing module resolution and improving code organization. * fix(loaders): handle SuperTokens session checks in test environment - Added a condition in the loadAuthenticated function to return an unauthenticated state when NODE_ENV is set to "test", preventing session checks from blocking navigation during Playwright e2e tests. * refactor(sse): transition to EventEmitter for SSE event handling - Replaced direct EventSource event listeners with an EventEmitter2 instance for improved event management. - Updated hooks to utilize the new sseEmitter for handling SSE events, enhancing modularity and maintainability. - Refactored tests to accommodate the changes in event handling, ensuring consistent behavior across the application. * refactor(sse): update USER_METADATA publishing method and enhance test coverage - Changed the USER_METADATA publishing method in the SSE server to use a response object, improving the handling of server-sent events. - Added a test to ensure that USER_METADATA is not replayed to existing tabs when a new tab opens, enhancing the reliability of the SSE implementation. * refactor(base.driver): streamline event handling in BaseDriver class - Moved the initialization of eventName and dataLine variables outside the loop in the BaseDriver class, improving code clarity and reducing redundancy. - Updated the test file for SSE server to remove redundant comments, enhancing readability while maintaining the test environment setup. * fix(events): ensure proper response handling for SSE stream errors - Added a check to send a 500 status response if an error occurs while opening the SSE stream and headers have not been sent, improving error handling in the EventsController. - Removed obsolete socket alias from jest configuration, streamlining module resolution for the web project. * refactor(sse): improve connection management in SSE server - Updated the connection handling logic in the SSE server to utilize a dedicated method for removing dead connections, enhancing code clarity and maintainability. - Refactored the subscription and error handling processes to ensure proper cleanup of connections, improving overall reliability of the SSE implementation.
1 parent 982383f commit 69bfa29

77 files changed

Lines changed: 1430 additions & 2523 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ This is a Typescript project with a monorepo structure.
123123

124124
### Packages Overview
125125

126-
- `@compass/backend` - Express.js REST API with MongoDB, Google Calendar sync, WebSocket support
126+
- `@compass/backend` - Express.js REST API with MongoDB, Google Calendar sync, Server-Sent Events (SSE)
127127
- `@compass/web` - React/TypeScript frontend with Redux, styled-components, webpack bundling
128128
- `@compass/core` - Shared utilities, types, and business logic
129129
- `@compass/scripts` - CLI tools for building, database operations, user management

docs/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Start with [AGENTS.md](../AGENTS.md) for repo rules, commands, and conventions.
1616
- Auth or session behavior:
1717
[Frontend Runtime Flow](./frontend/frontend-runtime-flow.md),
1818
[Password Auth Flow](./features/password-auth-flow.md),
19-
[Google Sync And Websocket Flow](./features/google-sync-and-websocket-flow.md)
19+
[Google Sync And SSE Flow](./features/google-sync-and-sse-flow.md)
2020
- Event shape or recurrence behavior:
2121
[Event And Task Domain Model](./architecture/event-and-task-domain-model.md),
2222
[Recurrence Handling](./features/recurring-events-handling.md)
@@ -30,7 +30,7 @@ Start with [AGENTS.md](../AGENTS.md) for repo rules, commands, and conventions.
3030
## Runtime Flows
3131

3232
- [Frontend Runtime Flow](./frontend/frontend-runtime-flow.md)
33-
- [Google Sync And Websocket Flow](./features/google-sync-and-websocket-flow.md)
33+
- [Google Sync And SSE Flow](./features/google-sync-and-sse-flow.md)
3434
- [Password Auth Flow](./features/password-auth-flow.md)
3535

3636
## Architecture And Domain
@@ -52,6 +52,6 @@ Start with [AGENTS.md](../AGENTS.md) for repo rules, commands, and conventions.
5252
## Feature Deep Dives
5353

5454
- [Password Auth Flow](./features/password-auth-flow.md)
55-
- [Google Sync And Websocket Flow](./features/google-sync-and-websocket-flow.md)
55+
- [Google Sync And SSE Flow](./features/google-sync-and-sse-flow.md)
5656
- [Recurrence Handling](./features/recurring-events-handling.md)
5757
- [Offline Storage And Migrations](./features/offline-storage-and-migrations.md)

docs/architecture/event-and-task-domain-model.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ It affects:
8585

8686
- query behavior
8787
- sync transitions
88-
- websocket notification type
88+
- SSE notification type
8989
- provider selection when mapping events
9090

9191
For someday events, Compass often behaves as the provider of record instead of Google.

docs/architecture/glossary.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Definition of terms used in the source code and documentation.
5151

5252
**Duck Pattern**: A Redux pattern that co-locates actions, reducers, and selectors in a single file (or directory) for a feature domain.
5353

54-
**WebSocket**: A communication protocol used for real-time bidirectional communication between the frontend and backend. Used to push updates when events change.
54+
**Server-Sent Events (SSE)**: An HTTP-based mechanism where the server pushes named events over a long-lived response. Compass uses one `EventSource` per tab to `GET /api/events/stream` for calendar sync and metadata updates.
5555

5656
**Supertokens**: The authentication library used by Compass to manage user sessions, access tokens, and refresh tokens.
5757

docs/architecture/repo-architecture.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The React frontend. It owns:
1212
- auth/session-aware UI
1313
- event and task interactions
1414
- local offline storage
15-
- websocket listeners
15+
- SSE listeners (`EventSource`)
1616

1717
Key entrypoints:
1818

@@ -29,13 +29,13 @@ The Express + MongoDB backend. It owns:
2929
- Supertokens session enforcement
3030
- event CRUD and recurrence processing
3131
- Google Calendar sync
32-
- websocket fanout
32+
- SSE fanout
3333

3434
Key entrypoints:
3535

3636
- `packages/backend/src/app.ts`
3737
- `packages/backend/src/servers/express/express.server.ts`
38-
- `packages/backend/src/servers/websocket/websocket.server.ts`
38+
- `packages/backend/src/servers/sse/sse.server.ts`
3939

4040
### `packages/core`
4141

@@ -51,7 +51,7 @@ High-value files:
5151
- `packages/core/src/types/event.types.ts`
5252
- `packages/core/src/types/type.utils.ts`
5353
- `packages/core/src/constants/core.constants.ts`
54-
- `packages/core/src/constants/websocket.constants.ts`
54+
- `packages/core/src/constants/sse.constants.ts`
5555

5656
### `packages/scripts`
5757

@@ -73,14 +73,14 @@ The web package imports shared event/task/date concepts from `core` and should n
7373

7474
### Backend -> Core
7575

76-
The backend uses `core` for shared validation, event categories, recurrence scopes, constants, and websocket event names.
76+
The backend uses `core` for shared validation, event categories, recurrence scopes, constants, and SSE event names.
7777

7878
### Web <-> Backend
7979

8080
The web talks to the backend through:
8181

8282
- HTTP APIs
83-
- websocket events
83+
- SSE events
8484
- shared domain types from `core`
8585

8686
## Startup Paths
@@ -102,7 +102,7 @@ The web talks to the backend through:
102102

103103
1. create Express app
104104
2. create HTTP server
105-
3. initialize websocket server on the HTTP server
105+
3. register HTTP routes (SSE is opened per authenticated `GET /api/events/stream`)
106106
4. start Mongo
107107
5. listen on the configured port
108108
6. optionally connect ngrok
@@ -138,5 +138,5 @@ The repo prefers:
138138

139139
- New event field: `core` schema, backend parsing/persistence, web editors/selectors/tests
140140
- New backend endpoint: backend route/controller/service plus maybe shared type in `core`
141-
- New websocket event: `core` constants/types, backend server emitter, web socket hook consumer
141+
- New SSE event: `core` constants/types, backend `sse.server` / `publish`, web SSE hook consumer
142142
- New local persistence behavior: web storage adapter, migration runner, tests

docs/backend/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Compass Backend
22

3-
Backend service for auth/session management, event persistence, Google sync, and websocket notifications.
3+
Backend service for auth/session management, event persistence, Google sync, and SSE notifications.
44

55
## Intent
66

@@ -22,7 +22,7 @@ When changing sync or auth logic:
2222
- Shared error handling:
2323
- `packages/backend/src/common/errors/handlers/error.express.handler.ts`
2424
- Realtime notifications:
25-
- `packages/backend/src/servers/websocket/websocket.server.ts`
25+
- `packages/backend/src/servers/sse/sse.server.ts`
2626

2727
## Primary Backend Workflows
2828

@@ -78,4 +78,4 @@ Observed outcomes include:
7878
- [Backend Request Flow](./backend-request-flow.md)
7979
- [Compass API Documentation](./api-documentation.md)
8080
- [Backend Error Handling](./backend-error-handling.md)
81-
- [Google Sync And Websocket Flow](../features/google-sync-and-websocket-flow.md)
81+
- [Google Sync And SSE Flow](../features/google-sync-and-sse-flow.md)

docs/backend/api-documentation.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ Authenticated user trigger for full import restart:
315315

316316
- middleware: `verifySession()` + `requireGoogleConnectionSession`
317317
- response: `204 No Content`
318-
- import runs asynchronously; progress is surfaced via websocket `IMPORT_GCAL_START` / `IMPORT_GCAL_END`
318+
- import runs asynchronously; progress is surfaced via SSE `IMPORT_GCAL_START` / `IMPORT_GCAL_END`
319319
- body schema (`ImportGCalRequestSchema` in `packages/backend/src/sync/sync.types.ts`):
320320
- optional `force: boolean`
321321
- behavior:
@@ -325,7 +325,7 @@ Authenticated user trigger for full import restart:
325325
### /api/event-change-demo
326326

327327
- `POST /api/event-change-demo`
328-
- debug helper route used to dispatch event-change notifications to a configured demo socket user
328+
- debug helper route used to dispatch event-change notifications to the user id in env `SSE_DEBUG_USER`
329329

330330
### ${SYNC_DEBUG}/import-incremental/:userId
331331

@@ -483,7 +483,7 @@ Standard error response format:
483483
}
484484
```
485485

486-
Google revocation is a first-class error contract used by API and websocket flows:
486+
Google revocation is a first-class error contract used by API and SSE flows:
487487

488488
```json
489489
{

docs/backend/backend-error-handling.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Internal details such as stack traces and operational flags stay server-side.
5454
- Keep `code` stable and machine-oriented. Prefer values like `GOOGLE_ACCOUNT_ALREADY_CONNECTED`.
5555
- Put technical detail in logs, not in the client payload.
5656
- Prefer reusing existing feature error metadata before inventing new names.
57-
- If the error should trigger special auth/sync behavior, verify both API handling and websocket side effects.
57+
- If the error should trigger special auth/sync behavior, verify both API handling and SSE side effects.
5858

5959
## Shared Frontend-Backend Error Pattern
6060

docs/backend/backend-request-flow.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ When adding a public contract, prefer creating or extending a shared schema in `
142142
3. Keep the controller thin: extract params, user id, and response orchestration only.
143143
4. Put business logic in a service.
144144
5. Add or update tests at the controller/service level.
145-
6. If the endpoint affects realtime UI, check whether a websocket notification is also needed.
145+
6. If the endpoint affects realtime UI, check whether an SSE notification is also needed.
146146

147147
## Where Bugs Usually Hide
148148

docs/development/agent-onboarding.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ sed -n '1,260p' packages/core/src/types/event.types.ts
4343
- Event controller: `packages/backend/src/event/controllers/event.controller.ts`
4444
- Event service: `packages/backend/src/event/services/event.service.ts`
4545
- Sync service: `packages/backend/src/sync/services/sync.service.ts`
46-
- Websocket server: `packages/backend/src/servers/websocket/websocket.server.ts`
46+
- SSE server: `packages/backend/src/servers/sse/sse.server.ts`
4747
- Shared event types: `packages/core/src/types/event.types.ts`
48-
- Shared websocket constants: `packages/core/src/constants/websocket.constants.ts`
48+
- Shared SSE event names: `packages/core/src/constants/sse.constants.ts`
4949

5050
## If You Are Touching...
5151

@@ -56,8 +56,8 @@ sed -n '1,260p' packages/core/src/types/event.types.ts
5656
- Backend endpoints:
5757
[Backend Request Flow](../backend/backend-request-flow.md),
5858
[API Documentation](../backend/api-documentation.md)
59-
- Google sync or websocket behavior:
60-
[Google Sync And Websocket Flow](../features/google-sync-and-websocket-flow.md)
59+
- Google sync or SSE behavior:
60+
[Google Sync And SSE Flow](../features/google-sync-and-sse-flow.md)
6161
- Local persistence:
6262
[Offline Storage And Migrations](../features/offline-storage-and-migrations.md)
6363
- Event or task shape:

0 commit comments

Comments
 (0)