@shardflux/sdk 0.8.0 → 0.10.0
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 +258 -0
- package/README.md +338 -7
- package/dist/account.d.ts +493 -0
- package/dist/account.js +641 -0
- package/dist/cell.d.ts +203 -8
- package/dist/cell.js +457 -32
- package/dist/client.d.ts +120 -5
- package/dist/client.js +142 -6
- package/dist/errors.d.ts +90 -3
- package/dist/errors.js +93 -1
- package/dist/executions.d.ts +120 -0
- package/dist/executions.js +99 -0
- package/dist/feedback.d.ts +67 -0
- package/dist/feedback.js +39 -0
- package/dist/generated/app-api.d.ts +10546 -5855
- package/dist/generated/cell-api.d.ts +501 -9
- package/dist/http.d.ts +7 -1
- package/dist/http.js +26 -7
- package/dist/index.d.ts +18 -7
- package/dist/index.js +5 -1
- package/dist/lifecycle.d.ts +27 -2
- package/dist/lifecycle.js +5 -0
- package/dist/progress.js +4 -2
- package/dist/templates.js +2 -2
- package/dist/tools.d.ts +28 -1
- package/dist/tools.js +172 -21
- package/dist/usage.d.ts +36 -6
- package/dist/usage.js +19 -4
- package/dist/version-check.d.ts +101 -0
- package/dist/version-check.js +191 -0
- package/dist/workspace.d.ts +100 -6
- package/dist/workspace.js +198 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,264 @@
|
|
|
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.10.0 (not yet published; npm `latest` is 0.9.0)
|
|
7
|
+
|
|
8
|
+
### A command that could not start rejects exec.run() (ExecStartError)
|
|
9
|
+
|
|
10
|
+
A minor release for one runtime change. Production (2026-09-29): `shard ws exec <key> --cwd app -- ls` exited 1 and
|
|
11
|
+
printed nothing, because the session ended `failed_to_start` and `exec.run()` dropped its reason.
|
|
12
|
+
|
|
13
|
+
- **Breaking:** `cell.exec.run()` rejects with the new `ExecStartError` when the command could not start (a `cwd` that
|
|
14
|
+
is not a directory, a program not on `PATH`, an unknown user). It was resolving with `exitCode: null`, empty output
|
|
15
|
+
and the reason only in `session.error`. `ExecStartError` extends `ShardfluxApiError` as a 409 `conflict` with
|
|
16
|
+
`reason` `exec_failed_to_start` (as a file-first execution that could not start reports it), `details.session_id`,
|
|
17
|
+
`details.error`, `sessionId` and `session`; its message is `The command could not start: <the workspace's reason>`,
|
|
18
|
+
e.g. `working directory "/home/user/app" is not a directory`. Also when a start answered `starting` ends that way.
|
|
19
|
+
- The `exec` agent tool (processful) returns `error: { code, message, reason }` with `exit_code: null` for such a
|
|
20
|
+
command, as the file-first `exec` tool does for a failed execution, instead of an empty result. Tool definitions
|
|
21
|
+
are unchanged.
|
|
22
|
+
- The cell API now refuses a relative `cwd` on exec, execution and PTY starts with 422 `validation_failed`,
|
|
23
|
+
`details.reason` `invalid_cwd`, `details.field` `cwd` (for every SDK version); the message names the absolute path
|
|
24
|
+
it likely means, e.g. `use "/home/user/app"`. `KnownErrorReason` adds `invalid_cwd`; `RunOptions.cwd` and the cell
|
|
25
|
+
types (regenerated) document it.
|
|
26
|
+
|
|
27
|
+
### Opt-in overage with a spend cap
|
|
28
|
+
|
|
29
|
+
Additive: an API without overage sends no `spend_cap` and no `reason`. The usage reads change types only (regenerated
|
|
30
|
+
from the API's OpenAPI); the account client's `setSpendPolicy()` gains the overage fields.
|
|
31
|
+
|
|
32
|
+
- Opt-in overage: `usage.summary()`, `spend()` and `estimate()` report `spend_cap` (new type `SpendCap`: `state`
|
|
33
|
+
`unavailable` | `off` | `paused` | `within_allowance` | `accruing` | `warning` | `reached`, `cap_minor`,
|
|
34
|
+
`effective_cap_minor`, `max_cap_minor`, `charges_minor`, `remaining_minor`, `percent_of_cap`, `currency`,
|
|
35
|
+
`resets_at`, `lines` per allowance with `units_over`, `billed_units`, `rate_minor`, `amount_minor`, and
|
|
36
|
+
`projected_reached_at`). Allowances past `included` while overage is on have `cap_state: 'overage'`; `summary()`
|
|
37
|
+
and `spend()` add `exhausted_reason`, and `spend.usage_charges_minor` and the estimate's charges are real amounts.
|
|
38
|
+
- `usage.spendPolicy()` and `ShardfluxAccount.billing.spendPolicy()` return the overage settings:
|
|
39
|
+
`overage_available`, `overage_enabled`, `overage_state` (`unavailable` | `off` | `on` | `paused`),
|
|
40
|
+
`spend_cap_minor`, `spend_cap_min_minor`, `spend_cap_max_minor`, `rates`, `currency` and `version`.
|
|
41
|
+
- `ShardfluxAccount.billing.setSpendPolicy(orgId, update)` (owners and billing members, with a user session; an API
|
|
42
|
+
key gets 403) takes `overageEnabled` and `spendCapMinor` besides `alertThresholdsPercent`, all optional (at least
|
|
43
|
+
one; an empty update throws before any request), and `ifMatch` (the `version` read, or `'*'`), sent as If-Match. New
|
|
44
|
+
type `SpendPolicyUpdate`. Runtime change: the body carries only the fields given.
|
|
45
|
+
- 402 `allowance_exhausted` carries `details.reason` (`allowance_used`, `overage_paused`, `spend_cap_reached`; also
|
|
46
|
+
`err.reason`) and `details.spend_cap` (`cap_minor`, `effective_cap_minor`, `charges_minor`, `currency`).
|
|
47
|
+
`KnownErrorReason` adds them, the spend-policy refusals (422 `overage_unavailable`, `spend_cap_required`,
|
|
48
|
+
`spend_cap_below_minimum`, `spend_cap_above_plan_price`, `spend_cap_below_charges`) and 409 `version_mismatch`.
|
|
49
|
+
|
|
50
|
+
### Suspend when idle (contracts §20.6)
|
|
51
|
+
|
|
52
|
+
- `workspace.suspendWhenIdle({ afterSeconds, idempotencyKey? })` and `cloud.workspaces.suspendWhenIdle(id, {
|
|
53
|
+
afterSeconds })` (POST /v1/workspaces/{id}/suspend-when-idle): the workspace is suspended once it has been idle for
|
|
54
|
+
`afterSeconds` (30..3600), counted from the later of its last work and the request. Meant for the end of an agent
|
|
55
|
+
turn. A running command, an attached stream or a keepalive postpones it; the next tool call or a resume cancels it.
|
|
56
|
+
Resolves with `{ suspendRequest, operation, workspace }`: `operation` is the suspend already in progress, if any
|
|
57
|
+
(then nothing is recorded).
|
|
58
|
+
- `workspace.cancelSuspendWhenIdle()` and `cloud.workspaces.cancelSuspendWhenIdle(id)` (DELETE, idempotent).
|
|
59
|
+
- `workspace.suspendRequest`: the pending request from the view's `idle.suspend_request`, or null.
|
|
60
|
+
- Tool-call capture writes recorded before `suspendWhenIdle` land first, as for `suspend`, since a later write would
|
|
61
|
+
count as the next turn and cancel the request.
|
|
62
|
+
- Types `SuspendRequest`, `SuspendWhenIdleOptions`, `SuspendWhenIdleResult`, `SuspendWhenIdleResponse`.
|
|
63
|
+
|
|
64
|
+
## 0.9.0 (not yet published; npm `latest` is 0.8.0)
|
|
65
|
+
|
|
66
|
+
Elastic compute (decision 0007): file tools and wake hints for parked workspaces. Additive; older APIs and cell
|
|
67
|
+
gateways keep working (the new calls answer 404 there).
|
|
68
|
+
|
|
69
|
+
### File search, patches with revisions, the wake hint
|
|
70
|
+
|
|
71
|
+
Needs a cell gateway with the contracts §26 routes (`files/search`, `files/patch`, `wake-hint`, revisions); an older
|
|
72
|
+
gateway does not serve them and returns no revisions.
|
|
73
|
+
|
|
74
|
+
- `cell.files.search(path, pattern, opts)`: content search under a directory (literal or RE2 with `regex`,
|
|
75
|
+
`caseInsensitive`, `include`/`exclude` globs, `maxMatches`, `maxFileBytes`, `contextLines`). Returns the gateway's
|
|
76
|
+
`FileSearchResult` (`matches` with `path`, 1-based `line` and byte `column`, `text`, optional `before`/`after`;
|
|
77
|
+
`truncated` and `stop_reason`; `files_scanned`) plus `served_from` (`disk` when a suspended workspace was searched on its disk
|
|
78
|
+
without waking it). It is read-only, so the HTTP layer retries it like a GET (new `RequestOptions.idempotent`).
|
|
79
|
+
- `cell.files.patch({ path, edits | content, expectedRevision, createParents, mode }, { idempotencyKey })`: text
|
|
80
|
+
edits (`{ oldText, newText, replaceAll }`, each must match exactly once unless `replaceAll`, applied in order,
|
|
81
|
+
all or nothing) or a whole new `content`, atomic and durable. Every call sends an `Idempotency-Key` (like `write`),
|
|
82
|
+
so a retried call is applied once. `expectedRevision` (or `absent`) makes a concurrent change a 409.
|
|
83
|
+
- Revisions: a file's revision is the SHA-256 of its content. `cell.files.stat(path, { revision: true })` returns it
|
|
84
|
+
(`FileInfo.revision`), writes and patches return it, and the new `cell.files.readWithInfo(path, opts)` returns
|
|
85
|
+
`{ data, size, revision, servedFrom }` from the read's `X-File-Size`, `X-File-Revision` and `X-Served-From` headers.
|
|
86
|
+
`read()` and `readText()` keep returning bytes and text: a separate method keeps every existing caller and return
|
|
87
|
+
type unchanged, where an options flag would have made `read()`'s return type depend on an argument. A read
|
|
88
|
+
continued over several requests reports a revision only when every part carried the same one.
|
|
89
|
+
- `workspace.hint(opts)` sends `POST /wake-hint`: a hibernated workspace is restored ahead of the tool call that
|
|
90
|
+
follows. It returns `{ residency, wake }`; for a workspace that is not running (409 `workspace_not_running`, also
|
|
91
|
+
when its tool token cannot be issued) it starts `wake()` in the background and returns at once (`wake` is that
|
|
92
|
+
promise, shared by concurrent hints; `wake: null` in the options only reports it). It is never retried and never
|
|
93
|
+
waits out `workspace_busy`. `cell.wakeHint()` is the bare request.
|
|
94
|
+
- Agent tools: `search_files` and `edit_file` (permission `files`), after `list_files`. `edit_file` patches with
|
|
95
|
+
`edits`; when the model gives no `expected_revision` it reads the file's revision first
|
|
96
|
+
(`stat?revision=true`) and pins the patch to it, so a change made in between is refused (`revision_mismatch`)
|
|
97
|
+
instead of edited blindly. `search_files` returns whole matches up to `maxOutputBytes` and counts the rest in
|
|
98
|
+
`omitted_matches`. The existing tools are unchanged. The tool runner sends `workspace.hint()` when a tool call
|
|
99
|
+
starts, without waiting for it; `workspaceTools(ws, { hint: false })` turns that off.
|
|
100
|
+
- Errors: `KnownErrorReason` adds `revision_mismatch` (409, `details.current_revision`), `edit_not_found`,
|
|
101
|
+
`edit_ambiguous` (422, `details.index`), `edit_not_text`, `patch_invalid`, `host_capacity` and `wake_failed` (503,
|
|
102
|
+
retryable, `Retry-After`: retried by the HTTP layer for GETs, searches and requests with an Idempotency-Key, like
|
|
103
|
+
any retryable 503), `workspace_fenced` (409 `workspace_busy`, waited out like any `workspace_busy`), and for reads
|
|
104
|
+
of a sleeping workspace `offline_unavailable` and `offline_budget` (409 `workspace_not_running`: woken and retried
|
|
105
|
+
like any) and `offline_changed` (503, retried; served by the running workspace).
|
|
106
|
+
- Reads of a suspended workspace without a held token: the API now issues tool tokens for a suspended workspace
|
|
107
|
+
(contracts §26.4), so `read`, `readText`, `readWithInfo`, `stat`, `list` and `search` of a suspended workspace are
|
|
108
|
+
served from its disk without waking it also for a handle that fetches its first token after the suspend (before,
|
|
109
|
+
the token was refused and the call woke the workspace). Any other call still wakes it: the cell refuses it with 409
|
|
110
|
+
`workspace_not_running`. Needs that API; with an older one the token is refused and the call wakes it as before.
|
|
111
|
+
- The agent-tool runner sends no wake hint for `read_file`, `list_files` and `search_files`: a sleeping workspace
|
|
112
|
+
serves them from its disk, and the hint would wake a suspended one (or restore a hibernated one) for nothing.
|
|
113
|
+
- Hosts without the features (contracts §26.7): `KnownErrorReason` adds `host_feature_unavailable` (409 `conflict`,
|
|
114
|
+
not retryable, `details.feature` `file_search` or `file_patch`): the workspace runs on a host agent that predates
|
|
115
|
+
the call, until it runs on an upgraded host. It is neither retried nor answered with a wake. Such a host also
|
|
116
|
+
returns no revisions (`FileInfo.revision`, `readWithInfo().revision` are absent).
|
|
117
|
+
- `JsonSchema.pattern`, checked by `validateArgs()`.
|
|
118
|
+
- Types: `FileSearchOptions`, `FileSearchResponse`, `FileSearchRequest`, `FileSearchResult`, `FileSearchMatch`,
|
|
119
|
+
`FilePatchParams`, `FilePatchEdit`, `FilePatchRequest`, `FilePatchResult`, `FileEdit`, `FileRevision`,
|
|
120
|
+
`FileReadResult`, `ServedFrom`, `Residency`, `WakeHintResult`, `HintOptions`, `HintResult`.
|
|
121
|
+
|
|
122
|
+
### File-first workspaces (contracts §29)
|
|
123
|
+
|
|
124
|
+
Needs an API with `FILE_FIRST_WORKSPACES` on and a cell that serves file-first workspaces (contracts §29.8). A
|
|
125
|
+
file-first workspace has no VM between executions: its state is a versioned file tree under /home/user, and each
|
|
126
|
+
command runs in a fresh VM whose changed files become the next tree revision. Processful workspaces are unchanged.
|
|
127
|
+
|
|
128
|
+
- `workspaces.open({ mode: 'file_first' })` (`mode: 'processful' | 'file_first'`; omitted: the API's default). A
|
|
129
|
+
file-first open is ready at once (200 with a tool token, no operation). `workspace.mode` and `workspace.treeRevision`
|
|
130
|
+
(null for processful): the handle follows every `X-Tree-Revision` its cell clients see, execution results and
|
|
131
|
+
`refresh()`, and never moves backwards.
|
|
132
|
+
- `workspace.executions.run(argv, opts)` / `cell.executions.run()`: runs one command as an execution and resolves when
|
|
133
|
+
it ended with an `ExecutionResult`: `stdout` / `stderr` bytes plus `text(stream)`, `stdoutText`, `stderrText`;
|
|
134
|
+
`exitCode`, `termSignal`, `timedOut`, `state` (`succeeded`, `failed`, `lost`), `baseRevision`, `treeRevision`,
|
|
135
|
+
`changed` (`{ path, change: added | modified | deleted, type }`), `changedTruncated`, the truncation flags,
|
|
136
|
+
`timings`, `error` / `errorReason`, `replayed`, `ok`, `raw`. Options: `executionId`, `cwd`, `env`, `user`, `stdin`,
|
|
137
|
+
`timeoutMs`, `killGraceMs`, `secretRefs`, `outputLimitBytes`, `maxRetries`, `attemptTimeoutMs`, `signal`.
|
|
138
|
+
- Idempotent by execution id: `executionId` defaults to a fresh `ex-<uuid>` (`newExecutionId()`, checked against
|
|
139
|
+
`EXECUTION_ID` before any request). Network failures and retryable 429/5xx answers (503 `no_execution_host`, with
|
|
140
|
+
`Retry-After`, honoured up to 30 s) are retried with the same id and body at most `maxRetries` (5) times; a wait
|
|
141
|
+
longer than `attemptTimeoutMs` (300 s) re-attaches with the same id without counting as a failure. The cell answers
|
|
142
|
+
201 for the call that ran the command and 200 (`replayed`) with the recorded result for any other, so the command
|
|
143
|
+
runs at most once. `workspace_busy` `execution_in_progress` is waited out like any `workspace_busy`;
|
|
144
|
+
`execution_id_reused` is thrown at once. A `failed` or `lost` result is returned, never retried with a new id.
|
|
145
|
+
- `executions.get(id, { waitMs })`: the result (`GET /executions/{id}`), or a `pending` one (202, state `queued` /
|
|
146
|
+
`running`) while it runs; `waitMs` polls (250 ms doubling to 2 s) until it ended or the wait elapsed.
|
|
147
|
+
- `ifTreeRevision` on `files.write`, `remove`, `mkdir`, `move` and `patch` sends `If-Match`: the call applies only at
|
|
148
|
+
that tree revision, else `TreeRevisionMismatchError` (409 `conflict` `tree_revision_mismatch`, with
|
|
149
|
+
`currentTreeRevision`) and nothing changed.
|
|
150
|
+
- Calls the mode lacks fail with `NotSupportedForModeError` (409 `conflict` `not_supported_for_mode`, `mode`,
|
|
151
|
+
`operation`, `local`): locally, without a request, when the handle knows the mode (file-first: exec sessions, PTY,
|
|
152
|
+
processes, git, browser, `changes()`, `suspend`, `resume`, `snapshot`, `fork`, `reset`, `saveAsTemplate`;
|
|
153
|
+
processful: `executions.*` and `ifTreeRevision`, which a processful cell would ignore), otherwise as the server's
|
|
154
|
+
refusal, typed the same way. On a file-first workspace `wake()` resolves `false` and `hint()` / `cell.wakeHint()`
|
|
155
|
+
answer `resident` without a request (nothing sleeps).
|
|
156
|
+
- Agent tools: `workspaceTools()` of a file-first workspace offers `exec` and the files tools only; its `exec` runs an
|
|
157
|
+
execution and returns `execution_id`, `state`, `tree_revision`, `changed` (up to 200, `changed_truncated`) and
|
|
158
|
+
`error` besides the output. New options: `mode` (build definitions without touching the workspace) and
|
|
159
|
+
`onExecution(id)` (called with the execution id before it is sent, so a caller that gives up can fetch the result).
|
|
160
|
+
**Breaking:** `workspaceTools()` now reads `workspace.mode` while building the definitions unless `mode` is given; a
|
|
161
|
+
caller that builds definitions from a stand-in workspace (as the MCP server does) passes `mode`.
|
|
162
|
+
- Errors: every error is built by reason, so `NotSupportedForModeError` and `TreeRevisionMismatchError` (both
|
|
163
|
+
`ShardfluxApiError`) come from any call; `ShardfluxApiError.treeRevision` is the refusal's `X-Tree-Revision`. Their
|
|
164
|
+
`name` is the subclass's (code that compared `err.name` with `'ShardfluxApiError'` should use `instanceof`).
|
|
165
|
+
`KnownErrorReason` adds `not_supported_for_mode`, `mode_mismatch`, `mode_not_available`, `layout_unsupported`,
|
|
166
|
+
`tree_revision_mismatch`, `outside_tree_root`, `execution_in_progress`, `execution_id_reused`,
|
|
167
|
+
`operation_id_reused`, `no_execution_host`, and the execution error reasons `lease_expired`, `host_unreachable`,
|
|
168
|
+
`host_restarted`, `tree_moved`, `blob_missing`, `blob_corrupt`, `exec_failed_to_start`. Retry progress causes name the
|
|
169
|
+
reason (`HTTP 503 service_unavailable no_execution_host`).
|
|
170
|
+
- Types: `WorkspaceMode`, `ExecutionResult`, `ExecutionResultBody`, `ExecutionChange`, `ExecutionState`,
|
|
171
|
+
`ExecutionError`, `ExecutionRunOptions`, `ExecutionGetOptions`, `TreeRevisionOptions`.
|
|
172
|
+
|
|
173
|
+
### Waking a suspended workspace is one request (contracts §22.6)
|
|
174
|
+
|
|
175
|
+
Needs an API with the held resume for the single request; against an older API every call below works as in 0.7.0.
|
|
176
|
+
|
|
177
|
+
- The wake of a tool call refused with `workspace_not_running` (and `hint()`'s background wake, and `wake()`) sends
|
|
178
|
+
one `POST /v1/workspaces/{id}/resume` with `Prefer: wait` and the calling client's agent label and tools. The API
|
|
179
|
+
answers once the workspace runs, with the view and a tool token minted during the restore: the handle keeps both
|
|
180
|
+
and the refused call is retried at once. On staging the automatic wake made five requests before the command
|
|
181
|
+
(refused call, resume, wait, view, token: 1,118 ms median, against 838 ms for a held reopen); it is now two.
|
|
182
|
+
- Without `Preference-Applied`, or on a 202 (not finished within the hold), the wake waits for the operation and reads
|
|
183
|
+
the view as before; the retried call then fetches its token.
|
|
184
|
+
- `resume({ wait })` (handle and `workspaces.resume(id)`) is the same single held request; a handle takes the view and
|
|
185
|
+
the token. `serverWait: false` keeps the polled path. A workspace that is already running still throws `conflict`
|
|
186
|
+
`already_running` (the held answer is 200 without an operation; the SDK reports it as before).
|
|
187
|
+
- Timing: a held resume or wake is one `request` phase with reason `held`; `server` comes from the returned operation.
|
|
188
|
+
- New options: `WakeOptions.agentLabel` / `tools` and `ResumeOptions` (`agentLabel`, `tools`; `WaitedResumeOptions`)
|
|
189
|
+
choose the token that comes back; `cell()`'s own wake passes its label and tools. `WorkspacesApi.requestResume()`
|
|
190
|
+
is the bare request (`ResumeAnswer`, `ResumeRequestOptions`, `ResumeResponse`).
|
|
191
|
+
- `CellClient`: after a wake that put a new token into the client's manager, the retry uses it instead of fetching one.
|
|
192
|
+
### The account plane and the version check (contracts §30)
|
|
193
|
+
|
|
194
|
+
Needs an API with CLI sessions and client versions (contracts §30). Every API is additive; the one change in
|
|
195
|
+
behavior is the automatic version check (below), which makes one background request per process.
|
|
196
|
+
|
|
197
|
+
### Account plane: `ShardfluxAccount`
|
|
198
|
+
|
|
199
|
+
- `ShardfluxAccount`: what a person does in the web app, from code, with a CLI session (`sfu_<token>`, sent as
|
|
200
|
+
`Authorization: Bearer` on `/v1`). Options: `sessionToken?`, `baseUrl?`, `fetch?`, `userAgent?`, `timeoutMs?`,
|
|
201
|
+
`maxRetries?`, `sleep?`, `onSessionToken?`, `versionCheck?`, `onProgress?`. A malformed token throws (shape
|
|
202
|
+
`^sfu_[A-Za-z0-9_-]{43}$`, also `isSessionToken()` and `SESSION_TOKEN_PATTERN`).
|
|
203
|
+
- Before a session exists (static, no token): `register({ email, password, displayName? })`,
|
|
204
|
+
`verifyEmail(linkOrToken)`, `requestPasswordReset(email)`, `confirmPasswordReset({ token, newPassword })`,
|
|
205
|
+
`confirmEmailChange(linkOrToken)` and `login({ email, password, onSessionToken? })` → `{ account, result }`
|
|
206
|
+
(`result.status` `authenticated` or `mfa_required`). Each takes the client options.
|
|
207
|
+
- Token rotation: login, `auth.completeMfa()`, `auth.stepUp()`, `auth.changePassword()`, `auth.totp.confirm()` and
|
|
208
|
+
`auth.totp.disable()` return a new token (the previous one is revoked). `account.sessionToken` always holds the
|
|
209
|
+
current one, every later call (the reused namespaces included) sends it, and `onSessionToken({ token, expiresAt })`
|
|
210
|
+
is called (and awaited) with each.
|
|
211
|
+
- Namespaces: `auth` (`session`, `completeMfa`, `logout`, `logoutAll`, `sessions`, `revokeSession`, `stepUp`,
|
|
212
|
+
`changePassword`, `changeEmail`, `resendVerification`, `totp.enroll|confirm|disable|regenerateRecoveryCodes`),
|
|
213
|
+
`organizations` (`list`, `listAll`, `create`, `get`, `entitlements`, `deletion`, `delete`, `exports.create|get|download`,
|
|
214
|
+
`workspaces`), `projects` (`list`, `listAll`, `create`, `get`), `apiKeys` (`list`, `create`, `revoke`), `members`
|
|
215
|
+
(`list`, `update`, `remove`), `invitations` (`list`, `create`, `revoke`, `accept`), `billing` (`catalog`,
|
|
216
|
+
`subscription`, `checkout`, `checkoutStatus`, `waitForCheckout`, `portal`, `invoices`, `spendPolicy`,
|
|
217
|
+
`setSpendPolicy`), `user` (`deletion`, `scheduleDeletion`, `cancelDeletion`, `exports.create|get|download`),
|
|
218
|
+
`templates` (every `TemplatesApi` method plus `publishVersion` and `archiveVersion`), `audit` (`list`, `listAll`,
|
|
219
|
+
`export` → the CSV or NDJSON text), `usage`, `secrets`, `egress`, `volumes`, `workspaces`, `me()` and `request()`.
|
|
220
|
+
List methods return the API's page `{ data, next_cursor }`.
|
|
221
|
+
- `apiKeys.create(projectId, { name, toolPermissions?, expiresAt?, idempotencyKey? })` sends an Idempotency-Key (a
|
|
222
|
+
fresh one unless given), so a retried request returns the same key and secret instead of creating a second key.
|
|
223
|
+
`toolPermissions` defaults to `[]`; `API_KEY_TOOL_PERMISSIONS` lists every tool.
|
|
224
|
+
- `billing.waitForCheckout(orgId, checkoutId, { timeoutMs?, intervalMs?, signal? })` polls until the subscription is
|
|
225
|
+
active or the checkout expired, was canceled or failed, and returns that status; after `timeoutMs` (default 15 min)
|
|
226
|
+
it throws `CheckoutTimeoutError` (`checkout`, `waitedMs`), on abort the signal's reason.
|
|
227
|
+
- `parseEmailToken(input)`: the `token` of an emailed link's `#token=` fragment or `?token=` query (percent-decoded),
|
|
228
|
+
else the trimmed input; throws for an empty input or a link without a token. Every method that takes an emailed
|
|
229
|
+
token accepts the whole link.
|
|
230
|
+
- Errors are `ShardfluxApiError` as elsewhere; the session adds the codes `step_up_required` (call `auth.stepUp()` and
|
|
231
|
+
retry), `mfa_required` and `email_unverified` (403).
|
|
232
|
+
|
|
233
|
+
### Version check
|
|
234
|
+
|
|
235
|
+
- `checkClientVersion({ baseUrl?, fetch?, package?, version?, ecosystem?, timeoutMs?, signal? })` →
|
|
236
|
+
`ClientVersionStatus` `{ status, package, ecosystem, current, latest, minimumSupported, upgradeCommand,
|
|
237
|
+
releaseNotesUrl, message? }` from `GET /v1/client-versions`. `status`: `unsupported` (below `minimum_supported`),
|
|
238
|
+
`outdated` (below `latest`), `current`, or `unknown` (no entry, `latest` null, a version that does not parse, or the
|
|
239
|
+
request failed; it never throws). `compareVersions(a, b)` → -1, 0, 1, or null for a string that is not
|
|
240
|
+
`major.minor.patch` (a pre-release sorts before its release).
|
|
241
|
+
- Automatic: after the first successful API response of a `Shardflux` or `ShardfluxAccount` client, once per process
|
|
242
|
+
per package identity, a background request (3 s timeout, every error swallowed; it never delays a call) emits
|
|
243
|
+
`process.emitWarning(message, { type: 'ShardfluxUpdateWarning', code: 'SHARDFLUX_UPDATE_AVAILABLE' })` when the
|
|
244
|
+
package is outdated or unsupported. Option `versionCheck?: boolean | { package, version, ecosystem? }` on both
|
|
245
|
+
clients (default `@shardflux/sdk` at `SDK_VERSION`; tools built on the SDK pass their own identity or `false`).
|
|
246
|
+
Off with `SHARDFLUX_NO_UPDATE_CHECK=1` (also `true`, `yes`, `on`) or `NO_UPDATE_NOTIFIER=1`. `fetchBillingCatalog()`
|
|
247
|
+
does not check.
|
|
248
|
+
|
|
249
|
+
### Feedback straight to the founder (POST /v1/feedback)
|
|
250
|
+
|
|
251
|
+
- `cloud.sendFeedback({ message, category?, context? })` sends feedback to the Shardflux founder by email and returns
|
|
252
|
+
`{ id, receivedAt, duplicate }`. `category`: `bug`, `confusing`, `missing`, `idea`, `praise` or `other` (default).
|
|
253
|
+
`context`: `agent`, `client`, `workspace`, `requestId`, `errorCode`, `command`, `page` (sent in snake_case);
|
|
254
|
+
`client` defaults to `shardflux-sdk-ts/<SDK_VERSION>`.
|
|
255
|
+
- `duplicate: true`: the same message from the same key within 24 hours; the original is returned and no second email
|
|
256
|
+
is sent. 429 `rate_limited` (with `retryAfterSeconds`) and 422 `validation_failed` are `ShardfluxApiError`s. The call
|
|
257
|
+
is a POST without an idempotency key, so it is never retried.
|
|
258
|
+
- `ShardfluxAccount.sendFeedback({ ..., organizationId? })`: the same with a CLI session, as the signed-in user,
|
|
259
|
+
optionally about one of their organizations (404 `not_found` for another).
|
|
260
|
+
- New exports: `FeedbackCategory`, `FeedbackContext`, `FeedbackReceipt`, `SendFeedbackParams`, `AccountFeedbackParams`,
|
|
261
|
+
`FEEDBACK_CATEGORIES`, `FEEDBACK_MESSAGE_MAX_LENGTH`.
|
|
262
|
+
|
|
263
|
+
|
|
6
264
|
## 0.8.0 (2026-09-28)
|
|
7
265
|
|
|
8
266
|
Types only; nothing changes at run time and the API is unchanged.
|