@shardflux/sdk 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,7 +3,17 @@
3
3
  Every API the README shows is available from the version named here. Below 1.0, a minor release may break
4
4
  compatibility; breaking changes are marked **Breaking**.
5
5
 
6
- ## 0.6.0 (not yet published; npm `latest` is 0.5.0)
6
+ ## 0.6.1 (not yet published; npm `latest` is 0.6.0)
7
+
8
+ - `formatTiming()` joined two phases that followed each other with `∥` (ran together) when their 0.1 ms times summed
9
+ with a floating-point error (1000.2 + 300.1 > 1300.3); it now prints `→`.
10
+ - `open()`: the wait's `signal` also aborts the held request (up to 20 s); before, it only ended the polls after it,
11
+ and an abort during the held request was retried as a network failure.
12
+ - `waitForOperation()` on its own records its first poll as a `request` phase; before, a held first poll's time
13
+ belonged to no phase (a 1 s wait could show `queued 0 ms`).
14
+ - README: the timing example is the formatter's real output (durations under a second print in ms).
15
+
16
+ ## 0.6.0 (2026-09-28)
7
17
 
8
18
  ### Lifecycle calls: requested or finished
9
19
 
package/README.md CHANGED
@@ -9,7 +9,7 @@ tools (exec, files, processes, PTY, git, browser) that plug into any model provi
9
9
  > **Early access.** Shardflux is in early access. The API is versioned (`/v1`), but this SDK is
