snapshot of https://github.com/toeverything/AFFiNE.git (canary, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 4s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Analyze (javascript, affine) (push) Failing after 3s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-16 00:31:07 +05:00
commit 50f788e799
7907 changed files with 988785 additions and 0 deletions

View File

@@ -0,0 +1,231 @@
import {
type AwarenessRecord,
AwarenessStorageBase,
} from '../../storage/awareness';
import type { SpaceType } from '../../utils/universal-id';
import {
base64ToUint8Array,
SocketConnection,
SPACE_JOIN_BATCH_LIMIT,
uint8ArrayToBase64,
} from './socket';
interface CloudAwarenessStorageOptions {
isSelfHosted: boolean;
serverBaseUrl: string;
type: SpaceType;
id: string;
}
export class CloudAwarenessStorage extends AwarenessStorageBase {
static readonly identifier = 'CloudAwarenessStorage';
constructor(private readonly options: CloudAwarenessStorageOptions) {
super();
}
connection = new SocketConnection(
this.options.serverBaseUrl,
this.options.isSelfHosted
);
private get socket() {
return this.connection.inner.socket;
}
private readonly activeAwarenessIds = new Set<string>();
private readonly joinedAwarenessIds = new Set<string>();
private joinPromise: Promise<void> | undefined;
private joinActiveAwareness(): Promise<void> {
if (
this.connection.status !== 'connected' ||
this.activeAwarenessIds.size === 0
) {
return Promise.resolve();
}
if (this.joinPromise) {
return this.joinPromise;
}
const batchPromise = (async () => {
while (this.connection.status === 'connected') {
await Promise.resolve();
const pendingIds = [...this.activeAwarenessIds].filter(
docId => !this.joinedAwarenessIds.has(docId)
);
if (pendingIds.length === 0) {
return;
}
for (
let index = 0;
index < pendingIds.length;
index += SPACE_JOIN_BATCH_LIMIT
) {
const spaces = pendingIds
.slice(index, index + SPACE_JOIN_BATCH_LIMIT)
.map(docId => ({
spaceType: this.options.type,
spaceId: this.options.id,
docId,
}));
const response = await this.socket.emitWithAck('space:join-batch', {
spaces,
clientVersion: BUILD_CONFIG.appVersion,
});
if ('error' in response) {
throw new Error(
`Awareness join failed: ${response.error.name}: ${response.error.message}`
);
}
if (!response.data.success) {
throw new Error('Awareness join was rejected');
}
}
for (const docId of pendingIds) {
if (this.activeAwarenessIds.has(docId)) {
this.joinedAwarenessIds.add(docId);
}
}
}
})();
const sharedPromise = batchPromise.finally(() => {
this.joinPromise = undefined;
});
this.joinPromise = sharedPromise;
return sharedPromise;
}
override async update(record: AwarenessRecord): Promise<void> {
const encodedUpdate = await uint8ArrayToBase64(record.bin);
this.socket.emit('space:update-awareness', {
spaceType: this.options.type,
spaceId: this.options.id,
docId: record.docId,
awarenessUpdate: encodedUpdate,
});
}
override subscribeUpdate(
id: string,
onUpdate: (update: AwarenessRecord, origin?: string) => void,
onCollect: () => Promise<AwarenessRecord | null>
): () => void {
this.activeAwarenessIds.add(id);
// leave awareness
const leave = () => {
this.activeAwarenessIds.delete(id);
this.joinedAwarenessIds.delete(id);
this.socket.off('space:collect-awareness', handleCollectAwareness);
this.socket.off(
'space:broadcast-awareness-update',
handleBroadcastAwarenessUpdate
);
if (this.connection.status !== 'connected') return;
this.socket.emit('space:leave-batch', {
spaceType: this.options.type,
spaceId: this.options.id,
docIds: [id],
});
};
// join awareness, and collect awareness from others
const joinAndCollect = async () => {
this.socket.on('space:collect-awareness', handleCollectAwareness);
this.socket.on(
'space:broadcast-awareness-update',
handleBroadcastAwarenessUpdate
);
await this.joinActiveAwareness();
if (this.connection.status !== 'connected') return;
this.socket.emit('space:load-awarenesses', {
spaceType: this.options.type,
spaceId: this.options.id,
docId: id,
});
};
const handleCollectAwareness = ({
spaceId,
spaceType,
docId,
}: {
spaceId: string;
spaceType: string;
docId: string;
}) => {
if (
spaceId === this.options.id &&
spaceType === this.options.type &&
docId === id
) {
(async () => {
const record = await onCollect();
if (record) {
const encodedUpdate = await uint8ArrayToBase64(record.bin);
this.socket.emit('space:update-awareness', {
spaceType: this.options.type,
spaceId: this.options.id,
docId: record.docId,
awarenessUpdate: encodedUpdate,
});
}
})().catch(err => console.error('awareness upload failed', err));
}
};
const handleBroadcastAwarenessUpdate = ({
spaceType,
spaceId,
docId,
awarenessUpdate,
}: {
spaceType: string;
spaceId: string;
docId: string;
awarenessUpdate: string;
}) => {
if (
spaceId === this.options.id &&
spaceType === this.options.type &&
docId === id
) {
onUpdate({
bin: base64ToUint8Array(awarenessUpdate),
docId: id,
});
}
};
if (this.connection.status === 'connected') {
joinAndCollect().catch(err =>
console.error('awareness join failed', err)
);
}
const unsubscribeConnectionStatusChanged = this.connection.onStatusChanged(
status => {
if (status !== 'connected') {
this.joinedAwarenessIds.clear();
}
if (status === 'connected') {
joinAndCollect().catch(err =>
console.error('awareness join failed', err)
);
}
}
);
return () => {
leave();
unsubscribeConnectionStatusChanged();
};
}
}