UNPKG

@pgxsinkit/pgwasm

Version:
163 lines • 8.56 kB
/** * `RepackedSyncClient` — the backend side of the synchronous broker. * * Every method blocks the calling thread in `Atomics.wait` until the coordinator answers, which is the * whole point: a thread running wasm parks in futexes and can never observe a promise, so the file * layer under it has to be synchronous. Nothing here is async, and nothing here knows about wasm. * * ## What throws and what does not * * A FILE rejection is data: every method returns `{ errno }` (0 on success) with whatever else the * operation produced. Callers map the errno straight into their own ABI — the values are WASI preview1 * errno numbers already. * * A TRANSPORT failure throws, because there is no answer to return: the server detached this client, * the client sent something the server refused, the server never replied inside the timeout, or the * store itself failed. Those are `RepackedBrokerTransportError` and `RepackedBrokerStoreError`. * * ## Mapping onto WASI preview1 * * The method set is shaped so a preview1 adapter is a straight translation, with no state of its own * beyond the preopen table: * * path_open → open(path, flags, mode) (flags are the POSIX bits, see protocol) * fd_close → close(fd) * fd_read → read(fd, length) (no position: the store's own cursor) * fd_pread → read(fd, length, position) * fd_write → write(fd, bytes) * fd_pwrite → write(fd, bytes, position) * fd_seek → resolved by the caller; the store's cursor moves on cursor reads/writes * fd_sync / fd_datasync → fsync(fd) (store-wide; see the server's note) * fd_filestat_get → fstat(fd) * path_filestat_get → stat(path) / lstat(path) * fd_readdir → readdir(path) or readdirPage(path, cursor) for the cookie form * path_create_directory → mkdir(path) * path_remove_directory → rmdir(path) * path_unlink_file → unlink(path) * path_rename → rename(oldPath, newPath) * path_symlink → symlink(target, path) (targets are ABSOLUTE; see the core) * path_readlink → readlink(path) * fd_filestat_set_size → truncate(path, size) — the core resizes by PATH only, so the adapter * keeps the path it opened each fd with and resolves it here * * Reads and writes larger than the channel's payload region are split transparently; a caller never * has to know the channel size. */ import type { BrokerStat, RepackedChannel } from "./protocol"; /** The transport failed: there is no answer, and this client can no longer make progress. */ export declare class RepackedBrokerTransportError extends Error { readonly brokerCode: "detached" | "protocol" | "timeout"; constructor(brokerCode: "detached" | "protocol" | "timeout", message: string); } /** The store behind the broker failed. Not a file rejection, and not this client's mistake. */ export declare class RepackedBrokerStoreError extends Error { readonly brokerCode = "store"; constructor(message: string); } /** Every result carries an errno; 0 means the operation succeeded. */ export interface BrokerResult { readonly errno: number; } export interface BrokerOpenResult extends BrokerResult { readonly fd: number; } export interface BrokerCountResult extends BrokerResult { /** Bytes actually transferred. Short of the request means end-of-file (read) or a store limit (write). */ readonly count: number; } export interface BrokerReadResult extends BrokerCountResult { readonly bytes: Uint8Array; } export interface BrokerStatResult extends BrokerResult { readonly stat: BrokerStat | undefined; } export interface BrokerSizeResult extends BrokerResult { readonly size: bigint; } export interface BrokerReaddirResult extends BrokerResult { readonly entries: readonly string[]; } export interface BrokerReadlinkResult extends BrokerResult { /** The link's target, or `undefined` when the call was rejected. */ readonly target: string | undefined; } export interface BrokerReaddirPageResult extends BrokerReaddirResult { /** The cursor to resume from, or `undefined` when the listing is complete. */ readonly nextCursor: number | undefined; } export interface RepackedSyncClientOptions { /** * How long one request may go unanswered before the client gives up and throws. A dead coordinator * would otherwise park this thread forever, which is worse than a loud failure. Pass `Infinity` for * a host that genuinely prefers to wait. */ readonly requestTimeoutMs?: number; } export declare class RepackedSyncClient { #private; readonly channel: RepackedChannel; constructor(channel: RepackedChannel, options?: RepackedSyncClientOptions); /** The largest single read or write that fits one request. Reads/writes above it are chunked. */ get maxTransferBytes(): number; open(path: string, flags: number, mode?: number): BrokerOpenResult; close(fd: number): BrokerResult; /** * Read up to `length` bytes. With no `position` the store's own descriptor cursor is used and * advances; with a `position` the cursor is untouched (`fd_pread`). A result shorter than `length` * means end-of-file, never a partial transport. */ read(fd: number, length: number, position?: bigint): BrokerReadResult; /** * Write `bytes`. With no `position` the store's own descriptor cursor is used and advances; with a * `position` the cursor is untouched (`fd_pwrite`). A descriptor opened with `O_APPEND` always * writes at end-of-file and ignores `position`, exactly as POSIX requires. */ write(fd: number, bytes: Uint8Array, position?: bigint): BrokerCountResult; /** * Flush the store. Durability is STORE-WIDE, not per-descriptor: on success every byte written * through this broker by any client before the call returned is recoverable. `fd` is validated so * the call still rejects a descriptor this client does not own. */ fsync(fd?: number): BrokerResult; fstat(fd: number): BrokerStatResult; stat(path: string): BrokerStatResult; /** Reports the LINK itself when the final component is one; `stat` follows it instead. */ lstat(path: string): BrokerStatResult; /** * Create a symbolic link at `path` pointing at `target`. Targets are ABSOLUTE — the store refuses * a relative one with `EINVAL` rather than reinterpreting it against the link's directory. */ symlink(target: string, path: string): BrokerResult; /** The target of the symbolic link at `path`. `EINVAL` when the path is not a link. */ readlink(path: string): BrokerReadlinkResult; /** The complete listing, paged transparently over as many requests as the channel needs. */ readdir(path: string): BrokerReaddirResult; /** * One page of a listing, for a caller that owns its own cookie (WASI `fd_readdir`). The cursor is an * index into the store's sorted listing, recomputed per call — a paged listing is therefore not an * atomic snapshot, which is exactly what POSIX `readdir` allows. */ readdirPage(path: string, cursor?: number): BrokerReaddirPageResult; mkdir(path: string, options?: { recursive?: boolean; mode?: number; }): BrokerResult; rmdir(path: string): BrokerResult; unlink(path: string): BrokerResult; rename(oldPath: string, newPath: string): BrokerResult; /** * Resize by PATH. The core store has no resize-by-descriptor, so a WASI `fd_filestat_set_size` * adapter keeps the path each fd was opened with and calls this. Nothing is lost by that: the store * has no hard links, and a descriptor whose path was unlinked meanwhile is an orphan the core keeps * readable but no longer resizes. */ truncate(path: string, size: bigint): BrokerResult; /** The size of one file, without the rest of a stat. `EISDIR` for a directory. */ size(path: string): BrokerSizeResult; } /** * Turn a broker result into the throw the core store would have produced, for a caller that prefers * exceptions to errnos. The rebuilt `FsError` carries the same numeric `code` the broker reported. */ export declare function throwOnErrno(result: BrokerResult, operation: string, path?: string): void; //# sourceMappingURL=client.d.ts.map