Files
WebDrop/web/src/core-bridge/real.ts
T

100 lines
6.9 KiB
TypeScript

import type { ParsedChannelLink } from '@/lib/channelLink';
import type { AccountInvitation } from './account';
import type { ParsedShareLink } from '@/lib/shareLink';
import type { WorkspaceApi } from './api';
import type { ShareApi } from './shareApi';
import { callWorker, subscribeWorker } from './workerClient';
import type { ArchiveEntry, ChannelInfo, ChannelSettingsPatch, CreateOptions, Share, ShareEvent, ShareSettings, WorkspaceEvent } from './types';
const API_BASE = import.meta.env.VITE_WEBDROP_API_URL ?? '/api/v1';
function reportChannelUnavailable(id: string, onEvent: (event: WorkspaceEvent) => void): void {
onEvent({ t: 'connection', state: 'offline' });
onEvent({ t: 'ready' });
void id;
}
export const realApi: WorkspaceApi = {
createChannel: (options: CreateOptions, captchaToken?: string) => callWorker<ChannelInfo>('createChannel', { options, captchaToken, apiBase: API_BASE }),
updateChannelSettings: (patch: ChannelSettingsPatch) => callWorker<void>('updateChannelSettings', { id: currentChannelId(), patch, apiBase: API_BASE }),
renameDevice: (endpointHash, name) => callWorker<void>('renameDevice', { id: currentChannelId(), endpointHash, name, apiBase: API_BASE }),
releaseDevice: (endpointHash) => callWorker<void>('releaseDevice', { id: currentChannelId(), endpointHash, apiBase: API_BASE }),
joinChannel: (link: ParsedChannelLink, password?: string) => callWorker<ChannelInfo>('joinChannel', { link, password, apiBase: API_BASE }),
inviteUser: (username) => callWorker<void>('inviteChannelUser', { id: currentChannelId(), username, apiBase: API_BASE }),
listInvitations: () => callWorker<AccountInvitation[]>('listChannelInvitations', { id: currentChannelId(), apiBase: API_BASE }),
revokeInvitation: (username) => callWorker<void>('revokeChannelInvitation', { id: currentChannelId(), username, apiBase: API_BASE }),
listSaved: () => callWorker<ChannelInfo[]>('listChannels', { apiBase: API_BASE }),
forget: (id) => callWorker<void>('forgetChannel', { id, apiBase: API_BASE }),
connect(channelId, onEvent) {
activeChannelId = channelId;
activeShareId = '';
const unsubscribe = subscribeWorker<WorkspaceEvent>(channelId, onEvent);
void callWorker<boolean>('connectChannel', { id: channelId, apiBase: API_BASE }).catch(() => reportChannelUnavailable(channelId, onEvent));
return () => {
unsubscribe();
void callWorker('stopChannel', { id: channelId, apiBase: API_BASE });
};
},
sendText: (text, threadId) => callWorker<void>('sendText', { id: currentChannelId(), text, threadId, apiBase: API_BASE }),
sendFiles: (files, options, threadId, folderId) => callWorker<void>('sendFiles', { id: currentChannelId(), files, options, threadId, folderId, apiBase: API_BASE }),
createThread: (name, groupId) => callWorker<string>('createThread', { id: currentChannelId(), name, groupId, apiBase: API_BASE }),
createGroup: (name) => callWorker<string>('createGroup', { id: currentChannelId(), name, apiBase: API_BASE }),
renameGroup: (groupId, name) => callWorker<void>('renameGroup', { id: currentChannelId(), groupId, name, apiBase: API_BASE }),
groupThread: (threadId, groupId) => callWorker<void>('groupThread', { id: currentChannelId(), threadId, groupId, apiBase: API_BASE }),
renameThread: (threadId, name) => callWorker<void>('renameThread', { id: currentChannelId(), threadId, name, apiBase: API_BASE }),
setChannelHistory: (threadId, chatHistory, filesHistory) => callWorker<void>('setChannelHistory', { id: currentChannelId(), threadId, chatHistory, filesHistory, apiBase: API_BASE }),
createFolder: (threadId, name, parentId) => callWorker<void>('createFolder', { id: currentChannelId(), threadId, name, parentId, apiBase: API_BASE }),
renameFolder: (folderId, threadId, name) => callWorker<void>('renameFolder', { id: currentChannelId(), folderId, threadId, name, apiBase: API_BASE }),
moveItems: (itemIds, threadId, folderId) => callWorker<void>('moveItems', { id: currentChannelId(), itemIds, threadId, folderId, apiBase: API_BASE }),
editText: (id, text, threadId) => callWorker<void>('editChannelText', { id: currentChannelId(), itemId: id, text, threadId, apiBase: API_BASE }),
resolveConflict: (id, choice) => callWorker<void>('resolveTextConflict', { id: currentChannelId(), itemId: id, choice, apiBase: API_BASE }),
remove: (id) => callWorker<void>('removeChannelItem', { id: currentChannelId(), itemId: id, apiBase: API_BASE }),
setSnapshot: (text) => callWorker<void>('updateSnapshot', { id: currentChannelId(), text, apiBase: API_BASE }),
getBlob: (id, versionId) => callWorker<Blob>('getChannelBlob', { id: currentChannelId(), itemId: id, versionId, apiBase: API_BASE }),
listArchive: (_id: string): Promise<ArchiveEntry[]> => callWorker<ArchiveEntry[]>('listArchive', { id: currentChannelId(), apiBase: API_BASE }),
markSeen: (id) => callWorker<void>('markChannelSeen', { id: currentChannelId(), itemId: id, apiBase: API_BASE }),
};
export const realShareApi: ShareApi = {
createDraft: (settings: ShareSettings, captchaToken?: string) => callWorker<Share>('createShare', { settings, captchaToken, apiBase: API_BASE }),
listSaved: () => callWorker<Share[]>('listShares', { apiBase: API_BASE }),
updateSettings: (id, patch) => callWorker<Share>('updateShareSettings', { id, patch, apiBase: API_BASE }),
seal: (id) => callWorker<Share>('sealShare', { id, apiBase: API_BASE }),
join: (link: ParsedShareLink) => callWorker<Share>('joinShare', { link, apiBase: API_BASE }),
forget: (id) => callWorker<void>('forgetShare', { id, apiBase: API_BASE }),
connect(shareId, onEvent) {
activeShareId = shareId;
activeChannelId = '';
const unsubscribe = subscribeWorker<ShareEvent>(shareId, onEvent);
void callWorker<void>('connectShare', { id: shareId, apiBase: API_BASE }).catch((error: unknown) => {
onEvent({ t: 'error', message: error instanceof Error ? error.message : '无法打开分享' });
onEvent({ t: 'ready' });
});
return () => {
unsubscribe();
void callWorker('stopShare', { id: shareId, apiBase: API_BASE });
};
},
addText: (text) => callWorker<void>('addShareText', { id: currentShareId(), text, apiBase: API_BASE }),
editText: (id, text) => callWorker<void>('editShareText', { id: currentShareId(), itemId: id, text, apiBase: API_BASE }),
addFiles: (files) => callWorker<void>('addShareFiles', { id: currentShareId(), files, apiBase: API_BASE }),
removeItem: (id) => callWorker<void>('removeShareItem', { id: currentShareId(), itemId: id, apiBase: API_BASE }),
getBlob: (id) => callWorker<Blob>('getShareBlob', { id: currentShareId(), itemId: id, apiBase: API_BASE }),
listArchive: (_id: string): Promise<ArchiveEntry[]> => callWorker<ArchiveEntry[]>('listArchive', { id: currentShareId(), apiBase: API_BASE }),
};
let activeChannelId = '';
let activeShareId = '';
function currentChannelId(): string {
return activeChannelId;
}
function currentShareId(): string {
return activeShareId;
}