101 lines
6.8 KiB
TypeScript
101 lines
6.8 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, ConnectionState, 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 }),
|
|
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;
|
|
}
|
|
|
|
export function simulateConnection(_state: ConnectionState): void {}
|