import { AutoReconnectConnection } from '../../connection'; import type { BlobRecord, DocClock, DocRecord, ListedBlobRecord, } from '../../storage'; import { type SpaceType, universalId } from '../../utils/universal-id'; export interface SqliteNativeDBOptions { readonly flavour: string; readonly type: SpaceType; readonly id: string; } export type NativeDBApis = { connect(id: string): Promise; disconnect(id: string): Promise; pushUpdate(id: string, docId: string, update: Uint8Array): Promise; getDocSnapshot(id: string, docId: string): Promise; setDocSnapshot(id: string, snapshot: DocRecord): Promise; getDocUpdates(id: string, docId: string): Promise; markUpdatesMerged( id: string, docId: string, updates: Date[] ): Promise; deleteDoc(id: string, docId: string): Promise; getDocClocks( id: string, after?: Date | undefined | null ): Promise; getDocClock(id: string, docId: string): Promise; getBlob(id: string, key: string): Promise; setBlob(id: string, blob: BlobRecord): Promise; deleteBlob(id: string, key: string, permanently: boolean): Promise; releaseBlobs(id: string): Promise; listBlobs(id: string): Promise; getPeerRemoteClocks(id: string, peer: string): Promise; getPeerRemoteClock( id: string, peer: string, docId: string ): Promise; setPeerRemoteClock( id: string, peer: string, docId: string, clock: Date ): Promise; getPeerPulledRemoteClocks(id: string, peer: string): Promise; getPeerPulledRemoteClock( id: string, peer: string, docId: string ): Promise; setPeerPulledRemoteClock( id: string, peer: string, docId: string, clock: Date ): Promise; getPeerPushedClocks(id: string, peer: string): Promise; getPeerPushedClock( id: string, peer: string, docId: string ): Promise; setPeerPushedClock( id: string, peer: string, docId: string, clock: Date ): Promise; clearClocks(id: string): Promise; }; type NativeDBApisWrapper = NativeDBApis extends infer APIs ? { [K in keyof APIs]: APIs[K] extends (...args: any[]) => any ? Parameters extends [string, ...infer Rest] ? (...args: Rest) => ReturnType : never : never; } : never; let apis: NativeDBApis | null = null; export function bindNativeDBApis(a: NativeDBApis) { apis = a; } export class NativeDBConnection extends AutoReconnectConnection { readonly apis: NativeDBApisWrapper; readonly flavour = this.options.flavour; readonly type = this.options.type; readonly id = this.options.id; constructor(private readonly options: SqliteNativeDBOptions) { super(); if (!apis) { throw new Error('Not in native context.'); } this.apis = this.warpApis(apis); } override get shareId(): string { return `sqlite:${this.flavour}:${this.type}:${this.id}`; } warpApis(originalApis: NativeDBApis): NativeDBApisWrapper { const id = universalId({ peer: this.flavour, type: this.type, id: this.id, }); return new Proxy( {}, { get: (_target, key: keyof NativeDBApisWrapper) => { const v = originalApis[key]; return async (...args: any[]) => { return v.call( originalApis, id, // @ts-expect-error I don't know why it complains ts(2556) ...args ); }; }, } ) as unknown as NativeDBApisWrapper; } override async doConnect() { await this.apis.connect(); } override doDisconnect() { this.apis.disconnect().catch(err => { console.error('NativeDBConnection close failed', err); }); } }