@appforge-ci/core 0.1.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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/dist/agent-readiness.d.ts +163 -0
  3. package/dist/agent-readiness.d.ts.map +1 -0
  4. package/dist/agent-readiness.js +179 -0
  5. package/dist/agent-readiness.js.map +1 -0
  6. package/dist/agent-readiness.test.d.ts +2 -0
  7. package/dist/agent-readiness.test.d.ts.map +1 -0
  8. package/dist/agent-readiness.test.js +177 -0
  9. package/dist/agent-readiness.test.js.map +1 -0
  10. package/dist/api-client.d.ts +529 -0
  11. package/dist/api-client.d.ts.map +1 -0
  12. package/dist/api-client.js +551 -0
  13. package/dist/api-client.js.map +1 -0
  14. package/dist/api-client.test.d.ts +2 -0
  15. package/dist/api-client.test.d.ts.map +1 -0
  16. package/dist/api-client.test.js +305 -0
  17. package/dist/api-client.test.js.map +1 -0
  18. package/dist/build-cost.test.d.ts +2 -0
  19. package/dist/build-cost.test.d.ts.map +1 -0
  20. package/dist/build-cost.test.js +21 -0
  21. package/dist/build-cost.test.js.map +1 -0
  22. package/dist/index.d.ts +8 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +8 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/ota-artifact.d.ts +41 -0
  27. package/dist/ota-artifact.d.ts.map +1 -0
  28. package/dist/ota-artifact.js +43 -0
  29. package/dist/ota-artifact.js.map +1 -0
  30. package/dist/ota-artifact.test.d.ts +2 -0
  31. package/dist/ota-artifact.test.d.ts.map +1 -0
  32. package/dist/ota-artifact.test.js +44 -0
  33. package/dist/ota-artifact.test.js.map +1 -0
  34. package/dist/ota-bundle-hash.d.ts +38 -0
  35. package/dist/ota-bundle-hash.d.ts.map +1 -0
  36. package/dist/ota-bundle-hash.js +40 -0
  37. package/dist/ota-bundle-hash.js.map +1 -0
  38. package/dist/ota-bundle-hash.test.d.ts +2 -0
  39. package/dist/ota-bundle-hash.test.d.ts.map +1 -0
  40. package/dist/ota-bundle-hash.test.js +28 -0
  41. package/dist/ota-bundle-hash.test.js.map +1 -0
  42. package/dist/ota-rollout.d.ts +38 -0
  43. package/dist/ota-rollout.d.ts.map +1 -0
  44. package/dist/ota-rollout.js +53 -0
  45. package/dist/ota-rollout.js.map +1 -0
  46. package/dist/ota-rollout.test.d.ts +2 -0
  47. package/dist/ota-rollout.test.d.ts.map +1 -0
  48. package/dist/ota-rollout.test.js +48 -0
  49. package/dist/ota-rollout.test.js.map +1 -0
  50. package/dist/schemas.d.ts +776 -0
  51. package/dist/schemas.d.ts.map +1 -0
  52. package/dist/schemas.js +538 -0
  53. package/dist/schemas.js.map +1 -0
  54. package/dist/token-packs.test.d.ts +2 -0
  55. package/dist/token-packs.test.d.ts.map +1 -0
  56. package/dist/token-packs.test.js +34 -0
  57. package/dist/token-packs.test.js.map +1 -0
  58. package/dist/types.d.ts +445 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +80 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +35 -0
