unfazed 0.6.0 → 0.8.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +299 -78
  3. package/REFERENCE.md +284 -0
  4. package/dist/cli/login.d.ts +129 -0
  5. package/dist/cli/login.js +596 -0
  6. package/dist/cli/login.js.map +1 -0
  7. package/dist/cli/workflow.d.ts +31 -0
  8. package/dist/cli/workflow.js +157 -0
  9. package/dist/cli/workflow.js.map +1 -0
  10. package/dist/cli.d.ts +2 -0
  11. package/dist/cli.js +173 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/client.d.ts +26 -5
  14. package/dist/client.js +93 -48
  15. package/dist/client.js.map +1 -1
  16. package/dist/credentials.d.ts +123 -0
  17. package/dist/credentials.js +317 -0
  18. package/dist/credentials.js.map +1 -0
  19. package/dist/errors.d.ts +64 -0
  20. package/dist/errors.js +95 -0
  21. package/dist/errors.js.map +1 -1
  22. package/dist/generated/gql.d.ts +78 -2
  23. package/dist/generated/gql.js +21 -2
  24. package/dist/generated/gql.js.map +1 -1
  25. package/dist/generated/graphql.d.ts +505 -6
  26. package/dist/generated/graphql.js +439 -2
  27. package/dist/generated/graphql.js.map +1 -1
  28. package/dist/index.d.ts +25 -6
  29. package/dist/index.js +23 -5
  30. package/dist/index.js.map +1 -1
  31. package/dist/operations.d.ts +116 -5
  32. package/dist/operations.js +379 -7
  33. package/dist/operations.js.map +1 -1
  34. package/dist/reference.d.ts +18 -0
  35. package/dist/reference.generated.d.ts +2 -0
  36. package/dist/reference.generated.js +5 -0
  37. package/dist/reference.generated.js.map +1 -0
  38. package/dist/reference.js +38 -0
  39. package/dist/reference.js.map +1 -0
  40. package/dist/remote/app.js +2 -1
  41. package/dist/remote/app.js.map +1 -1
  42. package/dist/remote/world.d.ts +2 -2
  43. package/dist/remote/world.js +32 -16
  44. package/dist/remote/world.js.map +1 -1
  45. package/dist/unfazed.d.ts +545 -68
  46. package/dist/unfazed.js +688 -64
  47. package/dist/unfazed.js.map +1 -1
  48. package/dist/wait.d.ts +7 -0
  49. package/dist/wait.js.map +1 -1
  50. package/dist/workflow/nitro.js +5 -3
  51. package/dist/workflow/nitro.js.map +1 -1
  52. package/package.json +22 -6
  53. package/schema/SOURCE.json +4 -4
  54. package/schema/schema.graphqls +1628 -30
