SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
This commit is contained in:
commit
fa9c73363d
1367 files changed
+355735
No files matched your search
@@ -0,0 +1,130 @@
|
||||
# Streaming files
|
||||
|
||||
Both `SnowLumaHttpClient` and `SnowLumaWebSocketClient` support incremental uploads
|
||||
and downloads. Existing `request()`, `call()`, `raw()`, `rawResponse()` and
|
||||
`downloadFile()` keep their single-response behavior. Use the new methods below
|
||||
when a response contains multiple frames.
|
||||
|
||||
## Upload
|
||||
|
||||
```ts
|
||||
import { createReadStream } from 'node:fs';
|
||||
import { stat } from 'node:fs/promises';
|
||||
import { SnowLumaHttpClient } from '@snowluma/sdk';
|
||||
|
||||
const client = new SnowLumaHttpClient({ baseUrl: 'http://127.0.0.1:3000/' });
|
||||
const controller = new AbortController();
|
||||
const path = './photo.png';
|
||||
const file = await client.uploadFileStream(
|
||||
createReadStream(path, { signal: controller.signal }),
|
||||
{
|
||||
fileSize: (await stat(path)).size,
|
||||
filename: 'photo.png',
|
||||
signal: controller.signal,
|
||||
onProgress: ({ uploadedBytes, fileSize }) => {
|
||||
console.log(`${uploadedBytes}/${fileSize}`);
|
||||
},
|
||||
},
|
||||
);
|
||||
console.log(file.file_path, file.file_size, file.sha256);
|
||||
```
|
||||
|
||||
`uploadFileStream(source, options?)` accepts `Uint8Array` (including Node.js
|
||||
`Buffer`), `Blob`, `ReadableStream<Uint8Array>` or `AsyncIterable<Uint8Array>`.
|
||||
Byte arrays and blobs provide their own size. Stream sources require `fileSize`:
|
||||
the server needs the total chunk count before accepting the first chunk. The SDK
|
||||
rejects input whose actual length differs from the declared size.
|
||||
|
||||
The default chunk size is 64 KiB. `chunkSize` accepts 1 through 1048576 bytes,
|
||||
keeping each encoded request below the standard server HTTP body limit. Input is
|
||||
read incrementally; chunks are acknowledged sequentially, and `onProgress` is
|
||||
awaited before continuing. Empty files are supported. Completion is a separate
|
||||
request and returns `UploadFileStreamComplete`, including the **server's** local
|
||||
file path; it does not write a local client file or send a QQ message.
|
||||
|
||||
Optional settings are `filename`, `expectedSha256`, `fileRetention` (milliseconds;
|
||||
zero disables server expiry), and `streamId`. The default server retention is five
|
||||
minutes. A generated ID identifies each upload; an explicit ID must be fresh, not
|
||||
an existing upload. The helper does not resume or automatically retry transfers.
|
||||
The server validates `expectedSha256` when provided; the SDK checks the completed
|
||||
metadata and returned digest against that expectation.
|
||||
|
||||
`signal` cancels requests and closes readable sources. For custom async iterables,
|
||||
pass the same signal to the source and ensure pending reads and iterator cleanup
|
||||
can finish on cancellation (as the `createReadStream` example does). Cancellation
|
||||
cannot force an arbitrary producer to resolve its own promises. A failed or
|
||||
cancelled upload is not finalized; partial server uploads expire after the
|
||||
server's idle timeout (currently ten minutes). The helper does not issue a reset
|
||||
request or delete a completed server file automatically.
|
||||
|
||||
## Download
|
||||
|
||||
```ts
|
||||
import { createWriteStream } from 'node:fs';
|
||||
import { pipeline } from 'node:stream/promises';
|
||||
|
||||
await pipeline(
|
||||
client.downloadFileStream(
|
||||
{ file: file.file_path, chunk_size: 64 * 1024 },
|
||||
{ onInfo: (info) => console.log(info.file_name, info.file_size) },
|
||||
),
|
||||
createWriteStream('./downloaded.png'),
|
||||
);
|
||||
```
|
||||
|
||||
`downloadFileStream(params, options?)` yields `Uint8Array` chunks and returns
|
||||
`DownloadFileStreamComplete` as the iterator's final value. `for await` and
|
||||
`pipeline()` consume chunks and verify completion, but discard that return value;
|
||||
call `iterator.next()` manually if you need `total_bytes` and `total_chunks` from
|
||||
the final result. `onInfo` runs before any file bytes are yielded.
|
||||
|
||||
Parameters accept a server-side `file` or `file_id`, plus optional `chunk_size`.
|
||||
The `action` option selects `download_file_stream` (default),
|
||||
`download_file_image_stream`, or `download_file_record_stream`.
|
||||
|
||||
The helper decodes base64 and checks chunk order, chunk lengths and final counts.
|
||||
A zero initial file size can mean unknown size; final byte and chunk totals still
|
||||
must match. Missing metadata, malformed frames, truncation and server failures
|
||||
throw; bytes already consumed are not rolled back. For durable output, write to
|
||||
a temporary file and rename it after the iteration succeeds.
|
||||
|
||||
## Individual frames
|
||||
|
||||
```ts
|
||||
for await (const frame of client.stream('test_download_stream', {})) {
|
||||
console.log(frame.type, frame.data_type);
|
||||
}
|
||||
|
||||
for await (const response of client.requestStream('test_download_stream', {})) {
|
||||
console.log(response.status, response.retcode, response.data);
|
||||
}
|
||||
```
|
||||
|
||||
- `requestStream()` yields response envelopes, including a final failed envelope.
|
||||
- `stream()` yields typed payloads and throws `SnowLumaApiError` (or its auth
|
||||
subtype) for failed envelopes, including errors after earlier chunks.
|
||||
- Both support the five streaming actions: the three downloads,
|
||||
`test_download_stream`, and `upload_file_stream`. Each upload request returns
|
||||
just one acknowledgement, including `type: 'stream'` chunk ACKs. Low-level
|
||||
callers must finalize in a separate request. Reset retains the server's
|
||||
existing failed-envelope behavior.
|
||||
- `AbortSignal`, `echo`, and `timeoutMs` work as on ordinary requests. Timeout
|
||||
covers an active streaming request (including WebSocket connection setup);
|
||||
uploads apply it to each chunk/finalization request. Zero disables timeout.
|
||||
Source reads and application callbacks are not timed by the request timeout.
|
||||
- Stopping iteration releases client resources. HTTP also cancels its response
|
||||
body. WebSocket stops collecting that request without closing the shared socket;
|
||||
the protocol has no per-request download cancellation message, so the server
|
||||
may continue sending remaining frames. Use unique echoes for transfers; do not
|
||||
reuse an aborted transfer's echo while late frames may still arrive.
|
||||
- WebSocket disconnection fails active transfers; reconnect does not replay them.
|
||||
- `maxBufferBytes` defaults to 32 MiB and bounds each HTTP frame or the queued
|
||||
WebSocket payloads. `maxBufferedFrames` defaults to 256 for WebSocket. An
|
||||
overflow throws instead of dropping frames or buffering the entire file.
|
||||
HTTP reads follow consumption; WebSocket has no per-request backpressure, so
|
||||
prefer HTTP for large downloads to a slow destination.
|
||||
|
||||
All new types are exported from `@snowluma/sdk` and `@snowluma/sdk/types`. Custom
|
||||
`SnowLumaApiClient` subclasses can opt in by implementing `requestStream()`;
|
||||
request-only subclasses remain compatible and receive an explicit unsupported
|
||||
error if streaming is attempted.
|
||||
Reference in new issue
Block a user