10
10
  > below 1.0: a minor release may contain breaking changes (see [Compatibility](#compatibility)).
11
11
 
12
- > **Versions.** This README describes 0.6.0. Anything marked **(0.6.0+)** is not in 0.5.0;
12
+ > **Versions.** This README describes 0.6.1. Anything marked **(0.6.0+)** is not in 0.5.0;
13
13
  > [CHANGELOG.md](./CHANGELOG.md) lists what each version added. Check yours with
14
14
  > `npm ls @shardflux/sdk` or the exported `SDK_VERSION`.
15
15
 
@@ -184,9 +184,9 @@ A slow open (34 s instead of the usual second) then reads, for example:
184
184
 
185
185
  ```text
186
186
  open 34.18 s, succeeded (workspace 01a0e5a8-3edd-74ba-b489-d62b8925e342, operation 01a0e5a8-3ef0-7ecb-975e-dff2d5ca6e33)
187
- client: request 20.01 s (held) → capacity_pending 13.52 s (no_ready_host) → running 0.59 s → view 42 ms ∥ token 61 ms
188
- server: queued 33.40 s, ran 0.62 s, total 34.02 s; start warm, boot to ready 79 ms
189
- outside the server: 0.16 s
187
+ client: request 20.01 s (held) → capacity_pending 13.52 s (no_ready_host) → running 590 ms → view 42 ms ∥ token 61 ms
188
+ server: queued 33.40 s, ran 620 ms, total 34.02 s; start warm, boot to ready 79 ms
189
+ outside the server: 161 ms
190
190
  ```
191
191
 
192
192
  Here the time went to waiting for a host with capacity; the network and the VM start were fast.
package/dist/client.js CHANGED
@@ -81,7 +81,8 @@ export class WorkspacesApi {
81
81
  const waitOpts = params.wait === false ? null : (params.wait ?? {});
82
82
  const trace = new Trace('open', combineListeners(this.#ctx().onProgress, params.onProgress, waitOpts?.onProgress));
83
83
  return traced(trace, async () => {
84
- const init = { json: body, idempotencyKey: params.idempotencyKey ?? randomId('open-'), onRetry: trace.onRetry };
84
+ // The wait's signal also ends the held request (it can take up to 20 s), not only the polls after it.
85
+ const init = { json: body, idempotencyKey: params.idempotencyKey ?? randomId('open-'), onRetry: trace.onRetry, ...(waitOpts?.signal ? { signal: waitOpts.signal } : {}) };
85
86
  const started = Date.now();
86
87
  const timeoutMs = waitOpts?.timeoutMs ?? 300_000;
87
88
  if (waitOpts && waitOpts.serverWait !== false) {
@@ -175,7 +176,11 @@ export class WorkspacesApi {
175
176
  const inherited = opts[TRACE];
176
177
  const trace = inherited ?? new Trace('wait', combineListeners(this.#ctx().onProgress, opts.onProgress), { operationId });
177
178
  const run = () => this.#poll(operationId, opts, trace);
178
- return inherited ? run() : traced(trace, run);
179
+ if (inherited)
180
+ return run();
181
+ // A wait on its own starts with its first poll: a held poll can take seconds before the first state is known.
182
+ trace.phase('request');
183
+ return traced(trace, run);
179
184
  }
180
185
  async #poll(operationId, opts, trace) {
181
186
  const { sleep, http, authorization } = this.#ctx();
package/dist/http.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { RetryRecord } from './progress.js';
2
- export declare const SDK_VERSION = "0.6.0";
2
+ export declare const SDK_VERSION = "0.6.1";
3
3
  export interface RequestOptions {
4
4
  query?: Record<string, string | number | boolean | undefined | null>;
5
5
  json?: unknown;
package/dist/http.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { ShardfluxApiError, ShardfluxProtocolError, isErrorBody } from "./errors.js";
8
8
  import { describeFailure } from "./progress.js";
9
- export const SDK_VERSION = '0.6.0';
9
+ export const SDK_VERSION = '0.6.1';
10
10
  export const defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
11
11
  /**
12
12
  * The fetch the SDK uses when none is given. On runtimes whose bundled undici is 8.x (Node 26) it sends
@@ -68,7 +68,7 @@ export interface ServerTiming {
68
68
  startPath: string | null;
69
69
  /** `result.warm_fallback`: why a start that could be warm booted instead. */
70
70
  warmFallback: string | null;
71
- /** `result.resume_path`: `local_cache` or `download` (the checkpoint had to be fetched first). */
71
+ /** `result.resume_path`: `local_cache`, `prestaged` (copied to this host ahead of the resume, contracts §23) or `download` (the checkpoint had to be fetched first). */
72
72
  resumePath: string | null;
73
73
  /** `result.boot_to_ready_ms`: VM start until the guest agent answered. */
74
74
  bootToReadyMs: number | null;
@@ -157,9 +157,9 @@ export declare function traced<T>(trace: Trace, fn: () => Promise<T>): Promise<T
157
157
  * A human-readable account of a timing, for logs and bug reports:
158
158
  *
159
159
  * open 34.18 s, succeeded (workspace <id>, operation <id>)
160
- * client: request 20.01 s (held) → capacity_pending 13.52 s (no_ready_host) → running 0.59 s → view 42 ms ∥ token 61 ms
161
- * server: queued 33.40 s, ran 0.62 s, total 34.02 s; start warm, boot to ready 79 ms
162
- * outside the server: 0.16 s
160
+ * client: request 20.01 s (held) → capacity_pending 13.52 s (no_ready_host) → running 590 ms → view 42 ms ∥ token 61 ms
161
+ * server: queued 33.40 s, ran 620 ms, total 34.02 s; start warm, boot to ready 79 ms
162
+ * outside the server: 161 ms
163
163
  * retries: 1 (POST /v1/workspaces/open, HTTP 503 unavailable, after 200 ms)
164
164
  */
165
165
  export declare function formatTiming(t: LifecycleTiming): string;
package/dist/progress.js CHANGED
@@ -202,9 +202,9 @@ const fmt = (ms) => (ms === null ? '?' : ms < 1000 ? `${Math.round(ms)} ms` : `$
202
202
  * A human-readable account of a timing, for logs and bug reports:
203
203
  *
204
204
  * open 34.18 s, succeeded (workspace <id>, operation <id>)
205
- * client: request 20.01 s (held) → capacity_pending 13.52 s (no_ready_host) → running 0.59 s → view 42 ms ∥ token 61 ms
206
- * server: queued 33.40 s, ran 0.62 s, total 34.02 s; start warm, boot to ready 79 ms
207
- * outside the server: 0.16 s
205
+ * client: request 20.01 s (held) → capacity_pending 13.52 s (no_ready_host) → running 590 ms → view 42 ms ∥ token 61 ms
206
+ * server: queued 33.40 s, ran 620 ms, total 34.02 s; start warm, boot to ready 79 ms
207
+ * outside the server: 161 ms
208
208
  * retries: 1 (POST /v1/workspaces/open, HTTP 503 unavailable, after 200 ms)
209
209
  */
210
210
  export function formatTiming(t) {
@@ -213,8 +213,10 @@ export function formatTiming(t) {
213
213
  let client = '';
214
214
  t.phases.forEach((p, i) => {
215
215
  const prev = t.phases[i - 1];
216
- // A phase that starts before the previous one ended ran alongside it (view and token at the end of open()).
217
- const sep = i === 0 ? '' : prev && p.startMs < prev.startMs + prev.durationMs ? ' ∥ ' : ' → ';
216
+ // A phase that starts before the previous one ended ran alongside it (view and token at the end of open()). Times
217
+ // are 0.1 ms values, so a phase that follows another can appear to start a float error early (1000.2 + 300.1 >
218
+ // 1300.3): overlap must exceed that.
219
+ const sep = i === 0 ? '' : prev && p.startMs < prev.startMs + prev.durationMs - 0.05 ? ' ∥ ' : ' → ';
218
220
  client += `${sep}${p.phase} ${fmt(p.durationMs)}${p.reason ? ` (${p.reason})` : ''}`;
219
221
  });
220
222
  if (client)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shardflux/sdk",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "description": "Shardflux TypeScript SDK: open persistent agent workspaces by key and give your agent workspace tools (exec, files, processes, PTY, git, browser).",
6
6
  "license": "Apache-2.0",