superdoc-sdk 0.1.0-next.beta.31

Typed Rust client for the SuperDoc document runtime
Documentation

SuperDoc Rust SDK

An asynchronous, generated Rust client for SuperDoc's native document runtime. The crate uses Tokio and requires Rust 1.85 or newer. The development toolchain is pinned separately in rust-toolchain.toml.

This is an initial prerelease. Release qualification includes the packaged crate, its pinned native bundles and both host modes on Linux x64 and arm64. Source compilation alone does not qualify a release.

use superdoc_sdk::{Client, HostOptions, Result, generated::types::*};

# async fn example() -> Result<()> {
let client = Client::connect(HostOptions::new("/installed/runtime/superdoc")).await?;
let doc = client.open(&DocOpenParams::new().with_doc("input.docx".into())).await?;
doc.api().insert(&DocInsertBoundParams::new().with_value("Hello from Rust".into())).await?;
doc.api().save(&DocSaveBoundParams::new().with_out("output.docx".into())).await?;
doc.close(&DocCloseBoundParams::new()).await?;
client.shutdown().await?;
# Ok(())
# }

Provisioning the native runtime is explicit. Building the crate and invoking a document operation never download an executable. Normal native use requires neither Node nor Python. HostOptions spawns the specified executable directly; prefix_args supports explicit development wrappers without a shell. The CLI host is the default. Set HostMode::Document for the standalone document host; unsupported collaboration or CLI-only fields fail before transmission.

The generated DocApi follows the contract's namespaces using Rust snake case: doc.api().comments().create(...). Document methods bind their session ID. Client::describe() and Client::describe_command() inspect the embedded contract without starting a host. Core tool schemas, prompts and dispatch use get_tools, get_system_prompt and Document::dispatch_tool; custom JavaScript callback registration is outside the Rust API.

Required request fields are constructor arguments; optional fields have with_* builders. Presence::Missing omits a field, while Presence::Present(Nullable::Null) sends explicit JSON null. Optional non-null fields reject null. Integers are checked against the JavaScript host's exact integer range; numbers must be finite. Overlapping unions preserve their original JSON and expose checked variant accessors. Closed objects reject unknown fields; open maps preserve additions. The host validates schema constraints such as ranges, patterns and exclusive alternatives.

All handle clones share close state. Close and shutdown are explicit async operations; dropping a document never saves it. A failed close with a known host error preserves the handle. Cancelling a request before writer admission sends no frame. After transmission starts, cancellation stops waiting while the transport drains the reply. A cancelled open retires the host to avoid leaving an unreachable session. Cancellation or timeout can leave a sent mutation's outcome unknown: inspect Error::outcome_unknown and reconcile saved content before retrying. The SDK never replays mutations automatically. Unsupported explicit deadlines on native save and replacement fail before admission.

Error retains the operation ID, host error code, RPC code, original host message and structured details. Default Debug/Display omit host text, document content, stdin and authentication. Access original diagnostic fields deliberately. Notification lag is reported explicitly; clients must resynchronize cached state. Owned temporary state is removed after confirmed process exit. Unconfirmed exit retains state for diagnosis. Caller-owned state directories are never removed.

CollaborationAuth::token is scoped to one open_with_options call. Credentials are carried in the RPC sidecar, never command-line arguments or persisted client configuration. replace_bytes keeps its staged file alive until the native request finishes or the process exits, including when the caller cancels.

From the public SDK workspace, run check:rust, test:rust-generation and test:conformance. The independent installed-consumer and native release checks are required in addition to source tests. The code generator owns generated modules; edit the exported contract or emitter, then regenerate.

Runtime setup

A released crate embeds the exact runtime version, contract hash, platform mapping, archive digest and complete file inventory. Setup is explicit and blocking; run it before document work (or use spawn_blocking in an async app):

use superdoc_sdk::{installation::{RuntimeManifest, host_target}, HostMode, Result};
use std::path::Path;
# fn example() -> Result<()> {
let manifest = RuntimeManifest::pinned()?;
let cache = Path::new("/application/cache/superdoc");
let installed = manifest.install(cache, host_target()?)?;
let host = installed.host_options(HostMode::Cli)?;
# Ok(())
# }

For offline setup, use manifest.install_archive(cache, target, archive_path). For subsequent starts, use manifest.resolve(cache, target) and installed.host_options(mode). Resolution verifies installed bytes and executable permissions. A corrupt existing installation fails closed; provision a new cache or remove that exact, inactive version after inspecting it. Setup serializes concurrent installers and publishes a complete installation by atomic rename. Interrupted temporary staging directories are never treated as installed versions. An externally supplied executable can use HostOptions::new(path); its host protocol and capabilities are checked when connecting.