package/REFERENCE.md ADDED
@@ -0,0 +1,284 @@
1
+ # unfazed SDK reference
2
+
3
+ Every method of `Unfazed`, with its signature, in one page. In a script:
4
+ `import { Unfazed, help } from "unfazed"; const unfazed = new Unfazed();`
5
+ (run_script injects the credential; elsewhere `UNFZ_API_TOKEN` or
6
+ `npx unfazed login`). `help()` returns this page; `help("writeFiles")` one
7
+ entry. Methods are async and throw an `UnfazedError` subclass on failure.
8
+ Every method takes an optional last `options` with `signal` (and, for single
9
+ requests, `timeoutMs`). The names follow the MCP tools: `listCommits` is
10
+ `list_commits`, `waitForEvents` is `wait_for_events`.
11
+
12
+ ```ts
13
+ import { Unfazed } from "unfazed";
14
+
15
+ export default async () => {
16
+ const unfazed = new Unfazed();
17
+ const ws = await unfazed.ensureWorkspace("hello");
18
+ const wrote = await unfazed.writeFiles(ws.id, {
19
+ "server.ts": `export default { fetch: () => new Response("hi") }`,
20
+ "package.json": JSON.stringify({ name: "hello" }),
21
+ }, { commitMessage: "First version" }); // ONE request, ONE commit
22
+ const app = await unfazed.deployService({ workspaceId: ws.id, alias: "hello", wait: true });
23
+ return { url: app.url, commit: wrote.commit?.sha, timings: app.timings };
24
+ };
25
+ ```
26
+
27
+ ## Saved, committed, deployed
28
+
29
+ A file write has three states. **Saved**: the call returned; the app's
30
+ files have it and the next deploy uses it. **Committed**: on an app with
31
+ platform git, `commit.committed && !commit.waiting`; it is in `listCommits`.
32
+ **Deployed**: a deploy of those files went READY (`deployService({ wait:
33
+ true })`). A write never deploys by itself, except when `commit.deploys` is
34
+ true (the branch head is imported like a push).
35
+
36
+ `commit.waiting: true` means saved, with the commit queued for the git
37
+ server: it lands in order, `sha` is null until then, nothing to retry.
38
+ `waitForCommit` (or `writeFiles(…, { waitForCommit: true })`) resolves once
39
+ it landed.
40
+
41
+ ## Workspaces
42
+
43
+ ### `createWorkspace(name: string): Promise<Workspace>`
44
+ A new workspace: files, env, deployments. Names are unique per owner,
45
+ case-insensitively; prefer `ensureWorkspace` in re-runnable scripts.
46
+
47
+ ### `ensureWorkspace(name: string): Promise<Workspace>`
48
+ The workspace named `name`, created only when missing. Safe to re-run.
49
+
50
+ ### `listWorkspaces(): Promise<Workspace[]>`
51
+
52
+ ### `liveApps(workspaceId: string): Promise<LiveApp[]>`
53
+ The apps the workspace serves now: `{ alias, deploymentID, domains }`.
54
+
55
+ ### `deleteWorkspace(workspaceId: string, options?: { withDeployments?: true, confirmAliases: string[], ignoreNotFound?: boolean }): Promise<boolean>`
56
+ Deletes it; with `withDeployments`, every app it serves, which
57
+ `confirmAliases` must name exactly (`liveApps`). Kept 30 days for support.
58
+
59
+ ### `deleteApp(app: { workspaceId, alias }, options?: { ignoreNotFound?: boolean }): Promise<DeleteAppResult>`
60
+ Deletes one app (every deployment of the alias, its App State, env and
61
+ bindings); the workspace and its other apps stay.
62
+
63
+ ### `whoami(): Promise<Whoami>`
64
+ Who the token is, its scopes, usage and limits.
65
+
66
+ ## Files
67
+
68
+ ### `writeFiles(workspaceId: string, files: Record<string, string | { text } | { base64 } | { bytes }>, options?: { commitMessage?: string, waitForCommit?: boolean | WaitOptions, allowPartial?: boolean }): Promise<WriteFilesResult>`
69
+ Writes every file in ONE request, which is ONE commit on an app with
70
+ platform git (MCP `write_workspace_files`). Result: `{ files: [{ path, ok,
71
+ error, file }], written, failed, totalBytes, commit, commits, landed? }`;
72
+ `commit` is `{ sha, branch, message, committed, waiting, waitingCount,
73
+ deploys, conflicts, writeSHA, paused }` or null without platform git. Not
74
+ transactional: when a file fails it throws `UnfazedWriteError` (`.result`,
75
+ `.failed`) unless `allowPartial`. Up to 100 files and 32 MiB per request; a
76
+ bigger map is several requests, each a commit.
77
+
78
+ ```ts
79
+ const out = await unfazed.writeFiles(ws.id, { "a.ts": a, "logo.png": { bytes } }, { commitMessage: "Logo" });
80
+ if (out.commit?.conflicts.length) console.log("a push changed", out.commit.conflicts, "mine:", out.commit.writeSHA);
81
+ ```
82
+
83
+ ### `writeFile(workspaceId: string, path: string, text: string, options?: { commitMessage?, waitForCommit? }): Promise<WorkspaceFile & { commit }>`
84
+ One text file: `writeFiles` with one entry.
85
+
86
+ ### `writeBinaryFile(workspaceId: string, path: string, content: Uint8Array | ArrayBuffer | { base64: string }, options?): Promise<WorkspaceFile & { commit }>`
87
+
88
+ ### `waitForCommit(workspaceId: string, waitOptions?: WaitOptions): Promise<{ branch, head, waitedMs }>`
89
+ Resolves once no write of the app waits for its commit; `head` then has
90
+ every earlier write. Immediate (`head: null`) without platform git. Default
91
+ timeout 2 minutes (`UnfazedTimeoutError`; the writes stay saved).
92
+
93
+ ### `readFile(workspaceId: string, path: string, input?: { offset?, limit? }): Promise<{ text, totalBytes, truncated, nextOffset, file } | null>`
94
+
95
+ ### `listFiles(workspaceId: string, input?: { limit?, offset?, order? }): Promise<WorkspaceFilePage>`
96
+
97
+ ### `deleteFile(workspaceId: string, path: string): Promise<boolean>`
98
+ `false` when there was nothing to delete.
99
+
100
+ ## Deploys
101
+
102
+ ### `deployService(options: { workspaceId, alias?, wait?, waitOptions?, timings?, runtime?, serviceMode?, healthPath?, cronSchedule?, cronPath? }): Promise<DeployResult>`
103
+ Builds and deploys the workspace as an HTTP service (`server.ts` default
104
+ export, or `unfazed.json`). Returns BUILDING at once; with `wait: true`,
105
+ resolves READY or throws `UnfazedDeployError` (`reason` FAILED with the
106
+ build error, or TIMEOUT; default 10 minutes). Every call is a new release;
107
+ the same `alias` redeploys that app.
108
+
109
+ With `wait: true` the result has `timings`:
110
+ `{ client: { createMs, waitMs, totalMs, waitRequests, waitMode },
111
+ platform: { totalMs, buildMs, promoteMs, phases, buildMode,
112
+ artifactTransport, buildMemoryMiB } }`, both in milliseconds. `platform` is
113
+ what the platform measured (created to READY); `client` is what you waited.
114
+ The wait is server-side, so the two differ by about one round trip.
115
+
116
+ ```ts
117
+ const app = await unfazed.deployService({ workspaceId: ws.id, alias: "api", wait: true });
118
+ app.timings?.platform?.phases; // { vm_install: 900, vm_build: 2600, admission: 40, … }
119
+ ```
120
+
121
+ ### `deployStatic(options: { workspaceId, alias?, wait?, spaMode? }): Promise<DeployResult>`
122
+
123
+ ### `deployBox(options: { workspaceId, alias, wait?, resources?: { memMiB?, vcpus?, diskGiB? } }): Promise<DeployResult>`
124
+ A persistent Linux VM over SSH (`sshCommand`). Always pass `alias`.
125
+
126
+ ### `deploy(input: CreateDeploymentInput, options?: { wait?, waitOptions?, timings? }): Promise<DeployResult>`
127
+ Any `createDeployment` input.
128
+
129
+ ### `waitForDeployment(deploymentId: string, waitOptions?: WaitOptions): Promise<Deployment>`
130
+ Waits server-side (MCP `wait_for_deployment`: one request per 45 s at most,
131
+ answered when the status changes) until READY; throws `UnfazedDeployError`
132
+ on FAILED or timeout. A new app's landing on its server is waited for too.
133
+ `waitOptions: { timeoutMs?, signal?, mode?: "server" | "poll" }`. The
134
+ platform holds at most 16 waits of one account at once; past that a wait
135
+ polls instead.
136
+
137
+ ### `getDeployment(deploymentId: string): Promise<Deployment | null>`
138
+
139
+ ### `getDeploymentByAlias(alias: string): Promise<Deployment | null>`
140
+
141
+ ### `listDeployments(input?: { workspaceID?, alias?, kind?, limit?, offset? }): Promise<DeploymentPage>`
142
+ Newest first.
143
+
144
+ ### `listReleases(alias: string): Promise<Deployment[]>`
145
+ The alias's history; `aliasHeld` marks the live one.
146
+
147
+ ### `rollback(options: { alias, to?, expectedCurrentId?, retries? }): Promise<Deployment>`
148
+ Points the alias back at a prior READY release (default: the one before
149
+ the live one). A bare `rollback({ alias })` toggles; pin `to` in anything
150
+ re-runnable.
151
+
152
+ ### `deleteDeployment(deploymentId: string, options?: { ignoreNotFound? }): Promise<boolean>`
153
+
154
+ ## Runtime, logs, events, timings
155
+
156
+ ### `getStatus(deploymentId: string): Promise<ServiceStatus>`
157
+ `{ running, health, inFlight, restartCount, memSizeMiB, lastError, … }`.
158
+
159
+ ### `getLogs(deploymentId: string, input?: { tailBytes? }): Promise<{ stdout, stderr, truncated, … }>`
160
+ Filter in the script: `logs.stderr.split("\n").filter((l) => l.includes("ERROR"))`.
161
+
162
+ ### `getEvents(deploymentId: string, limit?: number): Promise<DeploymentEvent[]>`
163
+ The latest `limit` (default 20) lifecycle events, oldest first: `{ type,
164
+ typeEnum, severity, message, vmID, metadata, createdAt }`. `type` is the
165
+ event's own name, as MCP reports it: `"deployment.build_finished"`,
166
+ `"deployment.phases"`, `"service.vm_started"`. `typeEnum` is the GraphQL
167
+ enum (`UNKNOWN` for names it lacks); match on `type`.
168
+
169
+ ### `getDeploymentTimings(deploymentId: string): Promise<PlatformTimings | null>`
170
+ A deploy's measured phases (ms) from its timing events: `{ totalMs,
171
+ buildMs, promoteMs, phases, buildMode, artifactTransport, buildMemoryMiB }`.
172
+ `parseDeploymentTimings(events)` does the same for events you already read.
173
+
174
+ ### `restartService(deploymentId: string)` / `stopService(deploymentId: string)`
175
+
176
+ ## Env and secrets
177
+
178
+ Snapshotted into a release at deploy time: redeploy the alias to apply.
179
+
180
+ ### `setEnv(workspaceId, name, value)` / `setSecret(workspaceId, name, value)`: `Promise<EnvVar>`
181
+ Workspace defaults. A name is plain or secret, never both.
182
+
183
+ ### `setEnvMany(workspaceId: string, vars: Record<string, string>, options?: { secret?: boolean }): Promise<EnvVar[]>`
184
+
185
+ ### `deleteEnv(workspaceId, name): Promise<boolean>` / `listEnv(workspaceId): Promise<EnvVar[]>`
186
+
187
+ ### `setAppEnv(workspaceId, alias, name, value)` / `setAppSecret(workspaceId, alias, name, value)`: `Promise<EnvVar>`
188
+ One app's override.
189
+
190
+ ### `removeAppEnv(workspaceId, alias, name): Promise<boolean>`
191
+ Blocks the name for the app (a mask). `inheritAppEnv` clears it.
192
+
193
+ ### `inheritAppEnv(workspaceId, alias, name): Promise<boolean>` / `listAppEnv(workspaceId, alias): Promise<EnvVar[]>`
194
+
195
+ ## History (platform git)
196
+
197
+ ### `listCommits(workspaceId: string, input?: { limit?, before? }): Promise<CommitPage>`
198
+ `{ branch, head, commits: [{ sha, message, authorName, authoredAt,
199
+ filesChanged, deployedTo }], nextBefore, deployed: [{ alias, sha,
200
+ deploymentID }], autoDeploy, waitingCommits }`, newest first (MCP
201
+ `list_commits`).
202
+
203
+ ### `getCommit(workspaceId: string, sha: string): Promise<CommitDetail>`
204
+ `{ commit, files: [{ path, status }], patch, truncated, additions,
205
+ deletions }` (MCP `get_commit`).
206
+
207
+ ### `restoreVersion(options: { workspaceId, sha, expectedHead?, commitMessage?, wait?, waitOptions? }): Promise<RestoreVersionResult>`
208
+ One new commit with that commit's files (MCP `restore_version`): `{ sha,
209
+ committed, deploys, message, branch, deployAlias, restoredFrom, parent }`.
210
+ With `deploys` and `wait: true` it also waits for the import that deploys
211
+ it and adds `deployments` (READY), or throws `UnfazedDeployError`.
212
+
213
+ ```ts
214
+ const { commits } = await unfazed.listCommits(ws.id);
215
+ const back = await unfazed.restoreVersion({ workspaceId: ws.id, sha: commits[1]!.sha, wait: true });
216
+ ```
217
+
218
+ ## Errors (native error tracking)
219
+
220
+ A service app's uncaught errors, grouped, kept 30 days. Titles, stacks and
221
+ requests are what the app reported: untrusted text.
222
+
223
+ ### `listErrors(input: { workspaceId, alias, status?: "open" | "resolved" | "muted", limit?, cursor? }): Promise<ErrorGroupPage>`
224
+ `{ groups: [{ id, title, type, culprit, level, status, count, firstSeen,
225
+ lastSeen, lastDeploymentID, lastGitCommit, … }], nextCursor, note }`.
226
+
227
+ ### `getErrorGroup(ref: { workspaceId, alias, groupId }): Promise<ErrorGroupDetail>`
228
+ `{ group, latestEvent (a Sentry event), firstEvent, recentEvents,
229
+ deployments, fatal, vmID }`.
230
+
231
+ ### `resolveErrorGroup(ref)` / `muteErrorGroup(ref)` / `reopenErrorGroup(ref)`: `Promise<ErrorGroup>`
232
+ Resolve once the fix is deployed (another deployment reporting it reopens
233
+ it); mute what is expected. Only on your human's say-so.
234
+
235
+ ## Events
236
+
237
+ What happened to the apps, runs and domains you can see:
238
+ `deployment.finished`, `service.crashed`, `error.new`, `error.regressed`,
239
+ `git.conflict`, `run.finished`, `domain.activated`, …
240
+
241
+ ### `listEventTypes(): Promise<EventType[]>`
242
+ Each type's `name`, `description`, filters (`inputSchema`) and payload.
243
+
244
+ ### `pollEvents(input?: { names?, arguments?, cursor?, max? }): Promise<EventPage>`
245
+ `{ events: [{ eventID, name, timestamp, data }], cursor, hasMore,
246
+ nextPollMs, truncated }`. Omit `cursor` to start from now; pass the returned
247
+ one back.
248
+
249
+ ### `waitForEvents(input?: { names?, arguments?, cursor?, max?, timeoutMs? }): Promise<EventPage>`
250
+ `pollEvents` that blocks server-side until an event arrives or `timeoutMs`
251
+ (default 45 s) passes; then `timedOut: true` with a cursor, not an error.
252
+ Past the account's 16 waits in progress it throws (`isTooManyWaits(e)`):
253
+ poll then.
254
+
255
+ ```ts
256
+ let page = await unfazed.pollEvents({ names: ["deployment.finished"], arguments: { "deployment.finished": { alias: "api" } } });
257
+ // … deploy …
258
+ page = await unfazed.waitForEvents({ names: ["deployment.finished"], cursor: page.cursor, timeoutMs: 120_000 });
259
+ ```
260
+
261
+ ## Agent runs
262
+
263
+ ### `createRun(options: { workspaceId, prompt?, harness?, command?, setup?, verify?, access?, alias?, maxSeconds?, wait? }): Promise<Run>`
264
+ A one-shot agent run in a fresh VM. `wait: true` polls to SUCCEEDED,
265
+ FAILED or CANCELLED (all returned, never thrown).
266
+
267
+ ### `waitForRun(runId: string, waitOptions?: WaitOptions): Promise<Run>`
268
+
269
+ ### `getRun(runId)` / `listRuns(filter?: { workspaceId?, status?, limit?, offset? })` / `cancelRun(runId)`
270
+
271
+ ### `followUpRun(runId: string, options: { prompt, mode?, wait? }): Promise<Run>`
272
+
273
+ ### `answerRun(runId: string, answer: string): Promise<Run>`
274
+ Answers a BLOCKED run's question.
275
+
276
+ ### `runEvents(runId)` / `runConsole(runId, { tailBytes? })` / `runTranscript(runId, { tailBytes? })`
277
+
278
+ ### `listRunHarnesses(): Promise<RunHarness[]>`
279
+
280
+ ## Anything else
281
+
282
+ `unfazed.client` is the typed GraphQL transport over the same credential:
283
+ `await unfazed.client.query(document, variables)`. `operations` exports
284
+ every document the SDK uses.
@@ -0,0 +1,129 @@
1
+ import { type StoredCredentials } from "../credentials.js";
2
+ import { UnfazedError } from "../errors.js";
3
+ export declare const USER_AGENT = "unfazed-cli/0.8.0 (+https://unfazed.dev/auth.md)";
4
+ /** What a login asks for: reading and deploying, like an MCP client. */
5
+ export declare const DEFAULT_SCOPE = "unfz:read unfz:deploy";
6
+ export declare const CLIENT_NAME = "unfazed CLI";
7
+ export declare const CALLBACK_PATH = "/callback";
8
+ /** The redirect registered once; each login uses it with its own port. */
9
+ export declare const REGISTERED_REDIRECT_URI = "http://127.0.0.1/callback";
10
+ /** Registered clients, per issuer, beside the login. */
11
+ export declare const CLIENTS_FILE = "oauth-clients.json";
12
+ /** How long a login waits for the browser. */
13
+ export declare const LOGIN_TIMEOUT_MS: number;
14
+ export type Env = Record<string, string | undefined>;
15
+ /** The `fetch` the CLI needs; the global one fits. */
16
+ export type Fetch = (input: string, init: {
17
+ method: string;
18
+ headers: Record<string, string>;
19
+ body?: string;
20
+ redirect?: "manual" | "follow";
21
+ signal?: AbortSignal;
22
+ }) => Promise<{
23
+ ok: boolean;
24
+ status: number;
25
+ text(): Promise<string>;
26
+ }>;
27
+ /** A login that could not be completed; the message says why and what to do. */
28
+ export declare class UnfazedLoginError extends UnfazedError {
29
+ }
30
+ /** The GraphQL endpoint: given, else `UNFZ_API_URL`, else unfazed.dev's; a bare origin gets `/query`. */
31
+ export declare function resolveEndpoint(raw: string | undefined, env: Env): string;
32
+ /** Whether a URL may carry tokens: https, or plain http to this machine only. */
33
+ export declare function safeURL(raw: unknown): raw is string;
34
+ /** RFC 8414 authorization server metadata: the fields the CLI uses. */
35
+ export interface AuthServerMetadata {
36
+ issuer: string;
37
+ authorization_endpoint: string;
38
+ token_endpoint: string;
39
+ registration_endpoint?: string;
40
+ revocation_endpoint?: string;
41
+ code_challenge_methods_supported?: string[];
42
+ response_types_supported?: string[];
43
+ authorization_response_iss_parameter_supported?: boolean;
44
+ }
45
+ /** Reads and checks the metadata of the server at `origin` (e.g. https://unfazed.dev). */
46
+ export declare function discover(origin: string, fetch: Fetch): Promise<AuthServerMetadata>;
47
+ /** A PKCE verifier and its S256 challenge. */
48
+ export declare function pkcePair(): {
49
+ verifier: string;
50
+ challenge: string;
51
+ };
52
+ /** A client the CLI registered at one issuer. */
53
+ export interface ClientRecord {
54
+ client_id: string;
55
+ redirect_uri: string;
56
+ scope: string;
57
+ registered_at: string;
58
+ }
59
+ /** The cached client for `issuer` that may ask for `scope`, if any. */
60
+ export declare function cachedClient(env: Env, issuer: string, scope: string): ClientRecord | undefined;
61
+ export interface LoginOptions {
62
+ /** GraphQL endpoint or platform origin. Default: `UNFZ_API_URL`, else https://unfazed.dev. */
63
+ endpoint?: string;
64
+ /** Space-separated scopes. Default: `unfz:read unfz:deploy`. */
65
+ scope?: string;
66
+ /** Default `process.env`: where `UNFZ_API_URL` and the login's location come from. */
67
+ env?: Env;
68
+ fetch?: Fetch;
69
+ /** Opens the sign-in URL; resolves to whether a browser started. Default: print only. */
70
+ openBrowser?: (url: string) => boolean | Promise<boolean>;
71
+ /** Where progress goes (never a token). Default: stderr. */
72
+ log?: (line: string) => void;
73
+ /** Where a pasted answer is read from (a browser on another machine). Default: none. */
74
+ input?: NodeJS.ReadableStream;
75
+ /** How long to wait for the browser. Default {@link LOGIN_TIMEOUT_MS}. */
76
+ timeoutMs?: number;
77
+ }
78
+ /** Signs in through the browser and stores the login. Resolves to it and where it was stored. */
79
+ export declare function login(options?: LoginOptions): Promise<{
80
+ credentials: StoredCredentials;
81
+ path: string;
82
+ }>;
83
+ /** The fields `whoami` shows. */
84
+ export interface Actor {
85
+ kind: string;
86
+ userID: string;
87
+ name: string;
88
+ scopes: string[];
89
+ }
90
+ export interface WhoamiResult {
91
+ actor: Actor;
92
+ endpoint: string;
93
+ /** `token`: UNFZ_API_TOKEN; `login`: the stored login at `path`. */
94
+ source: "token" | "login";
95
+ path?: string;
96
+ }
97
+ /** Who the SDK acts as here: `UNFZ_API_TOKEN` when set, else the stored login (refreshed as needed). */
98
+ export declare function whoami(options?: {
99
+ env?: Env;
100
+ fetch?: Fetch;
101
+ }): Promise<WhoamiResult>;
102
+ export interface LogoutResult {
103
+ /** Whether there was a login to remove. */
104
+ signedOut: boolean;
105
+ issuer?: string;
106
+ /** Whether the server revoked the tokens. */
107
+ revoked: boolean;
108
+ /** Whether the server offers revocation (RFC 7009). */
109
+ revocationSupported: boolean;
110
+ }
111
+ /**
112
+ * Revokes the stored tokens when the server advertises revocation, then
113
+ * deletes the login. The endpoint is read from the server's metadata again,
114
+ * so one the server gained since the login is used.
115
+ */
116
+ export declare function logout(options?: {
117
+ env?: Env;
118
+ fetch?: Fetch;
119
+ }): Promise<LogoutResult>;
120
+ export declare function accountName(credentials: StoredCredentials): string;
121
+ /**
122
+ * Whether a browser can be expected here. Over SSH, or on Linux without a
123
+ * display, the login prints the URL instead (and takes the pasted answer).
124
+ */
125
+ export declare function canOpenBrowser(env: Env, platform?: NodeJS.Platform): boolean;
126
+ /** The command that opens `url` — `$BROWSER`, `open`, `xdg-open` or the Windows URL handler — as argv, never a shell line. */
127
+ export declare function browserCommand(url: string, env: Env, platform?: NodeJS.Platform): string[];
128
+ /** Starts the browser on `url`. Resolves to whether it could be started. */
129
+ export declare function openBrowser(url: string, env?: Env, platform?: NodeJS.Platform): Promise<boolean>;