@@ -0,0 +1,529 @@
1
+ import type { AgentCommand, AgentInfo, ApiTokenInfo, App, BillingMode, BillingUsage, Build, BuildFailureExplanation, LedgerEntry, MonthlyInvoice, Org, OtaChannel, OtaManifest, OtaRelease, SmokeTestVerdict, TokenPack, User, VncSession } from "./types.js";
2
+ export interface ApiClientOptions {
3
+ baseUrl: string;
4
+ /** Bearer token — either a user session JWT or a CLI/agent API token. */
5
+ token?: string;
6
+ /**
7
+ * Fleet management (listAgents/createEnrollmentToken/sendAgentCommand)
8
+ * is served by a separately-deployed admin Worker, not the customer-
9
+ * facing API — see apps/admin-api. Falls back to `baseUrl` if unset,
10
+ * which only matters for callers that never touch those three methods.
11
+ */
12
+ adminApiUrl?: string;
13
+ /** Test seam only — same "optional, defaults to the real thing" shape
14
+ * `packages/admin-cli`'s `waitForCommandResolution`/`packages/cli`'s
15
+ * `followBuildLogs` already use for their own injectable dependencies.
16
+ * Every real caller (dashboard, CLI, agent) omits this and gets the
17
+ * real global `fetch`. */
18
+ fetchImpl?: typeof fetch;
19
+ /** Test seam only — production callers always get the real
20
+ * `DEFAULT_REQUEST_TIMEOUT_MS`. See that constant's own docblock. */
21
+ requestTimeoutMs?: number;
22
+ }
23
+ /**
24
+ * Every `ApiClient` call is a small JSON request/response — no file
25
+ * upload/download is ever routed through this client (build artifacts and
26
+ * OTA bundles go straight to/from R2 via a presigned URL the caller fetches
27
+ * separately) — but a handful of routes (`explainBuildFailure`,
28
+ * `analyzeSmokeTest`, `askDocsChat`, `generateAppforgeConfig`) proxy to
29
+ * Anthropic server-side and can legitimately take tens of seconds for a
30
+ * real completion, well past what a plain CRUD call needs. 60s is
31
+ * generous enough to cover the slowest of those with room to spare, while
32
+ * still being a real ceiling: without one, a connection that stalls after
33
+ * opening (a network partition, a proxy holding the connection open
34
+ * without sending further bytes, a hung Worker instance) left every
35
+ * caller's `fetch` promise pending forever — same shape as `packages/
36
+ * agent/src/lib/api.ts`'s already-fixed `AgentApi.request`, but for the
37
+ * single shared client every dashboard page, CLI command, and admin-cli
38
+ * command talks to the control plane through. */
39
+ export declare const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
40
+ export declare class ApiError extends Error {
41
+ status: number;
42
+ body: unknown;
43
+ constructor(status: number, body: unknown);
44
+ }
45
+ /**
46
+ * Shared "what should the user see" extraction for a caught error from
47
+ * any `ApiClient` call. `ApiError` extends `Error`, so a naive
48
+ * `err instanceof Error ? err.message : fallback` always matches an
49
+ * `ApiError` too and returns *this class's own* constructor string —
50
+ * `API error ${status}: ${JSON.stringify(body)}`, meant for logs/
51
+ * debugging — instead of the server's actual user-facing text at
52
+ * `body.error`. This was independently found and fixed the same way in
53
+ * `Login.tsx`/`Signup.tsx`/`Device.tsx`/`VerifyEmail.tsx` (dashboard)
54
+ * and `VncViewer.tsx`'s own `vncViewerErrorMessage` before this shared
55
+ * helper existed; new callers (both CLIs' top-level handlers first, per
56
+ * ROADMAP.md) should use this instead of repeating the same extraction
57
+ * inline.
58
+ */
59
+ export declare function apiErrorMessage(err: unknown, fallback: string): string;
60
+ /**
61
+ * Small typed fetch wrapper shared by the CLI and the dashboard so both
62
+ * talk to the control-plane API through the same request/response shapes.
63
+ */
64
+ export declare class ApiClient {
65
+ private opts;
66
+ constructor(opts: ApiClientOptions);
67
+ private request;
68
+ private adminRequest;
69
+ /**
70
+ * `twoFactor` is only needed on a second call, after a first call
71
+ * without it throws `ApiError(401, { requiresTotp: true })` — see
72
+ * apps/api/src/routes/auth.ts's login handler. `recoveryCode` is a
73
+ * lost-authenticator alternate to `totpCode`, never both at once.
74
+ */
75
+ login(email: string, password: string, twoFactor?: {
76
+ totpCode?: string;
77
+ recoveryCode?: string;
78
+ }): Promise<{
79
+ token: string;
80
+ user: User;
81
+ }>;
82
+ signup(email: string, password: string, name: string | undefined, orgName: string): Promise<{
83
+ token: string;
84
+ user: User;
85
+ org: Org;
86
+ }>;
87
+ me(): Promise<{
88
+ user: User;
89
+ orgs: Org[];
90
+ }>;
91
+ /**
92
+ * Redeems the token from the signup verification email's link
93
+ * (`apps/api/src/lib/email-verification.ts`'s `verifyUrl`). No auth of
94
+ * its own — the route this hits (`POST /auth/verify-email`) doesn't
95
+ * require a session, since whoever clicked the link may not be logged
96
+ * in on this browser at all. Was previously unreachable from any
97
+ * client: this method, plus a dashboard route to call it, is the fix.
98
+ */
99
+ verifyEmail(token: string): Promise<{
100
+ ok: true;
101
+ }>;
102
+ /** Requires an existing session — unlike `verifyEmail`, this is only
103
+ * ever offered to an already-logged-in user who hasn't verified yet
104
+ * (see `Security.tsx`). Rate-limited server-side. */
105
+ resendVerification(): Promise<{
106
+ ok: true;
107
+ }>;
108
+ /** Requires re-entering the current password — same reasoning as
109
+ * `disableTwoFactor` below: a stolen session token alone must not be
110
+ * enough to take over the account's own fallback credential.
111
+ * Rate-limited server-side, keyed by user. Also revokes every other
112
+ * live session for the account (a leaked token stops working
113
+ * immediately) — `token` is a freshly-issued replacement for *this*
114
+ * session specifically, so the caller must swap it in (e.g. into
115
+ * `session.token`) or this same request's own session gets logged
116
+ * out by its own success. */
117
+ changePassword(currentPassword: string, newPassword: string): Promise<{
118
+ ok: true;
119
+ token: string;
120
+ }>;
121
+ /** No auth of its own — this is the entry point for someone who can't
122
+ * log in at all. Always resolves the same way regardless of whether
123
+ * the email is actually registered (see the route's own doc
124
+ * comment) — never use the response to decide whether to tell the
125
+ * caller "no account with that email". */
126
+ forgotPassword(email: string): Promise<{
127
+ ok: true;
128
+ }>;
129
+ /** Redeems the token from the forgot-password email's link
130
+ * (`apps/api/src/lib/password-reset.ts`'s `resetUrl`). No auth of its
131
+ * own, same reasoning as `verifyEmail` above. Also revokes every
132
+ * other live session for the account and returns a fresh one, same
133
+ * as `changePassword`/`disableTwoFactor` — a reset is at least as
134
+ * strong proof of ownership as re-entering the current password. */
135
+ resetPassword(token: string, newPassword: string): Promise<{
136
+ ok: true;
137
+ token: string;
138
+ }>;
139
+ /** Starts (or restarts) enrollment — the secret is only ever returned
140
+ * here and from confirmTwoFactor's success, never again afterward. */
141
+ enrollTwoFactor(): Promise<{
142
+ secret: string;
143
+ otpauthUri: string;
144
+ }>;
145
+ /** Redeems the first code from an authenticator app to actually turn
146
+ * 2FA on — `recoveryCodes` is shown exactly once, same as the secret
147
+ * above; the caller is responsible for surfacing it to the user now.
148
+ * Also requires re-entering the account password, same reasoning and
149
+ * requirement as `disableTwoFactor` below: without it, any live
150
+ * session (a stolen JWT, or a CLI/webhook API token, which never
151
+ * expires on its own) was enough to confirm 2FA with an
152
+ * attacker-chosen secret, permanently locking the real account owner
153
+ * out at their next login — see docs/security.md's "2FA (TOTP)" note. */
154
+ confirmTwoFactor(code: string, password: string): Promise<{
155
+ ok: true;
156
+ recoveryCodes: string[];
157
+ }>;
158
+ /** Requires re-entering the account password — see docs/security.md's
159
+ * "2FA (TOTP)" note on why a session token alone isn't enough here.
160
+ * Also revokes every other live session for the account, same
161
+ * reasoning and `token`-swap requirement as `changePassword` above —
162
+ * the JWT this very request authenticated with might be the leaked
163
+ * one 2FA existed to guard against. */
164
+ disableTwoFactor(password: string): Promise<{
165
+ ok: true;
166
+ token: string;
167
+ }>;
168
+ /** Invalidates every existing recovery code and returns a fresh set,
169
+ * shown exactly once like the original set from confirmTwoFactor.
170
+ * Also requires re-entering the account password, same reasoning as
171
+ * `disableTwoFactor` above: without it, a stolen session token alone
172
+ * was enough to silently destroy the real owner's recovery path
173
+ * (this codebase has no account-recovery flow) and hand the
174
+ * attacker a fresh set of recovery codes instead — see
175
+ * docs/security.md's "2FA (TOTP)" note. */
176
+ regenerateRecoveryCodes(password: string): Promise<{
177
+ ok: true;
178
+ recoveryCodes: string[];
179
+ }>;
180
+ /** `appforge-admin login --web`'s device-authorization flow (#5) — the CLI calls this first, no auth of its own yet. */
181
+ startDeviceAuth(): Promise<{
182
+ deviceCode: string;
183
+ userCode: string;
184
+ verificationUrl: string;
185
+ expiresInSeconds: number;
186
+ intervalSeconds: number;
187
+ }>;
188
+ /** Poll with the long deviceCode until status stops being "pending" — same shape as gh/OAuth device flow polling. */
189
+ pollDeviceAuth(deviceCode: string): Promise<{
190
+ status: "pending" | "denied" | "expired";
191
+ } | {
192
+ status: "approved";
193
+ token: string;
194
+ orgId: string;
195
+ orgName: string;
196
+ }>;
197
+ /** Called from the dashboard (already has a user session) with the short, human-typed userCode. */
198
+ approveDeviceAuth(userCode: string): Promise<{
199
+ ok: true;
200
+ orgName: string;
201
+ }>;
202
+ denyDeviceAuth(userCode: string): Promise<{
203
+ ok: true;
204
+ }>;
205
+ /** Drafts an appforge.yaml from real project files — see #8. `files` is path -> file contents for whatever the caller found on disk. */
206
+ generateAppforgeConfig(input: {
207
+ detectedPlatform: "ios" | "android" | "flutter" | "react-native" | null;
208
+ files: Record<string, string>;
209
+ }): Promise<{
210
+ yaml: string;
211
+ }>;
212
+ /** Public, unauthenticated docs Q&A widget (pricing page) — see #10. Resend the whole conversation each call; nothing is kept server-side. */
213
+ askDocsChat(history: {
214
+ role: "user" | "assistant";
215
+ content: string;
216
+ }[]): Promise<{
217
+ answer: string;
218
+ }>;
219
+ createApiToken(orgId: string, label: string): Promise<{
220
+ token: string;
221
+ }>;
222
+ /** Never includes the token value itself or its hash — see
223
+ * `ApiTokenInfo`'s own docblock. */
224
+ listApiTokens(orgId: string, pagination?: {
225
+ limit?: number;
226
+ offset?: number;
227
+ }): Promise<{
228
+ tokens: ApiTokenInfo[];
229
+ }>;
230
+ /** Immediate and permanent — there's no undo once a token is
231
+ * revoked (a fresh one via `createApiToken` is the only way back). */
232
+ revokeApiToken(orgId: string, tokenId: string): Promise<{
233
+ revoked: true;
234
+ tokenId: string;
235
+ }>;
236
+ /** Fixes a typo'd or since-changed org name (e.g. a placeholder used
237
+ * at signup) without any of `updateApp`'s deletion/recreation
238
+ * downsides — there's nothing else to break, since unlike an app's
239
+ * `webhookSecret`, an org's identity has no dependent secret tied to
240
+ * it. `name` is the only updatable field; see `updateOrgSchema`'s own
241
+ * docblock in `packages/core/src/schemas.ts`. */
242
+ updateOrg(orgId: string, input: {
243
+ name?: string;
244
+ buildWebhookUrl?: string | null;
245
+ }): Promise<{
246
+ org: Org;
247
+ }>;
248
+ listApps(orgId: string, pagination?: {
249
+ limit?: number;
250
+ offset?: number;
251
+ }): Promise<{
252
+ apps: App[];
253
+ }>;
254
+ createApp(orgId: string, input: {
255
+ name: string;
256
+ platform: string;
257
+ repoUrl: string;
258
+ defaultBranch: string;
259
+ }): Promise<{
260
+ app: App;
261
+ }>;
262
+ /** A single app's own name/platform/etc. — `listApps` only ever returns a
263
+ * whole org's apps, so a page that already knows just the `appId` (any
264
+ * `/apps/:appId/*` page) needs this rather than fetching every app in
265
+ * the org just to find the one it's showing. */
266
+ getApp(appId: string): Promise<{
267
+ app: App;
268
+ }>;
269
+ /** The one route that actually returns `webhookSecret` — every other
270
+ * app response (`getApp`/`listApps`/`createApp`/`updateApp`)
271
+ * deliberately omits it. This is the value GitHub's webhook settings
272
+ * "Secret" field needs, per `docs/security.md`'s "GitHub webhooks"
273
+ * note; without it there's no way to ever configure a working
274
+ * webhook at all. */
275
+ getAppWebhookSecret(appId: string): Promise<{
276
+ webhookSecret: string;
277
+ }>;
278
+ /** `platform` isn't updatable — see `updateAppSchema`'s own docblock
279
+ * in `packages/core/src/schemas.ts`. */
280
+ updateApp(appId: string, input: {
281
+ name?: string;
282
+ repoUrl?: string;
283
+ defaultBranch?: string;
284
+ }): Promise<{
285
+ app: App;
286
+ }>;
287
+ /** Permanently removes the app and cascades every `Build`/OTA row for
288
+ * it — 409s (a plain `ApiError`) if a build is still queued/leased/
289
+ * running, so an in-flight build never has its `App` row vanish out
290
+ * from under it. */
291
+ deleteApp(appId: string): Promise<{
292
+ deleted: true;
293
+ appId: string;
294
+ }>;
295
+ /** Build-secrets v1 (ROADMAP.md, split off from #322) — sets or
296
+ * overwrites a named secret for this app, injected as an env var
297
+ * under that name on every build. Never returns the value back;
298
+ * see `getAppSecretNames` for why. */
299
+ setAppSecret(appId: string, input: {
300
+ name: string;
301
+ value: string;
302
+ }): Promise<{
303
+ name: string;
304
+ }>;
305
+ /** Names only — this codebase has no route anywhere that returns a
306
+ * secret's decrypted value once it's been set (same discipline
307
+ * `getAppWebhookSecret` deliberately doesn't extend to). */
308
+ getAppSecretNames(appId: string): Promise<{
309
+ names: string[];
310
+ }>;
311
+ deleteAppSecret(appId: string, name: string): Promise<{
312
+ deleted: true;
313
+ name: string;
314
+ }>;
315
+ /** Fleet-secrets v1 (issue #392) — sets or overwrites one of the
316
+ * org's fleet-wide infra secrets (`JWT_SECRET`,
317
+ * `JWT_SECRET_PREVIOUS`, `INTERNAL_SERVICE_TOKEN`; see
318
+ * `FLEET_SECRET_NAMES`). Every Mac mini enrolled in this org picks
319
+ * the new value up on its next heartbeat and re-applies it locally,
320
+ * so this call *is* the rotation — there's no per-machine follow-up
321
+ * step. Never returns the value back, same as `setAppSecret`. */
322
+ setFleetSecret(orgId: string, input: {
323
+ name: string;
324
+ value: string;
325
+ }): Promise<{
326
+ name: string;
327
+ }>;
328
+ /** Names only — as with `getAppSecretNames`, no route anywhere returns
329
+ * a fleet secret's decrypted value to a human-facing client; the only
330
+ * decrypt-and-return path in this codebase is apps/admin-api's
331
+ * `GET /agents/fleet-secrets`, which requires an agent bearer token. */
332
+ getFleetSecretNames(orgId: string): Promise<{
333
+ names: string[];
334
+ }>;
335
+ deleteFleetSecret(orgId: string, name: string): Promise<{
336
+ deleted: true;
337
+ name: string;
338
+ }>;
339
+ listBuilds(appId: string): Promise<{
340
+ builds: Build[];
341
+ }>;
342
+ /** Best-effort suggestions for the trigger-build form's "Workflow"
343
+ * field — see `apps/api/src/lib/appforge-yaml.ts`'s own docblock for
344
+ * why this can legitimately come back empty (private repo, no
345
+ * appforge.yaml on this branch yet, etc.) rather than erroring. */
346
+ listAppWorkflows(appId: string): Promise<{
347
+ workflows: string[];
348
+ }>;
349
+ getBuild(buildId: string): Promise<{
350
+ build: Build;
351
+ }>;
352
+ triggerBuild(input: {
353
+ appId: string;
354
+ workflow: string;
355
+ branch?: string;
356
+ }): Promise<{
357
+ build: Build;
358
+ }>;
359
+ cancelBuild(buildId: string): Promise<{
360
+ build: Build;
361
+ }>;
362
+ listAgents(orgId: string): Promise<{
363
+ agents: AgentInfo[];
364
+ }>;
365
+ createEnrollmentToken(orgId: string): Promise<{
366
+ enrollmentToken: string;
367
+ expiresAt: string;
368
+ }>;
369
+ /** Permanently remove a Mac mini from the fleet. The daemon on the
370
+ * machine itself must be stopped separately — see apps/admin-api's
371
+ * DELETE handler and `appforge-admin agents decommission`. */
372
+ deleteAgent(orgId: string, agentId: string): Promise<{
373
+ deleted: true;
374
+ agentId: string;
375
+ }>;
376
+ /** `scriptName` is only used by RUN_MAINTENANCE_SCRIPT; `targetVersion`
377
+ * only by UPDATE_AGENT (npm version or, for a repo-checkout install, a
378
+ * git ref); `buildId` only by CANCEL_BUILD (which of this agent's
379
+ * possibly-several concurrent builds to kill) — all three are ignored
380
+ * server-side for every other command type. `buildId` was the one
381
+ * missing piece keeping CANCEL_BUILD entirely unreachable from any
382
+ * client despite the rest of the stack (route, schema, DB column,
383
+ * agent handling) already being fully built — see ROADMAP.md. */
384
+ sendAgentCommand(agentId: string, type: string, scriptName?: string, targetVersion?: string, buildId?: string): Promise<{
385
+ command: {
386
+ id: string;
387
+ };
388
+ }>;
389
+ /** Remote-management history for one agent, newest first — how the
390
+ * Fleet page shows whether a DRAIN/REBOOT/... actually landed
391
+ * (`done`/`failed` + the agent's `result` string) instead of leaving
392
+ * the operator guessing after a click. */
393
+ listAgentCommands(agentId: string, limit?: number): Promise<{
394
+ commands: AgentCommand[];
395
+ }>;
396
+ /** VNC "Connect" button, Phase 1c: mints a 5-minute session token plus
397
+ * the `wsUrl` (`apps/device-stream`'s `/vnc` relay, see that Worker's
398
+ * Phase 1b) the dashboard's viewer page dials it against. Called fresh
399
+ * each time the viewer page mounts, same "no pre-fetched token sitting
400
+ * in a URL or router state" shape as `startDeviceTestSession`.
401
+ *
402
+ * `options.requestControl` (Feature 3) asks the server for a session
403
+ * that can also forward mouse/keyboard input, not just watch — sent
404
+ * as `{ mode: "control" }` only when true, so an omitted/false call
405
+ * sends no body at all, unchanged from before this option existed.
406
+ * This is only ever a *request*: the response's own `mode` field
407
+ * ("view" | "control") is what the server actually granted (`403` if
408
+ * control was requested but `Agent.remoteControlEnabled` isn't set —
409
+ * see `apps/admin-api/src/routes/fleet.ts`), and callers must treat
410
+ * that field, never their own request, as authoritative. */
411
+ startVncSession(orgId: string, agentId: string, options?: {
412
+ requestControl?: boolean;
413
+ }): Promise<{
414
+ agentId: string;
415
+ token: string;
416
+ expiresAt: string;
417
+ wsUrl: string;
418
+ mode: "view" | "control";
419
+ }>;
420
+ /** Grants or revokes `Agent.remoteControlEnabled` (Feature 3) — the
421
+ * one and only way that flag changes, mirroring `deleteAgent` above's
422
+ * "dedicated route with its own DB write" shape rather than the
423
+ * AgentCommand queue, since this is a persisted authorization bit
424
+ * `startVncSession` needs to read synchronously, not a directive for
425
+ * the agent daemon to act on. See `appforge-admin agents
426
+ * allow-remote-control` (`packages/admin-cli`) for the CLI surface
427
+ * this same route backs. */
428
+ setAgentRemoteControl(orgId: string, agentId: string, enabled: boolean): Promise<{
429
+ agentId: string;
430
+ remoteControlEnabled: number;
431
+ }>;
432
+ /** The audit trail's read side — who's requested a VNC "Connect"
433
+ * session for this agent and when, newest first. How a "Last VNC
434
+ * session" column reads this (`apps/dashboard/src/pages/Fleet.tsx`),
435
+ * same shape `listAgentCommands` above already established. */
436
+ listVncSessions(orgId: string, agentId: string): Promise<{
437
+ sessions: VncSession[];
438
+ }>;
439
+ getBalance(orgId: string): Promise<{
440
+ tokenBalance: number;
441
+ buildCostTokens: number;
442
+ }>;
443
+ listTokenPacks(): Promise<{
444
+ packs: TokenPack[];
445
+ }>;
446
+ /** Starts an LHV Paytech checkout session for a token top-up — also opportunistically saves a card for MIT monthly billing. */
447
+ createLhvCheckoutSession(orgId: string, packId: string): Promise<{
448
+ url: string;
449
+ }>;
450
+ isLhvConfigured(): Promise<{
451
+ configured: boolean;
452
+ }>;
453
+ listLedger(orgId: string): Promise<{
454
+ entries: LedgerEntry[];
455
+ }>;
456
+ getBillingUsage(orgId: string): Promise<BillingUsage>;
457
+ setBillingMode(orgId: string, mode: BillingMode): Promise<{
458
+ org: Org;
459
+ }>;
460
+ listMonthlyInvoices(orgId: string): Promise<{
461
+ invoices: MonthlyInvoice[];
462
+ }>;
463
+ /** AI triage of a failed build's log — see docs/ai-failure-triage.md.
464
+ * Throws ApiError(501) if ANTHROPIC_API_KEY isn't configured on this
465
+ * deployment; callers should show that as "not available here", not
466
+ * as a generic error. */
467
+ explainBuildFailure(buildId: string): Promise<{
468
+ explanation: BuildFailureExplanation;
469
+ }>;
470
+ /** On-demand re-analysis of every smoke-test screenshot a build produced
471
+ * (#9), one verdict per screenshot in index order — same
472
+ * 501-if-unconfigured contract as explainBuildFailure above. */
473
+ analyzeSmokeTest(buildId: string): Promise<{
474
+ verdicts: SmokeTestVerdict[];
475
+ }>;
476
+ startDeviceTestSession(buildId: string): Promise<{
477
+ sessionId: string;
478
+ wsUrl: string;
479
+ token: string;
480
+ }>;
481
+ /** `appKey` is required — the manifest endpoint has no unauthenticated
482
+ * fallback (see `apps/api/src/routes/ota.ts`'s docblock on it), only
483
+ * `generateOtaAppKey`'s one-time response ever reveals a usable
484
+ * value. This call carries no user session (a mobile app binary has
485
+ * none), so the key travels as a query param rather than the
486
+ * `authorization` header `request()` already reserves for the
487
+ * dashboard/CLI's bearer token. */
488
+ getOtaManifest(appId: string, channel: string, appKey: string, currentHash?: string, installationId?: string): Promise<OtaManifest | null>;
489
+ /** Generates (rotates) this app's OTA manifest key — see
490
+ * `getOtaManifest`. Returned once; the server keeps only its hash. */
491
+ generateOtaAppKey(appId: string): Promise<{
492
+ appKey: string;
493
+ }>;
494
+ listOtaReleases(appId: string, channel?: string, pagination?: {
495
+ limit?: number;
496
+ offset?: number;
497
+ }): Promise<{
498
+ releases: OtaRelease[];
499
+ }>;
500
+ listOtaChannels(appId: string, pagination?: {
501
+ limit?: number;
502
+ offset?: number;
503
+ }): Promise<{
504
+ channels: OtaChannel[];
505
+ }>;
506
+ promoteOtaRelease(appId: string, input: {
507
+ buildId: string;
508
+ channel?: string;
509
+ mandatory?: boolean;
510
+ rollout?: number;
511
+ }): Promise<{
512
+ release: OtaRelease;
513
+ }>;
514
+ /** Progresses an existing release's rollout in place (10% -> 50% ->
515
+ * 100%) instead of re-promoting the same build, which would mint a
516
+ * new release id and reshuffle `isInStagedRollout`'s per-install
517
+ * bucketing — see `updateOtaReleaseRolloutSchema`'s own docblock in
518
+ * `packages/core/src/schemas.ts`. */
519
+ updateOtaReleaseRollout(appId: string, releaseId: string, rollout: number): Promise<{
520
+ release: OtaRelease;
521
+ }>;
522
+ setActiveOtaRelease(appId: string, channel: string, releaseId: string | null): Promise<{
523
+ ok: true;
524
+ }>;
525
+ rollbackOtaChannel(appId: string, channel: string): Promise<{
526
+ release: OtaRelease | null;
527
+ }>;
528
+ }
529
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}