Something went wrong. Try again.
A local-first note taking app
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394/** * Subtext cache operations (renderer-side). * * Bridges the renderer's Yjs documents with the Subtext local CRDT store via * the IPC-exposed TCP client. * * All functions below accept a `vaultPath` directly; there is no URI→vaultPath * mapping layer at this time. */
import * as Y from 'yjs';
const IPC_TIMEOUT_MS = 5000;
async function ipcCall<T>(method: string, ...args: unknown[]): Promise<T> { if (!window.textile?.subtext) { throw new Error('subtext IPC not available'); } const fn = window.textile.subtext[method as keyof typeof window.textile.subtext]; if (typeof fn !== 'function') { throw new Error(`unknown subtext IPC method: ${method}`); } return Promise.race([ (fn as (...args: unknown[]) => Promise<T>)(...args), new Promise<T>((_, reject) => setTimeout(() => reject(new Error('subtext IPC timeout')), IPC_TIMEOUT_MS), ), ]);}
/** Try to seed an existing Y.Doc from Subtext's local cache. Returns true if seeded. */export async function seedYdocFromSubtext(vaultPath: string, ydoc: Y.Doc): Promise<boolean> { try { const bytes = (await ipcCall<Uint8Array | null>('getFullState', vaultPath)) as Uint8Array | null; if (bytes && bytes.length > 0) { Y.applyUpdateV2(ydoc, bytes); return true; } } catch (e) { console.warn('[subtext] seed failed for', vaultPath, e); } return false;}
/** Push the full Yjs state of a document to Subtext (overwrite local cache). */export async function pushYdocToSubtext(vaultPath: string, ydoc: Y.Doc): Promise<void> { const bytes = Y.encodeStateAsUpdateV2(ydoc); try { await ipcCall('applyUpdate', vaultPath, bytes); } catch (e) { console.warn('[subtext] push failed for', vaultPath, e); throw e; }}
/** Push a single update diff to Subtext (lightweight, used on every local edit). */export async function pushUpdateToSubtext(vaultPath: string, update: Uint8Array): Promise<void> { try { await ipcCall('applyUpdate', vaultPath, update); } catch (e) { console.warn('[subtext] push update failed for', vaultPath, e); }}
/** Create a new vault file in Subtext with the given initial Yjs state. */export async function createFileInSubtext( vaultPath: string, initialState: Uint8Array,): Promise<void> { await ipcCall('createFile', vaultPath, initialState);}
/** Rename a vault file in Subtext. */export async function renameFileInSubtext( oldVaultPath: string, newVaultPath: string,): Promise<void> { await ipcCall('renameFile', oldVaultPath, newVaultPath);}
/** Check whether Subtext has a local file at the given vault path. */export async function fileExists(vaultPath: string): Promise<boolean> { try { return await ipcCall<boolean>('fileExists', vaultPath); } catch { return false; }}
/** List all local vault paths from Subtext. */export async function listCachedVaults(): Promise<string[]> { return await ipcCall<string[]>('listFiles');}