The deployment mappings are aarch64-apple-darwin, x86_64-apple-darwin, aarch64-unknown-linux-gnu, x86_64-unknown-linux-gnu, and x86_64-pc-windows-msvc. Native CI executes on Linux x64 and arm64 only. Both Linux jobs verify and provision every pinned bundle, including Mach-O/PE target identity and retained Mac signature data. Those checks do not execute a Mac or Windows runtime. Linux bundles require glibc; musl, WASM and Windows ARM are unsupported. Tested Linux environments use Ubuntu 24.04. Older OS/CPU baseline compatibility has not been established by these checks.

The checked-in manifest is an intentionally unprepared template. Source builds can configure a host explicitly; release preparation replaces the template in an isolated package copy. Publishing a source checkout directly with cargo publish does not produce a qualified release.

Validation and release

From the SDK package, run pnpm check:rust, pnpm test:rust-generation and pnpm test:conformance after pnpm prepare:ci. From Orbit root, run pnpm proof run --suite superdoc/rust-sdk. The Proof adapter collects actual Cargo test cases, checks generated bytes against the retained preparation, and executes every reviewed case once. Installed qualification extracts the exact .crate outside Orbit, resolves fresh consumer dependencies, builds with Rust 1.85 and the pinned current compiler, and removes Node/Python from its runtime PATH. Use:

pnpm test:rust-installed CANDIDATE_DIRECTORY INPUT.docx linux-x64

The Orbit SDK preview CI also qualifies a controlled authenticated collaboration room with independent Rust clients, edits in both directions, invalid auth, rejoin, DOCX export and reopen. The 100-cycle native run checks host-process count, state-file growth, save/close, dropped read futures, and a 256 MiB host-RSS growth ceiling after ten warmup cycles. This is a bounded regression check, not a production capacity claim.

The SuperDoc SDK team owns SDK changes and prerelease feedback. The Orbit release owner owns candidate custody, native bundles and publication. Rust has its own 0.x prerelease sequence: pnpm version:set-rust 0.1.0-alpha.2 changes only the Cargo package and its lock entry. A Node/Python 2.x release prepares Rust artifacts but never publishes a Rust version automatically.

The release adapter requires a clean committed source and a canonical native SDK inventory. It hashes the exact source/assets, Cargo's normalized archive, the generation receipt, and all five deterministic runtime archives. Evaluation candidates remain localOnly and publication rejects them. Keep the complete candidate directory and the Linux qualification JSON receipts together.

From Orbit, pnpm rust:publish:next --version 0.1.0-next.beta.1 coordinates canonical GHA qualification and local publication using your exported CARGO_REGISTRY_TOKEN or CARGO_TOKEN. First publication also requires --claim-new-crate; if immutable runtime releases are disabled, the explicit one-time --enable-runtime-immutability flag is required. Run from a clean checkout of the current main commit. The command retains artifacts so the same invocation can resume verification after an interruption.

The lower-level release-owner operation is scripts/publish-rust-sdk.mjs MODE CANDIDATE QUALIFICATION_DIRECTORY [--owner LOGIN]:

  1. --preflight checks all local artifacts, both exact-candidate Linux receipts, controlled collaboration evidence, registry ownership and version availability. First publication additionally requires --claim-new-crate; name availability and organization ownership must be confirmed by the release owner.
  2. --stage-runtime uploads missing bundles to a GitHub release draft. Existing assets must have identical digests; it never overwrites them. For a new draft, pass --release-target PUBLIC_COMMIT_SHA, an existing commit in the public release repository. The private Orbit source SHA remains separate provenance. Publish the complete draft with GitHub release immutability enabled.
  3. --publish-crate requires that immutable release, reads back every remote bundle, uploads the tested .crate bytes through Cargo's registry API, then reads back the registry checksum and downloaded crate. It writes a publication receipt only after they match.

Credentials come from CARGO_REGISTRY_TOKEN (or CARGO_TOKEN) and authenticated gh; do not put them in argv or receipts. A timeout after upload is an ambiguous result. Preserve the candidate and resume verification of that immutable version; do not rebuild or blindly retry. A conflicting published checksum stops publication. Stop promotion for a broken release, publish a corrected crate/runtime pair and use cargo yank only through the release owner's normal withdrawal process. Do not replace a bundle or edit generated modules to repair a published version. Pinning the previous crate also pins its previous runtime.

Manual Orbit SDK preview qualification defaults to the canonical build profile. Its optional stress input expands the seeded framing corpus from 2,000 to 100,000 cases and the native lifecycle run from 100 to 1,000 cycles. Ordinary PR callers retain the explicitly marked evaluation profile; publication requires qualification of the canonical candidate. For a stacked PR with a non-main base, dispatch this workflow on the exact branch because automatic native preview routing is limited to main/v2 bases. Keep that exact-head workflow URL with the qualification receipts.