UNPKG

insite-ws-transfers

Version:

File transfers over WebSockets for inSite

259 lines (190 loc) 9.18 kB
# insite-ws-transfers File transfers over WebSockets for the inSite stack. Streams data in chunks with progress tracking, abort support, and receiver confirmation. Part of [inSite](../../README.md) — built on [insite-ws](../ws/README.md). Requires `WSServer` or `WS` from that package. ## Installation ```sh npm install insite-ws-transfers ``` Or: ```sh bun add insite-ws-transfers ``` ## Overview **Entry points:** | Entry | Environment | Description | |-------|-------------|-------------| | `insite-ws-transfers` | Node.js | Default; same as `/node` | | `insite-ws-transfers/node` | Node.js | Incoming/outgoing with streams and file paths | | `insite-ws-transfers/browser` | Browser | Incoming/outgoing with `File` API | **Protocol flow:** Sender sends a transfer request → Receiver confirms (or rejects via `begin` returning `false`) → Chunks stream over the wire → Progress updates every 250 ms → Completion, abort, or error. **Transfer types:** `object` (JSON), `string`, `datauri`, `file`, `stream` (Node only). ## Usage ### Node server (receiving) ```ts import { WSServer } from "insite-ws/server"; import { IncomingTransport } from "insite-ws-transfers"; const wss = new WSServer({ port: 8080 }); new IncomingTransport(wss, { sizeLimit: 50 * 1024 * 1024 }); wss.onTransfer("file", { begin(wssc, transfer) { // Return false to reject }, end(wssc, transfer) { // transfer.data is ready (Buffer, string, or parsed object) } }); ``` ### Node server (sending) ```ts import { OutgoingTransport } from "insite-ws-transfers"; new OutgoingTransport(wss); const transfer = wss.transfer(wssc, "file", { data: "/path/to/file.pdf" }); ``` ### Browser client ```ts import { WS } from "insite-ws/client"; import { IncomingTransport, OutgoingTransport } from "insite-ws-transfers/browser"; const ws = new WS({ url: "wss://example.com" }); new IncomingTransport(ws); new OutgoingTransport(ws); ws.onTransfer("file", { end(transfer) { console.log(transfer.data); } }); ws.transfer("file", { data: fileInput.files[0] }); ``` ## Transfer types by environment | Type | Node (out) | Node (in) | Browser (out) | Browser (in) | |------|------------|-----------|---------------|---------------| | object ||||| | string ||||| | datauri ||||| | file | File path | Stream / Buffer | `File` | Base64 string | | stream | `Readable` | Stream / Buffer ||| ## API Reference ### IncomingTransport Handles incoming transfers. Attaches `onTransfer` and `onceTransfer` to the WS instance. **Constructor:** `new IncomingTransport(ws, options?)` | Option | Type | Default | Description | |--------|------|---------|-------------| | `sizeLimit` | `number` | 10 GB | Max transfer size in bytes | **Methods:** | Method | Description | |--------|-------------| | `addTransferListener(kind, listener, options?)` | Register handler for transfer kind | | `on(kind, listener, options?)` | Alias for `addTransferListener` | | `once(kind, listener, options?)` | One-time listener | | `removeTransferListener(kind, listener?)` | Unregister; omit `listener` to remove all for kind | | `off(kind, listener?)` | Alias for `removeTransferListener` | **Properties:** `sizeLimit` — max transfer size. ### IncomingTransfer Represents an incoming transfer. Instance of `IncomingTransfer` (browser) or `NodeIncomingTransfer` (Node). **Properties:** | Property | Type | Description | |----------|------|-------------| | `ws` | `WS \| WSServerClient` | WebSocket connection | | `id` | `string` | Transfer ID | | `kind` | `string` | Transfer kind (e.g. `"file"`) | | `type` | `TransferTypes` | Data type | | `collect` | `boolean` | Whether data is buffered | | `encoding` | `"base64" \| "buffer" \| "utf8"` | Chunk encoding | | `size` | `number` | Total size in bytes (0 if unknown) | | `metadata` | `Record<string, unknown>` | Sender metadata | | `confirmResponse` | `string \| undefined` | Set in `begin` to send custom response to sender | | `data` | `Buffer \| string \| undefined` | Collected result (when `collect` and transfer done) | | `progress` | `number` | 01 receiver progress | | `transferedSize` | `number` | Bytes received so far | | `processedSize` | `number` | Bytes processed so far | | `bytesPerMs` | `number \| null` | Throughput | | `duration` | `number \| null` | Transfer duration (ms) | | `isAborted` | `boolean` | Whether aborted | | `isAbortedBySender` | `boolean` | Aborted by sender | | `isAbortedByReceiver` | `boolean` | Aborted by receiver | | `isTransfered` | `boolean` | All chunks received | | `error` | `Error \| null` | Error if failed | **Methods:** | Method | Description | |--------|-------------| | `whenSetUp()` | `Promise<void>` — Resolves when setup and confirm sent | | `abort(bySender?)` | Abort transfer; `bySender: true` when sender aborted | | `serialize()` | Returns plain object with transfer state | **Node only:** `pipeTo(writableStream)` — Pipe incoming stream/file data to a `Writable` stream. Available when `type` is `stream` or `file`. ### OutgoingTransport Handles outgoing transfers. Attaches `transfer` to the WS instance. **Constructor:** `new OutgoingTransport(ws)` **Methods:** | Method | Description | |--------|-------------| | `transfer(ws, kind, props)` | Start transfer. On server, `ws` is `WSServerClient`; on client, use `ws.transfer(kind, props)` | ### OutgoingTransfer Represents an outgoing transfer. **Properties:** | Property | Type | Description | |----------|------|-------------| | `ws` | `WS \| WSServerClient` | WebSocket connection | | `id` | `string` | Transfer ID | | `kind` | `string` | Transfer kind | | `type` | `string` | Detected data type | | `collect` | `boolean` | Whether receiver buffers | | `metadata` | `Record<string, unknown>` | Custom metadata | | `size` | `number \| null` | Total size (null if unknown) | | `senderProgress` | `number` | 01 sender progress | | `progress` | `number` | 01 receiver progress | | `transferedSize` | `number` | Bytes sent | | `bytesPerMs` | `number \| null` | Throughput | | `duration` | `number \| null` | Transfer duration (ms) | | `isAborted` | `boolean` | Whether aborted | | `isTransfered` | `boolean` | Transfer completed | | `error` | `Error \| null` | Error if failed | **Methods:** | Method | Description | |--------|-------------| | `whenSetUp()` | `Promise<void>` — Resolves when request sent | | `abort()` | Abort transfer | | `serialize()` | Returns plain object with transfer state | ### Types **IncomingTransportOptions** | Property | Type | Description | |----------|------|-------------| | `sizeLimit?` | `number` | Max transfer size in bytes | **IncomingTransferListener** | Property | Signature | Description | |----------|-----------|-------------| | `begin?` | `(wssc, transfer) => unknown \| false` | Before confirm; return `false` to reject | | `chunk?` | `(wssc, transfer, chunk) => unknown` | Each chunk received | | `progress?` | `(wssc, transfer, chunk) => unknown` | Same as chunk | | `end?` | `(wssc, transfer) => unknown` | Transfer complete | | `error?` | `(wssc, transfer, error) => unknown` | On error or abort | | `once?` | `boolean` | Remove listener after first trigger | On client (`WS`), `wssc` is omitted; listeners receive `(transfer)` or `(transfer, chunk)`. **IncomingTransferListenerOptions** | Property | Type | Description | |----------|------|-------------| | `once?` | `boolean` | One-time listener | **OutgoingTransferProps** | Property | Type | Description | |----------|------|-------------| | `data` | `Buffer \| File \| Readable \| object \| string` | Data to send | | `type?` | `TransferTypes` | Force type; auto-detected if omitted | | `incomingType?` | `TransferTypes` | Type for receiver | | `collect?` | `boolean` | Whether receiver buffers (default: `false`) | | `metadata?` | `Record<string, unknown>` | Custom metadata | | `size?` | `number` | Total size (for progress) | | `chunkSize?` | `number` | Chunk size (default: 256 KB) | | `encoding?` | `"base64" \| "buffer" \| "utf8"` | Chunk encoding | | `incomingEncoding?` | `"base64" \| "buffer" \| "utf8"` | Encoding for receiver | | `onBegin?` | `(transfer) => unknown` | After receiver confirmed | | `onSenderProgress?` | `(transfer) => unknown` | After each chunk sent | | `onProgress?` | `(transfer) => unknown` | Receiver progress update | | `onEnd?` | `(transfer) => unknown` | Transfer complete | | `onError?` | `(transfer, error) => unknown` | On error or abort | On server, callbacks receive `(wssc, transfer)` or `(wssc, transfer, error)`. **Type helpers** | Type | Description | |------|-------------| | `WithTransfer<W, WSSC>` | `W` with `transfer(wssc, kind, props)` | | `WithOptionalTransfer<W, WSSC>` | Partial `transfer` | | `WithOnTransfer<W, WSSC>` | `W` with `onTransfer` and `onceTransfer` | | `WithOptionalOnTransfer<W, WSSC>` | Partial `onTransfer` / `onceTransfer` | ## Related - [insite-ws](../ws/README.md) — provides WSServer and WS - [insite-server](../server/README.md), [insite-client](../client/README.md), [insite-users-server](../users-server/README.md) — use transfers ## License MIT