unfazed 0.0.1 → 0.1.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/LICENSE +21 -0
- package/README.md +300 -1
- package/dist/client.d.ts +134 -0
- package/dist/client.js +266 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +93 -0
- package/dist/errors.js +137 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/gql.d.ts +132 -0
- package/dist/generated/gql.js +41 -0
- package/dist/generated/gql.js.map +1 -0
- package/dist/generated/graphql.d.ts +774 -0
- package/dist/generated/graphql.js +607 -0
- package/dist/generated/graphql.js.map +1 -0
- package/dist/generated/index.d.ts +1 -0
- package/dist/generated/index.js +2 -0
- package/dist/generated/index.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/operations.d.ts +136 -0
- package/dist/operations.js +461 -0
- package/dist/operations.js.map +1 -0
- package/dist/unfazed.d.ts +445 -0
- package/dist/unfazed.js +510 -0
- package/dist/unfazed.js.map +1 -0
- package/dist/wait.d.ts +57 -0
- package/dist/wait.js +59 -0
- package/dist/wait.js.map +1 -0
- package/package.json +50 -6
- package/schema/SOURCE.json +9 -0
- package/schema/schema.graphqls +1303 -0
- package/index.js +0 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jilio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,302 @@
|
|
|
1
1
|
# unfazed
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Official TypeScript SDK for [unfazed](https://unfazed.dev) — deploy and operate
|
|
4
|
+
agent-built apps (static sites, HTTP services, persistent Linux boxes) in
|
|
5
|
+
isolated microVMs.
|
|
6
|
+
|
|
7
|
+
**This is the code-mode companion to the unfazed MCP server.** Same platform,
|
|
8
|
+
same bearer token, different shape. Use the MCP tools when you want the model to
|
|
9
|
+
decide one step at a time. Use this SDK when you'd rather write one script that
|
|
10
|
+
does the whole chain and only reports back what matters.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
MCP: create_workspace → write_file → write_file → write_file → deploy
|
|
14
|
+
→ list_deployments → list_deployments → list_deployments → get_logs
|
|
15
|
+
(9+ round trips, every result lands in the model's context)
|
|
16
|
+
|
|
17
|
+
SDK: one script. Three requests. You read the four lines you cared about.
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- Zero runtime dependencies. Installing `unfazed` installs exactly one package.
|
|
21
|
+
- Strict TypeScript, generated from the platform's own GraphQL schema.
|
|
22
|
+
- Bun-first, runs unchanged on Node >= 20 and Deno.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
bun add unfazed # or: npm i unfazed
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Auth
|
|
31
|
+
|
|
32
|
+
Get a token from <https://unfazed.dev/auth.md> (or `POST
|
|
33
|
+
https://unfazed.dev/agents/register`). The SDK reads `UNFZ_API_TOKEN`:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
export UNFZ_API_TOKEN="..."
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const unfazed = new Unfazed(); // reads UNFZ_API_TOKEN
|
|
41
|
+
const unfazed = new Unfazed({ token }); // or pass it explicitly
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Both endpoint and token are configurable. `UNFZ_API_URL` overrides the endpoint
|
|
45
|
+
(default `https://unfazed.dev/query`); `baseUrl` is a convenience for
|
|
46
|
+
self-hosted control planes where only the host differs.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
new Unfazed({ token, baseUrl: "https://staging.example.com" }); // → /query
|
|
50
|
+
new Unfazed({ token, endpoint: "https://example.com/graphql" }); // exact
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Code mode: deploy, wait, tail logs, in one script
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
#!/usr/bin/env bun
|
|
57
|
+
import { Unfazed, UnfazedDeployError } from "unfazed";
|
|
58
|
+
|
|
59
|
+
const unfazed = new Unfazed();
|
|
60
|
+
|
|
61
|
+
const ws = await unfazed.createWorkspace("greeter");
|
|
62
|
+
|
|
63
|
+
// One request, not three — batched as aliased mutations.
|
|
64
|
+
await unfazed.writeFiles(ws.id, {
|
|
65
|
+
"server.ts": `
|
|
66
|
+
export default {
|
|
67
|
+
fetch(req: Request) {
|
|
68
|
+
const name = new URL(req.url).searchParams.get("name") ?? "world";
|
|
69
|
+
return Response.json({ hello: name });
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
`,
|
|
73
|
+
"unfazed.json": JSON.stringify({ entry: "server.ts" }),
|
|
74
|
+
"README.md": "# greeter",
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
// Blocks until the build, VM boot and health probe all pass.
|
|
79
|
+
const app = await unfazed.deployService({
|
|
80
|
+
workspaceId: ws.id,
|
|
81
|
+
alias: "greeter",
|
|
82
|
+
wait: true,
|
|
83
|
+
});
|
|
84
|
+
console.log(`live: ${app.url}`);
|
|
85
|
+
|
|
86
|
+
// Verify it for real before trusting the alias.
|
|
87
|
+
const res = await fetch(`${app.url}?name=agent`);
|
|
88
|
+
console.log(res.status, await res.json());
|
|
89
|
+
|
|
90
|
+
// Filter logs LOCALLY. This is the whole point: a 16 KiB tail costs the
|
|
91
|
+
// model nothing, because only the matching lines are ever printed.
|
|
92
|
+
const logs = await unfazed.getLogs(app.id, { tailBytes: 16384 });
|
|
93
|
+
const errors = logs.stdout
|
|
94
|
+
.split("\n")
|
|
95
|
+
.filter((l) => /error|warn/i.test(l))
|
|
96
|
+
.slice(-20);
|
|
97
|
+
console.log(errors.length ? errors.join("\n") : "no errors in tail");
|
|
98
|
+
} catch (e) {
|
|
99
|
+
if (e instanceof UnfazedDeployError && e.reason === "FAILED") {
|
|
100
|
+
// The build finished and is broken — retrying will not help.
|
|
101
|
+
console.error("build failed:", e.message);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
throw e;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Two layers
|
|
109
|
+
|
|
110
|
+
### 1. Typed GraphQL core — `UnfazedClient`
|
|
111
|
+
|
|
112
|
+
A fetch-based transport with full types and nothing else. Use it for any of the
|
|
113
|
+
platform's ~660 schema fields the workflow layer doesn't wrap.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { UnfazedClient, operations } from "unfazed";
|
|
117
|
+
|
|
118
|
+
const client = new UnfazedClient();
|
|
119
|
+
|
|
120
|
+
// Generated documents infer both result and variable types.
|
|
121
|
+
const { whoami } = await client.query(operations.WhoamiDocument, {});
|
|
122
|
+
|
|
123
|
+
// Or your own document, with explicit types.
|
|
124
|
+
const data = await client.query<{ workspaces: { id: string }[] }, never>(
|
|
125
|
+
`query { workspaces { id } }`,
|
|
126
|
+
);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Errors are typed and specific: `UnfazedAuthError`, `UnfazedHTTPError` (carries
|
|
130
|
+
`status`/`body`), `UnfazedGraphQLError` (carries `errors` **and any partial
|
|
131
|
+
`data`**), `UnfazedTimeoutError`, `UnfazedDeployError`, `UnfazedConflictError`,
|
|
132
|
+
`UnfazedNotFoundError`. All extend `UnfazedError`.
|
|
133
|
+
|
|
134
|
+
### 2. Workflow layer — `Unfazed`
|
|
135
|
+
|
|
136
|
+
The chains an agent actually performs. Reach `client` from it any time:
|
|
137
|
+
`unfazed.client.query(...)`.
|
|
138
|
+
|
|
139
|
+
**Identity**
|
|
140
|
+
| Method | Notes |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `whoami()` | actor kind, scopes, usage and resource limits |
|
|
143
|
+
|
|
144
|
+
**Workspaces**
|
|
145
|
+
| Method | Notes |
|
|
146
|
+
| --- | --- |
|
|
147
|
+
| `createWorkspace(name)` | |
|
|
148
|
+
| `listWorkspaces()` | |
|
|
149
|
+
| `deleteWorkspace(id)` | also destroys a BOX's data disk |
|
|
150
|
+
|
|
151
|
+
**Files**
|
|
152
|
+
| Method | Notes |
|
|
153
|
+
| --- | --- |
|
|
154
|
+
| `writeFiles(wsId, files, opts?)` | **batched** — many files per request |
|
|
155
|
+
| `writeFile(wsId, path, text)` | |
|
|
156
|
+
| `writeBinaryFile(wsId, path, bytes)` | base64 under the hood |
|
|
157
|
+
| `listFiles(wsId, page?)` | |
|
|
158
|
+
| `readFile(wsId, path, range?)` | |
|
|
159
|
+
| `deleteFile(wsId, path)` | |
|
|
160
|
+
|
|
161
|
+
**Deploy**
|
|
162
|
+
| Method | Notes |
|
|
163
|
+
| --- | --- |
|
|
164
|
+
| `deployService(opts)` | `wait: true` polls to READY |
|
|
165
|
+
| `deployStatic(opts)` | `spaMode` for single-page apps |
|
|
166
|
+
| `deployBox(opts)` | persistent Linux VM; result carries `sshCommand` |
|
|
167
|
+
| `deploy(input, opts?)` | raw `CreateDeploymentInput` escape hatch |
|
|
168
|
+
| `waitForDeployment(id, opts?)` | standalone poller |
|
|
169
|
+
| `getDeployment(id)` / `getDeploymentByAlias(alias)` | |
|
|
170
|
+
| `listDeployments(filter?)` | |
|
|
171
|
+
|
|
172
|
+
**Runtime**
|
|
173
|
+
| Method | Notes |
|
|
174
|
+
| --- | --- |
|
|
175
|
+
| `getLogs(id, { tailBytes })` | stdout + stderr tail |
|
|
176
|
+
| `getStatus(id)` | health, in-flight, restarts, `memSizeMiB` |
|
|
177
|
+
| `getEvents(id, limit?)` | build/boot/probe/cron lifecycle events |
|
|
178
|
+
| `restartService(id)` / `stopService(id)` | |
|
|
179
|
+
| `deleteDeployment(id)` | |
|
|
180
|
+
|
|
181
|
+
**Env & secrets**
|
|
182
|
+
| Method | Notes |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| `setEnv` / `setSecret` / `deleteEnv` / `listEnv` | workspace-wide defaults |
|
|
185
|
+
| `setEnvMany(wsId, vars, { secret? })` | **batched** |
|
|
186
|
+
| `setAppEnv` / `setAppSecret` | one alias only |
|
|
187
|
+
| `removeAppEnv` (mask) / `inheritAppEnv` (unmask) | |
|
|
188
|
+
| `listAppEnv(wsId, alias)` | effective view; secrets redacted |
|
|
189
|
+
|
|
190
|
+
**Releases**
|
|
191
|
+
| Method | Notes |
|
|
192
|
+
| --- | --- |
|
|
193
|
+
| `listReleases(alias)` | newest first; one entry has `aliasHeld: true` |
|
|
194
|
+
| `rollback({ alias, to?, retries? })` | **whole compare-and-swap in one call** |
|
|
195
|
+
|
|
196
|
+
## The two things worth knowing
|
|
197
|
+
|
|
198
|
+
### `writeFiles` batches, because the API is one-file-per-mutation
|
|
199
|
+
|
|
200
|
+
Writing a 12-file app the obvious way costs 12 round trips. `writeFiles` puts
|
|
201
|
+
one **aliased** mutation per file into a single GraphQL document:
|
|
202
|
+
|
|
203
|
+
```graphql
|
|
204
|
+
mutation SdkWriteFilesBatch($workspaceID: ID!, $p0: String!, $c0: String!, ...) {
|
|
205
|
+
f0: writeWorkspaceTextFile(input: { workspaceID: $workspaceID, path: $p0, text: $c0 }) { file { ... } }
|
|
206
|
+
f1: writeWorkspaceBase64File(input: { workspaceID: $workspaceID, path: $p1, contentBase64: $c1 }) { file { ... } }
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Text and binary mix freely in one batch. It splits automatically at 20 files or
|
|
211
|
+
4 MiB per request (`batchSize`, `maxBatchBytes`).
|
|
212
|
+
|
|
213
|
+
Batches are **not atomic** — GraphQL resolves each field independently. If one
|
|
214
|
+
path fails, the others still commit; the thrown `UnfazedGraphQLError` carries
|
|
215
|
+
`data` with the aliases that succeeded and `errors[].path` naming the ones that
|
|
216
|
+
didn't.
|
|
217
|
+
|
|
218
|
+
### `rollback` does the compare-and-swap for you
|
|
219
|
+
|
|
220
|
+
The platform requires you to prove you observed the current state: you must send
|
|
221
|
+
the live release's id **and** its opaque `aliasRevision`, and the swap is
|
|
222
|
+
rejected if either moved — including same-id ABA. That's a read-then-write
|
|
223
|
+
protocol, and getting it wrong means racing a concurrent deploy.
|
|
224
|
+
|
|
225
|
+
`rollback` does the whole thing in one call: list releases → find the `aliasHeld`
|
|
226
|
+
entry → pick the target → submit both guard values.
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
await unfazed.rollback({ alias: "my-app" }); // undo the last deploy
|
|
230
|
+
await unfazed.rollback({ alias: "my-app", to: relId }); // a specific release
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
If the guard is rejected it re-lists and retries once (`retries`). The **target
|
|
234
|
+
stays pinned** across retries while the guard is refreshed — a concurrent deploy
|
|
235
|
+
can never redirect your rollback to a release you didn't choose. Non-READY
|
|
236
|
+
targets and the current holder are refused client-side, before the mutation.
|
|
237
|
+
|
|
238
|
+
## Deploy semantics the SDK can't hide
|
|
239
|
+
|
|
240
|
+
- `createDeployment` returns **`BUILDING`** immediately. `READY` and `FAILED`
|
|
241
|
+
are the only terminal states. `wait: true` exists because of this.
|
|
242
|
+
- `previewUrl` is the immutable by-id URL. It 503s (with `Retry-After`) while
|
|
243
|
+
building and 422s with the build error on failure — use it to verify a build
|
|
244
|
+
before it owns the public alias.
|
|
245
|
+
- Env and secrets are **snapshotted into a release at deploy time**. Changing
|
|
246
|
+
them does not affect a running app until you redeploy that alias. Old releases
|
|
247
|
+
are immutable, and STATIC deployments get no env at all.
|
|
248
|
+
- Release retention keeps only the most recent few per alias (default 5). Older
|
|
249
|
+
releases can't be inspected or restored.
|
|
250
|
+
|
|
251
|
+
## Development
|
|
252
|
+
|
|
253
|
+
```sh
|
|
254
|
+
bun install
|
|
255
|
+
bun run codegen # regenerate typed operations from the vendored schema
|
|
256
|
+
bun run typecheck
|
|
257
|
+
bun test
|
|
258
|
+
bun run build
|
|
259
|
+
bun run check # all of the above, plus a dist smoke test on Bun AND Node
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Regenerating from the schema
|
|
263
|
+
|
|
264
|
+
`schema/schema.graphqls` is a **vendored copy** of `graph/schema.graphqls` from
|
|
265
|
+
the [unfazed](https://unfazed.dev) repo — the same contract gqlgen serves. It is
|
|
266
|
+
vendored so `bun install && bun run build` works with no access to the platform
|
|
267
|
+
repo, and `schema/SOURCE.json` records the exact unfazed commit it came from.
|
|
268
|
+
|
|
269
|
+
To refresh it against a local unfazed checkout:
|
|
270
|
+
|
|
271
|
+
```sh
|
|
272
|
+
bun run sync-schema # tries ../../../unfazed, then $UNFAZED_REPO
|
|
273
|
+
UNFAZED_REPO=~/src/unfazed bun run sync-schema
|
|
274
|
+
bun run sync-schema -- --repo ~/src/unfazed
|
|
275
|
+
bun run sync-schema -- --check # verify only; non-zero if stale
|
|
276
|
+
|
|
277
|
+
bun run codegen && bun test # ALWAYS follow a sync with these
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
`src/generated/` is committed on purpose: consumers of the published package
|
|
281
|
+
never run codegen, and neither does a clean CI checkout. A schema change that
|
|
282
|
+
invalidates an operation shows up as a **compile error**, not a runtime
|
|
283
|
+
surprise.
|
|
284
|
+
|
|
285
|
+
`bun run codegen` also runs `scripts/postcodegen.ts`, which inlines the one
|
|
286
|
+
type-only import graphql-codegen emits (`DocumentTypeDecoration`) so the package
|
|
287
|
+
keeps zero dependencies. `test/generated.test.ts` asserts that invariant.
|
|
288
|
+
|
|
289
|
+
## Publishing
|
|
290
|
+
|
|
291
|
+
Publishing is a deliberate, attended step — there is intentionally **no**
|
|
292
|
+
`prepublishOnly`/`prepare` script that could fire a publish or a stale build by
|
|
293
|
+
accident. `dist/` is gitignored, so build before publishing:
|
|
294
|
+
|
|
295
|
+
```sh
|
|
296
|
+
bun run check # typecheck + tests + build + dist smoke
|
|
297
|
+
npm publish # or: bun publish --access public
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## License
|
|
301
|
+
|
|
302
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/** SDK version, sent as the User-Agent. Keep in sync with package.json. */
|
|
2
|
+
export declare const VERSION = "0.1.0";
|
|
3
|
+
/**
|
|
4
|
+
* Default GraphQL endpoint.
|
|
5
|
+
*
|
|
6
|
+
* Note this is the FULL endpoint, not an origin: the platform's own documented
|
|
7
|
+
* convention (`UNFZ_API_URL="https://unfazed.dev/query"`, and cmd/showcase-deploy
|
|
8
|
+
* in the unfazed repo) treats the /query URL as the configurable unit, so the
|
|
9
|
+
* SDK matches it rather than inventing a base-URL convention.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_ENDPOINT = "https://unfazed.dev/query";
|
|
12
|
+
/** Platform origin, used to derive the endpoint when only `baseUrl` is given. */
|
|
13
|
+
export declare const DEFAULT_BASE_URL = "https://unfazed.dev";
|
|
14
|
+
/** Path of the GraphQL endpoint under an origin. */
|
|
15
|
+
export declare const GRAPHQL_PATH = "/query";
|
|
16
|
+
/**
|
|
17
|
+
* Environment variable holding the bearer token.
|
|
18
|
+
*
|
|
19
|
+
* This is the platform's documented name (docs/agent-deployments.md,
|
|
20
|
+
* internal/agentdocs/reference.md). It accepts either an operator API token or
|
|
21
|
+
* an agent access token from POST /agents/register — /query takes both as
|
|
22
|
+
* plain bearers.
|
|
23
|
+
*/
|
|
24
|
+
export declare const TOKEN_ENV_VAR = "UNFZ_API_TOKEN";
|
|
25
|
+
/** Environment variable holding the full GraphQL endpoint URL. */
|
|
26
|
+
export declare const ENDPOINT_ENV_VAR = "UNFZ_API_URL";
|
|
27
|
+
/** Minimal structural type of the `fetch` the transport needs. */
|
|
28
|
+
export type FetchLike = (input: string, init: {
|
|
29
|
+
method: string;
|
|
30
|
+
headers: Record<string, string>;
|
|
31
|
+
body: string;
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
}) => Promise<{
|
|
34
|
+
ok: boolean;
|
|
35
|
+
status: number;
|
|
36
|
+
text(): Promise<string>;
|
|
37
|
+
}>;
|
|
38
|
+
export interface ClientOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Bearer token. Falls back to `UNFZ_API_TOKEN`. Get one from
|
|
41
|
+
* https://unfazed.dev/auth.md — the same token the MCP server uses.
|
|
42
|
+
*/
|
|
43
|
+
token?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Full GraphQL endpoint URL. Wins over `baseUrl`. Falls back to
|
|
46
|
+
* `UNFZ_API_URL`, then {@link DEFAULT_ENDPOINT}.
|
|
47
|
+
*/
|
|
48
|
+
endpoint?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Platform origin; `/query` is appended. Convenience for self-hosted or
|
|
51
|
+
* staging control planes where only the host differs.
|
|
52
|
+
*/
|
|
53
|
+
baseUrl?: string;
|
|
54
|
+
/** Extra headers merged into every request. Authorization always wins. */
|
|
55
|
+
headers?: Record<string, string>;
|
|
56
|
+
/**
|
|
57
|
+
* Per-request timeout in ms. Default 60_000. Pass 0 to disable.
|
|
58
|
+
*
|
|
59
|
+
* Bounds the WHOLE request — connect, headers and reading the response body —
|
|
60
|
+
* so a proxy that answers with headers and then stalls still fails on time.
|
|
61
|
+
*/
|
|
62
|
+
timeoutMs?: number;
|
|
63
|
+
/** Injection point for tests and instrumented/proxied transports. */
|
|
64
|
+
fetch?: FetchLike;
|
|
65
|
+
/** Overrides the default `unfazed-sdk/<version>` User-Agent. */
|
|
66
|
+
userAgent?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A GraphQL document.
|
|
70
|
+
*
|
|
71
|
+
* Structural rather than `string & {...}` on purpose: graphql-codegen emits
|
|
72
|
+
* `TypedDocumentString`, a String SUBCLASS, which is not assignable to the
|
|
73
|
+
* primitive `string`. Requiring only `toString()` plus the optional phantom
|
|
74
|
+
* `__apiType` lets three things through with full inference:
|
|
75
|
+
*
|
|
76
|
+
* - generated `TypedDocumentString` documents (types inferred),
|
|
77
|
+
* - documents assembled at runtime, like the batched writeFiles mutation,
|
|
78
|
+
* - plain template-literal strings a caller wrote by hand.
|
|
79
|
+
*/
|
|
80
|
+
export interface GraphQLDocument<TResult, TVariables> {
|
|
81
|
+
/** Phantom type carrier. Never called; present only to bind the generics. */
|
|
82
|
+
__apiType?: (variables: TVariables) => TResult;
|
|
83
|
+
toString(): string;
|
|
84
|
+
}
|
|
85
|
+
/** Result type carried by a typed document. */
|
|
86
|
+
export type ResultOf<T> = T extends GraphQLDocument<infer R, infer _V> ? R : unknown;
|
|
87
|
+
/** Variables type carried by a typed document. */
|
|
88
|
+
export type VariablesOf<T> = T extends GraphQLDocument<infer _R, infer V> ? V : never;
|
|
89
|
+
/** Per-request knobs. */
|
|
90
|
+
export interface RequestOptions {
|
|
91
|
+
signal?: AbortSignal;
|
|
92
|
+
timeoutMs?: number;
|
|
93
|
+
operationName?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Layer 1 — a typed, dependency-free GraphQL transport over `fetch`.
|
|
97
|
+
*
|
|
98
|
+
* This is the SDK's entire networking surface. It understands auth, timeouts
|
|
99
|
+
* and the GraphQL error envelope, and nothing about deployments. The workflow
|
|
100
|
+
* layer ({@link import("./unfazed.js").Unfazed}) is built strictly on top of
|
|
101
|
+
* it, so you can always drop down here for any operation the workflow layer
|
|
102
|
+
* does not wrap — the schema has ~660 fields and the workflow layer
|
|
103
|
+
* deliberately covers only the agent-facing ones.
|
|
104
|
+
*
|
|
105
|
+
* ```ts
|
|
106
|
+
* const client = new UnfazedClient(); // reads UNFZ_API_TOKEN
|
|
107
|
+
* const data = await client.query<{ whoami: { name: string } }, never>(
|
|
108
|
+
* `query { whoami { name } }`,
|
|
109
|
+
* );
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare class UnfazedClient {
|
|
113
|
+
#private;
|
|
114
|
+
/** Resolved GraphQL endpoint URL. */
|
|
115
|
+
readonly endpoint: string;
|
|
116
|
+
constructor(options?: ClientOptions);
|
|
117
|
+
/** Runs a query document. Identical wire behaviour to {@link mutate}. */
|
|
118
|
+
query<TResult, TVariables>(document: GraphQLDocument<TResult, TVariables>, variables?: TVariables, options?: RequestOptions): Promise<TResult>;
|
|
119
|
+
/**
|
|
120
|
+
* Runs a mutation document. Distinct from {@link query} for call-site
|
|
121
|
+
* readability only — GraphQL over HTTP POST makes no distinction.
|
|
122
|
+
*/
|
|
123
|
+
mutate<TResult, TVariables>(document: GraphQLDocument<TResult, TVariables>, variables?: TVariables, options?: RequestOptions): Promise<TResult>;
|
|
124
|
+
/**
|
|
125
|
+
* The single code path behind {@link query} and {@link mutate}.
|
|
126
|
+
*
|
|
127
|
+
* Throws {@link UnfazedHTTPError} on non-2xx, {@link UnfazedGraphQLError}
|
|
128
|
+
* when the body carries `errors`, {@link UnfazedTimeoutError} on timeout or
|
|
129
|
+
* abort. Resolves to the `data` object on success.
|
|
130
|
+
*/
|
|
131
|
+
request<TResult = unknown>(document: string | {
|
|
132
|
+
toString(): string;
|
|
133
|
+
}, variables?: unknown, options?: RequestOptions): Promise<TResult>;
|
|
134
|
+
}
|