Skip to main content
The SDK batches remote calls for throughput, but batching is not a transaction. Use Storage upload sessions when bytes are too large for the JSON runtime batch or when a file must be assembled across calls. An upload session is a temporary durable control record, not a file. It stores the intended target, progress, lease, access, retention, metadata, schema, and compute policy. A readable storageEntryId exists only after the session reaches FINALIZED.

Automatic batching

Calls queued in the same microtask are grouped. Promise.all is the normal way to create a batch:
Sequential awaits naturally dispatch separate batches:
Configure batching before the first remote dispatch:
The SDK defaults to 32 calls, 256 KiB per request, four in-flight batches, and 1,024 queued calls. Client configuration can only lower platform ceilings. The current server envelope allows up to 64 calls, a 1 MiB request, and a 4 MiB response.
Runtime batches are never retried automatically because they can contain mutations. A transport interruption after dispatch produces an indeterminate result; inspect durable state before retrying.

Small objects

Use putObject() when text or base64 data comfortably fits the runtime batch:
Binary data must be base64-encoded when sent through this JSON path.

Large uploads with explicit parts

For data generated by the application, an incremental session gives each appended part the next number. Upload calls carry small text or base64 chunks through the SDK, while the durable entry appears only at finalization.
For chunked, pass an explicit positive partNumber; re-uploading that number repairs a part. For incremental, omit the number during normal appends but you may still provide one to repair a known part. getUploadSession() exposes the manifest, uploaded bytes, part count, and next number. An active session has a lease: call extendUploadSession() while a long-running producer is still making progress.
Finalization is the durable boundary. A part acknowledged by uploadPart() is not yet a readable Storage entry and must not trigger downstream processing.

Direct browser or Node upload

Choose uploadMode: 'direct' when bytes should travel through the managed upload URL rather than through SDK JSON calls:
The platform’s managed completion flow finalizes a successful direct upload. Do not call finalization merely because fetch() returned success, and do not infer durable completion from the byte-transfer response alone. Poll the session or react to the resulting Storage event. When an instance returns another upload strategy, follow that strategy and its public completion contract. Upload URLs and headers are temporary credentials. Do not log, persist, or pass them to another principal. If byte transfer fails before completion, abort the active session as a best-effort cleanup.

Read structured files in pages

CSV, TSV, XLSX, NDJSON/JSONL, JSON arrays, and record-oriented XML return structured pages. Follow the opaque cursor instead of assuming the result is an array of text lines. This example reads a CSV file. For XML, pass recordPath to getFileData() and to any explicit getFileStats() call.
getFileData() builds missing structured statistics when needed. If the persisted mapping must be recomputed, call getFileStats(storageEntryId, { reloadStats: true }) first; reloadStats is not a getFileData() option. For XLSX, select sheet when the first visible worksheet is not the intended source. XML requires recordPath. CSV indexing validates quote syntax and source field counts before returning records. STORAGE_CSV_INVALID includes bounded location diagnostics without raw rows or cell values. Its per-record maxRecordBytes guard defaults to 64 MiB independently of read size. Set the same dialect for indexing and reading; quote: false deliberately keeps literal quotes and backslashes and ignores escape. See CSV validation and physical counts. For CSV/TSV, readers default to onError: 'abort'. Set onError: 'skipRow' on statistics and every page read to skip records with the wrong source field count. The returned csvReport contains the exact skipped count and bounded original-file locations for the whole source; do not sum it across pages. Invalid syntax and oversized records still abort. See CSV record error policy for upload settings, walkers, and diagnostic fields. Plain text can still be read through line windows. Explicit mode: 'lines' also reads a CSV as strings without interpreting its fields, preserving headers, blanks and the terminal empty element. That mode is for custom text processing, rather than automatic recovery from malformed CSV. Storage record/line batches are unrelated to SDK request batching. For binary data, getFileData() returns base64. Direct reads are limited to 10 MiB; use buffer: true with an explicit byte start and end for a bounded range.

Large data exports

For a CSV, TSV, NDJSON, or XLSX export of a Table, View, or Materialized View, use revo.api.exportDatabase(name, options) so the platform streams the selected rows directly into Storage. Use the following page-and-upload flow only when the output requires custom Node.js processing or an unsupported format:
  1. request bounded pages rather than one unbounded result;
  2. use a stable unique sort key;
  3. advance pagination only when the previous page made progress;
  4. use a snapshot/version filter if the source can change during export;
  5. generate the file locally in Node.js, then upload it through a session.
For an HTTP source, use api.httpCall({ ... }, { responseType: 'storage', target: { ... } }) so the response is finalized directly into Storage. In Node.js, call this through revo.api or the hosted runtime.api. responseType: 'stream' means a byte/SSE iterator consumed inside low-code V8; the Node.js SDK does not transport those iterators and rejects this mode before dispatch. Use a Storage target or consume the stream inside a low-code execution and return a bounded result. For structured CSV or Excel generation, upload sessions accept rows and worksheet batches with one shared declared schema. See Structured files in Storage. Local Node.js generation remains useful when a report needs a format outside the supported structured-file contract. Callback-based transaction compatibility APIs are intentionally not part of the public SDK. If several remote operations require atomicity, implement that boundary in one RevoEngine component or library where the database transaction context exists. See Storage operations, Storage upload sessions, HTTP integrations, and the generated Storage method reference.
Last modified on October 10, 2026