feat(server): realtime notification & task status (#14934)

#### PR Dependency Tree


* **PR #14934** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Full realtime platform added: live notifications, comments, embedding
progress, and transcription task updates via realtime subscriptions.

* **Chores**
* Frontend switched from polling/GraphQL queries to realtime channels;
legacy query fields marked deprecated and client libs updated to use
realtime APIs.

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/toeverything/AFFiNE/pull/14934)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


#### PR Dependency Tree


* **PR #14934** 👈
  * **PR #14936**

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
This commit is contained in:
DarkSky
2026-05-10 23:21:50 +08:00
committed by GitHub
parent 417d31cabe
commit 8cf00738c2
70 changed files with 2378 additions and 283 deletions
@@ -1,3 +1,9 @@
import {
type RealtimeEvent,
type RealtimeRequestEnvelope,
type RealtimeSubscribeEnvelope,
type RealtimeUnsubscribeEnvelope,
} from '@affine/realtime';
import {
Manager as SocketIOManager,
type Socket as SocketIO,
@@ -52,6 +58,8 @@ interface ServerEvents {
docId: string;
awarenessUpdate: string;
};
'realtime:event': RealtimeEvent;
}
interface ClientEvents {
@@ -116,6 +124,10 @@ interface ClientEvents {
'space:delete-doc': { spaceType: string; spaceId: string; docId: string };
'telemetry:batch': [TelemetryBatch, TelemetryAck];
'realtime:request': [RealtimeRequestEnvelope, unknown];
'realtime:subscribe': [RealtimeSubscribeEnvelope, { subscriptionId: string }];
'realtime:unsubscribe': [RealtimeUnsubscribeEnvelope, { ok: true }];
}
export type ServerEventsMap = {
@@ -227,10 +239,11 @@ class SocketManager {
const SOCKET_MANAGER_CACHE = new Map<string, SocketManager>();
function getSocketManager(endpoint: string, isSelfHosted: boolean) {
let manager = SOCKET_MANAGER_CACHE.get(endpoint);
const key = `${endpoint}:${isSelfHosted ? 'selfhosted' : 'cloud'}`;
let manager = SOCKET_MANAGER_CACHE.get(key);
if (!manager) {
manager = new SocketManager(endpoint, isSelfHosted);
SOCKET_MANAGER_CACHE.set(endpoint, manager);
SOCKET_MANAGER_CACHE.set(key, manager);
}
return manager;
}