@fly.io/sdk 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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/dist/app.d.ts +181 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +212 -0
  5. package/dist/client.d.ts +42 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +200 -0
  8. package/dist/errors.d.ts +48 -0
  9. package/dist/errors.d.ts.map +1 -0
  10. package/dist/errors.js +85 -0
  11. package/dist/index.d.ts +28 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +18 -0
  14. package/dist/machine.d.ts +319 -0
  15. package/dist/machine.d.ts.map +1 -0
  16. package/dist/machine.js +249 -0
  17. package/dist/network.d.ts +45 -0
  18. package/dist/network.d.ts.map +1 -0
  19. package/dist/network.js +44 -0
  20. package/dist/organization.d.ts +20 -0
  21. package/dist/organization.d.ts.map +1 -0
  22. package/dist/organization.js +22 -0
  23. package/dist/regions.d.ts +35 -0
  24. package/dist/regions.d.ts.map +1 -0
  25. package/dist/regions.js +53 -0
  26. package/dist/secret.d.ts +55 -0
  27. package/dist/secret.d.ts.map +1 -0
  28. package/dist/secret.js +53 -0
  29. package/dist/token.d.ts +14 -0
  30. package/dist/token.d.ts.map +1 -0
  31. package/dist/token.js +16 -0
  32. package/dist/types.d.ts +937 -0
  33. package/dist/types.d.ts.map +1 -0
  34. package/dist/types.js +40 -0
  35. package/dist/volume.d.ts +72 -0
  36. package/dist/volume.d.ts.map +1 -0
  37. package/dist/volume.js +45 -0
  38. package/package.json +54 -0
  39. package/src/app.ts +462 -0
  40. package/src/client.ts +262 -0
  41. package/src/errors.ts +135 -0
  42. package/src/index.ts +141 -0
  43. package/src/machine.ts +644 -0
  44. package/src/network.ts +87 -0
  45. package/src/organization.ts +43 -0
  46. package/src/regions.ts +94 -0
  47. package/src/secret.ts +101 -0
  48. package/src/token.ts +29 -0
  49. package/src/types.ts +1072 -0
  50. package/src/volume.ts +124 -0
package/src/machine.ts ADDED
@@ -0,0 +1,644 @@
1
+ // Machine management for Fly Machines REST API.
2
+ // Vendored from supabase/fly-admin with added exec, releaseLease, and metadata methods.
3
+
4
+ import { Client } from './client.ts'
5
+ import type { FlyResult } from './errors.ts'
6
+ import {
7
+ ApiMachineConfig,
8
+ ApiMachineInit,
9
+ ApiMachineService,
10
+ ApiMachineMount,
11
+ ApiMachinePort,
12
+ ApiMachineCheck,
13
+ ApiMachineRestart,
14
+ ApiMachineGuest,
15
+ CheckStatus as ApiCheckStatus,
16
+ CreateMachineRequest as ApiCreateMachineRequest,
17
+ ImageRef as ApiImageRef,
18
+ Machine as ApiMachine,
19
+ MachineExecRequest as ApiMachineExecRequest,
20
+ MachineExecResponse as ApiMachineExecResponse,
21
+ StateEnum as ApiMachineState,
22
+ SignalRequestSignalEnum as ApiMachineSignal,
23
+ OrgMachine,
24
+ OrgMachinesResponse as ApiOrgMachinesResponse,
25
+ WaitMachineResponse as ApiWaitMachineResponse,
26
+ MemoryResponse as ApiMemoryResponse,
27
+ SetMemoryLimitRequest as ApiSetMemoryLimitRequest,
28
+ ReclaimMemoryRequest as ApiReclaimMemoryRequest,
29
+ ReclaimMemoryResponse as ApiReclaimMemoryResponse,
30
+ Lease as ApiLease,
31
+ ApiDuration,
32
+ MetadataValueResponse,
33
+ UpdateMetadataRequestBody,
34
+ UpsertMetadataKeyRequest,
35
+ } from './types.ts'
36
+
37
+ export interface MachineConfig extends ApiMachineConfig {
38
+ image: string
39
+ schedule?: 'hourly' | 'daily' | 'weekly' | 'monthly'
40
+ }
41
+
42
+ export type ListMachineRequest =
43
+ | string
44
+ | {
45
+ app_name: string
46
+ include_deleted?: boolean
47
+ region?: string
48
+ state?: string
49
+ summary?: boolean
50
+ }
51
+
52
+ export interface CreateMachineRequest extends ApiCreateMachineRequest {
53
+ app_name: string
54
+ config: MachineConfig
55
+ }
56
+
57
+ interface BaseEvent {
58
+ id: string
59
+ type: string
60
+ status: string
61
+ source: 'flyd' | 'user'
62
+ timestamp: number
63
+ }
64
+
65
+ interface StartEvent extends BaseEvent {
66
+ type: 'start'
67
+ status: 'started' | 'starting'
68
+ }
69
+
70
+ interface LaunchEvent extends BaseEvent {
71
+ type: 'launch'
72
+ status: 'created'
73
+ source: 'user'
74
+ }
75
+
76
+ interface RestartEvent extends BaseEvent {
77
+ type: 'restart'
78
+ status: 'starting' | 'stopping'
79
+ source: 'flyd' | 'user'
80
+ }
81
+
82
+ interface ExitEvent extends BaseEvent {
83
+ type: 'exit'
84
+ status: 'stopped'
85
+ source: 'flyd'
86
+ request: {
87
+ exit_event: {
88
+ requested_stop: boolean
89
+ restarting: boolean
90
+ guest_exit_code: number
91
+ guest_signal: number
92
+ guest_error: string
93
+ exit_code: number
94
+ signal: number
95
+ error: string
96
+ oom_killed: boolean
97
+ exited_at: string
98
+ }
99
+ restart_count: number
100
+ }
101
+ }
102
+
103
+ export type MachineEvent = LaunchEvent | StartEvent | RestartEvent | ExitEvent
104
+
105
+ export enum MachineState {
106
+ Created = 'created',
107
+ Starting = 'starting',
108
+ Started = 'started',
109
+ Stopping = 'stopping',
110
+ Stopped = 'stopped',
111
+ Suspended = 'suspended',
112
+ Replacing = 'replacing',
113
+ Destroying = 'destroying',
114
+ Destroyed = 'destroyed',
115
+ Failed = 'failed',
116
+ }
117
+
118
+ interface MachineMount extends ApiMachineMount {
119
+ encrypted: boolean
120
+ path: string
121
+ size_gb: number
122
+ volume: string
123
+ name: string
124
+ }
125
+
126
+ export enum ConnectionHandler {
127
+ TLS = 'tls',
128
+ PG_TLS = 'pg_tls',
129
+ HTTP = 'http',
130
+ PROXY_PROTO = 'proxy_proto',
131
+ }
132
+
133
+ interface MachinePort extends ApiMachinePort {
134
+ port: number
135
+ handlers?: ConnectionHandler[]
136
+ }
137
+
138
+ interface MachineService extends ApiMachineService {
139
+ protocol: 'tcp' | 'udp'
140
+ internal_port: number
141
+ ports: MachinePort[]
142
+ concurrency?: {
143
+ type: 'connections' | 'requests'
144
+ soft_limit: number
145
+ hard_limit: number
146
+ }
147
+ }
148
+
149
+ interface MachineCheck extends ApiMachineCheck {
150
+ type: 'tcp' | 'http'
151
+ port: number
152
+ interval: string
153
+ timeout: string
154
+ }
155
+
156
+ interface MachineGuest extends ApiMachineGuest {
157
+ cpu_kind: 'shared' | 'performance'
158
+ cpus: number
159
+ memory_mb: number
160
+ }
161
+
162
+ interface CheckStatus extends ApiCheckStatus {
163
+ name: string
164
+ status: 'passing' | 'warning' | 'critical'
165
+ output: string
166
+ updated_at: string
167
+ }
168
+
169
+ interface MachineImageRef extends Omit<ApiImageRef, 'labels'> {
170
+ registry: string
171
+ repository: string
172
+ tag: string
173
+ digest: string
174
+ labels: Record<string, string> | null
175
+ }
176
+
177
+ export interface MachineResponse extends Omit<ApiMachine, 'image_ref'> {
178
+ id: string
179
+ name: string
180
+ state: MachineState
181
+ region: string
182
+ instance_id: string
183
+ private_ip: string
184
+ host_status?: 'ok' | 'unknown' | 'unreachable'
185
+ incomplete_config?: ApiMachineConfig
186
+ nonce?: string
187
+ config: {
188
+ env: Record<string, string>
189
+ init: ApiMachineInit
190
+ mounts: MachineMount[]
191
+ services: MachineService[]
192
+ checks: Record<string, MachineCheck>
193
+ restart: ApiMachineRestart
194
+ guest: MachineGuest
195
+ size: 'shared-cpu-1x' | 'shared-cpu-2x' | 'shared-cpu-4x'
196
+ } & MachineConfig
197
+ image_ref: MachineImageRef
198
+ created_at: string
199
+ updated_at: string
200
+ events: MachineEvent[]
201
+ checks: CheckStatus[]
202
+ }
203
+
204
+ export interface GetMachineRequest {
205
+ app_name: string
206
+ machine_id: string
207
+ }
208
+
209
+ interface OkResponse {
210
+ ok: boolean
211
+ }
212
+
213
+ export interface DeleteMachineRequest extends GetMachineRequest {
214
+ force?: boolean
215
+ }
216
+
217
+ export interface RestartMachineRequest extends GetMachineRequest {
218
+ timeout?: string
219
+ signal?: string
220
+ }
221
+
222
+ export interface SignalMachineRequest extends GetMachineRequest {
223
+ signal: ApiMachineSignal
224
+ }
225
+
226
+ export interface StopMachineRequest extends GetMachineRequest {
227
+ signal?: ApiMachineSignal
228
+ timeout?: ApiDuration
229
+ }
230
+
231
+ export type StartMachineRequest = GetMachineRequest
232
+
233
+ export interface UpdateMachineRequest extends GetMachineRequest {
234
+ config: MachineConfig
235
+ }
236
+
237
+ export type ListEventsRequest = GetMachineRequest
238
+ export type ListVersionsRequest = GetMachineRequest
239
+
240
+ export interface ListProcessesRequest extends GetMachineRequest {
241
+ sort_by?: string
242
+ order?: string
243
+ }
244
+
245
+ export interface ProcessResponse {
246
+ command: string
247
+ cpu: number
248
+ directory: string
249
+ listen_sockets: { address: string; proto: string }[]
250
+ pid: number
251
+ rss: number
252
+ rtime: number
253
+ stime: number
254
+ }
255
+
256
+ export interface WaitMachineRequest extends GetMachineRequest {
257
+ instance_id?: string
258
+ timeout?: number
259
+ state?: ApiMachineState
260
+ version?: string
261
+ from_event_id?: string
262
+ }
263
+
264
+ export interface WaitMachineStopRequest extends WaitMachineRequest {
265
+ instance_id: string
266
+ state?: typeof ApiMachineState.Stopped | typeof ApiMachineState.Suspended
267
+ }
268
+
269
+ export interface MachineVersionResponse {
270
+ user_config: MachineResponse
271
+ version: string
272
+ }
273
+
274
+ export type GetLeaseRequest = GetMachineRequest
275
+
276
+ export interface LeaseResponse extends ApiLease {
277
+ description: string
278
+ expires_at: number
279
+ nonce: string
280
+ owner: string
281
+ version?: string
282
+ }
283
+
284
+ export interface AcquireLeaseRequest extends GetLeaseRequest {
285
+ description?: string
286
+ ttl?: number
287
+ }
288
+
289
+ export interface ReleaseLeaseRequest extends GetLeaseRequest {
290
+ nonce: string
291
+ }
292
+
293
+ export type CordonMachineRequest = GetMachineRequest
294
+ export type UncordonMachineRequest = GetMachineRequest
295
+
296
+ // --- Exec types ---
297
+
298
+ export interface ExecMachineRequest extends GetMachineRequest {
299
+ command: string[]
300
+ stdin?: string
301
+ timeout?: number
302
+ container?: string
303
+ }
304
+
305
+ export interface ExecMachineResponse {
306
+ exit_code: number
307
+ exit_signal: number
308
+ stderr: string
309
+ stdout: string
310
+ }
311
+
312
+ // --- Metadata types ---
313
+
314
+ export type GetMetadataRequest = GetMachineRequest
315
+
316
+ export interface UpdateMetadataRequest extends GetMachineRequest {
317
+ request: UpdateMetadataRequestBody
318
+ }
319
+
320
+ export interface GetMetadataPropertyRequest extends GetMachineRequest {
321
+ key: string
322
+ }
323
+
324
+ export interface SetMetadataPropertyRequest extends GetMachineRequest {
325
+ key: string
326
+ request: UpsertMetadataKeyRequest
327
+ }
328
+
329
+ export interface DeleteMetadataPropertyRequest extends GetMachineRequest {
330
+ key: string
331
+ }
332
+
333
+ // --- Memory types ---
334
+
335
+ export interface MachineMemoryResponse extends ApiMemoryResponse {
336
+ available_mb: number
337
+ limit_mb: number
338
+ }
339
+
340
+ export interface UpdateMemoryRequest extends GetMachineRequest {
341
+ limit_mb: number
342
+ }
343
+
344
+ export interface ReclaimMemoryMachineRequest extends GetMachineRequest {
345
+ amount_mb?: number
346
+ }
347
+
348
+ export interface ReclaimMemoryResponse extends ApiReclaimMemoryResponse {
349
+ actual_mb: number
350
+ }
351
+
352
+ // --- Org-level types ---
353
+
354
+ export interface ListOrgMachinesRequest {
355
+ org_slug: string
356
+ include_deleted?: boolean
357
+ region?: string
358
+ state?: string
359
+ updated_after?: string
360
+ cursor?: string
361
+ limit?: number
362
+ }
363
+
364
+ export interface OrgMachinesResponse extends ApiOrgMachinesResponse {
365
+ machines: OrgMachine[]
366
+ last_machine_id?: string
367
+ last_updated_at?: string
368
+ next_cursor?: string
369
+ }
370
+
371
+ export interface ListEventsOptions extends GetMachineRequest {
372
+ limit?: number
373
+ }
374
+
375
+ export class Machine {
376
+ private client: Client
377
+
378
+ constructor(client: Client) {
379
+ this.client = client
380
+ }
381
+
382
+ // --- Core CRUD ---
383
+
384
+ async listMachines(app_name: ListMachineRequest): Promise<FlyResult<MachineResponse[]>> {
385
+ let path: string
386
+ if (typeof app_name === 'string') {
387
+ path = `apps/${app_name}/machines`
388
+ } else {
389
+ const { app_name: appId, ...params } = app_name
390
+ path = `apps/${appId}/machines`
391
+ const queryParams: Record<string, string> = {}
392
+ if (params.include_deleted !== undefined) {
393
+ queryParams.include_deleted = String(params.include_deleted)
394
+ }
395
+ if (params.region) {
396
+ queryParams.region = params.region
397
+ }
398
+ if (params.state) {
399
+ queryParams.state = params.state
400
+ }
401
+ if (params.summary !== undefined) {
402
+ queryParams.summary = String(params.summary)
403
+ }
404
+ const query = new URLSearchParams(queryParams).toString()
405
+ if (query) {
406
+ path += `?${query}`
407
+ }
408
+ }
409
+ return await this.client.restOrThrow(path)
410
+ }
411
+
412
+ async getMachine(payload: GetMachineRequest): Promise<FlyResult<MachineResponse>> {
413
+ const { app_name, machine_id } = payload
414
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}`)
415
+ }
416
+
417
+ async createMachine(payload: CreateMachineRequest): Promise<FlyResult<MachineResponse>> {
418
+ const { app_name, ...body } = payload
419
+ return await this.client.restOrThrow(`apps/${app_name}/machines`, 'POST', body)
420
+ }
421
+
422
+ async updateMachine(payload: UpdateMachineRequest): Promise<FlyResult<MachineResponse>> {
423
+ const { app_name, machine_id, ...body } = payload
424
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}`, 'POST', body)
425
+ }
426
+
427
+ async deleteMachine(payload: DeleteMachineRequest): Promise<FlyResult<OkResponse>> {
428
+ const { app_name, machine_id, force } = payload
429
+ const query = force ? '?force=true' : ''
430
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}${query}`, 'DELETE')
431
+ }
432
+
433
+ // --- Lifecycle control ---
434
+
435
+ async startMachine(payload: StartMachineRequest): Promise<FlyResult<OkResponse>> {
436
+ const { app_name, machine_id } = payload
437
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/start`, 'POST')
438
+ }
439
+
440
+ async stopMachine(payload: StopMachineRequest): Promise<FlyResult<OkResponse>> {
441
+ const { app_name, machine_id, ...body } = payload
442
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/stop`, 'POST', {
443
+ signal: ApiMachineSignal.SIGTERM,
444
+ ...body,
445
+ })
446
+ }
447
+
448
+ async restartMachine(payload: RestartMachineRequest): Promise<FlyResult<OkResponse>> {
449
+ const { app_name, machine_id, ...params } = payload
450
+ let path = `apps/${app_name}/machines/${machine_id}/restart`
451
+ const queryParams: Record<string, string> = {}
452
+ if (params.timeout) {
453
+ queryParams.timeout = params.timeout
454
+ }
455
+ if (params.signal) {
456
+ queryParams.signal = params.signal
457
+ }
458
+ const query = new URLSearchParams(queryParams).toString()
459
+ if (query) {
460
+ path += `?${query}`
461
+ }
462
+ return await this.client.restOrThrow(path, 'POST')
463
+ }
464
+
465
+ async signalMachine(payload: SignalMachineRequest): Promise<FlyResult<OkResponse>> {
466
+ const { app_name, machine_id, ...body } = payload
467
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/signal`, 'POST', body)
468
+ }
469
+
470
+ async suspendMachine(payload: GetMachineRequest): Promise<FlyResult<OkResponse>> {
471
+ const { app_name, machine_id } = payload
472
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/suspend`, 'POST')
473
+ }
474
+
475
+ // --- Memory ---
476
+
477
+ async getMemory(payload: GetMachineRequest): Promise<FlyResult<MachineMemoryResponse>> {
478
+ const { app_name, machine_id } = payload
479
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/memory`)
480
+ }
481
+
482
+ async setMemoryLimit(payload: UpdateMemoryRequest): Promise<FlyResult<MachineMemoryResponse>> {
483
+ const { app_name, machine_id, ...body } = payload
484
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/memory`, 'PUT', body)
485
+ }
486
+
487
+ /** @deprecated use setMemoryLimit instead */
488
+ async updateMemory(payload: UpdateMemoryRequest): Promise<FlyResult<MachineMemoryResponse>> {
489
+ return this.setMemoryLimit(payload)
490
+ }
491
+
492
+ async reclaimMemory(payload: ReclaimMemoryMachineRequest): Promise<FlyResult<ReclaimMemoryResponse>> {
493
+ const { app_name, machine_id, ...body } = payload
494
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/memory/reclaim`, 'POST', body)
495
+ }
496
+
497
+ // --- Monitoring ---
498
+
499
+ async listEvents(payload: ListEventsOptions): Promise<FlyResult<MachineResponse['events']>> {
500
+ const { app_name, machine_id, limit } = payload
501
+ const query = limit !== undefined ? `?limit=${String(limit)}` : ''
502
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/events${query}`)
503
+ }
504
+
505
+ async listVersions(payload: ListVersionsRequest): Promise<FlyResult<MachineVersionResponse[]>> {
506
+ const { app_name, machine_id } = payload
507
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/versions`)
508
+ }
509
+
510
+ async listProcesses(payload: ListProcessesRequest): Promise<FlyResult<ProcessResponse[]>> {
511
+ const { app_name, machine_id, ...params } = payload
512
+ let path = `apps/${app_name}/machines/${machine_id}/ps`
513
+ const query = new URLSearchParams(params).toString()
514
+ if (query) {
515
+ path += `?${query}`
516
+ }
517
+ return await this.client.restOrThrow(path)
518
+ }
519
+
520
+ async waitMachine(payload: WaitMachineRequest): Promise<FlyResult<ApiWaitMachineResponse>> {
521
+ const { app_name, machine_id, ...params } = payload
522
+ let path = `apps/${app_name}/machines/${machine_id}/wait`
523
+ const queryParams: Record<string, string> = {}
524
+ if (params.instance_id) {
525
+ queryParams.instance_id = params.instance_id
526
+ }
527
+ if (params.timeout !== undefined) {
528
+ queryParams.timeout = String(params.timeout)
529
+ }
530
+ if (params.state) {
531
+ queryParams.state = params.state
532
+ }
533
+ if (params.version) {
534
+ queryParams.version = params.version
535
+ }
536
+ if (params.from_event_id) {
537
+ queryParams.from_event_id = params.from_event_id
538
+ }
539
+ const query = new URLSearchParams(queryParams).toString()
540
+ if (query) {
541
+ path += `?${query}`
542
+ }
543
+ return await this.client.restOrThrow(path)
544
+ }
545
+
546
+ // --- Cordoning ---
547
+
548
+ async cordonMachine(payload: CordonMachineRequest): Promise<FlyResult<OkResponse>> {
549
+ const { app_name, machine_id } = payload
550
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/cordon`, 'POST')
551
+ }
552
+
553
+ async uncordonMachine(payload: UncordonMachineRequest): Promise<FlyResult<OkResponse>> {
554
+ const { app_name, machine_id } = payload
555
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/uncordon`, 'POST')
556
+ }
557
+
558
+ // --- Leases ---
559
+
560
+ async getLease(payload: GetLeaseRequest): Promise<FlyResult<LeaseResponse>> {
561
+ const { app_name, machine_id } = payload
562
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/lease`)
563
+ }
564
+
565
+ async acquireLease(payload: AcquireLeaseRequest): Promise<FlyResult<LeaseResponse>> {
566
+ const { app_name, machine_id, ...body } = payload
567
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/lease`, 'POST', body)
568
+ }
569
+
570
+ async releaseLease(payload: ReleaseLeaseRequest): Promise<FlyResult<void>> {
571
+ const { app_name, machine_id, nonce } = payload
572
+ return await this.client.restOrThrow(
573
+ `apps/${app_name}/machines/${machine_id}/lease`,
574
+ 'DELETE',
575
+ undefined,
576
+ { 'fly-machine-lease-nonce': nonce },
577
+ )
578
+ }
579
+
580
+ // --- Exec ---
581
+
582
+ async execMachine(payload: ExecMachineRequest): Promise<FlyResult<ExecMachineResponse>> {
583
+ const { app_name, machine_id, ...body } = payload
584
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/exec`, 'POST', body)
585
+ }
586
+
587
+ // --- Metadata ---
588
+
589
+ async getMetadata(payload: GetMetadataRequest): Promise<FlyResult<Record<string, string>>> {
590
+ const { app_name, machine_id } = payload
591
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/metadata`)
592
+ }
593
+
594
+ async updateMetadata(payload: UpdateMetadataRequest): Promise<FlyResult<void>> {
595
+ const { app_name, machine_id, request } = payload
596
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/metadata`, 'PUT', request)
597
+ }
598
+
599
+ async getMetadataProperty(payload: GetMetadataPropertyRequest): Promise<FlyResult<MetadataValueResponse>> {
600
+ const { app_name, machine_id, key } = payload
601
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/metadata/${key}`)
602
+ }
603
+
604
+ async setMetadataProperty(payload: SetMetadataPropertyRequest): Promise<FlyResult<void>> {
605
+ const { app_name, machine_id, key, request } = payload
606
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/metadata/${key}`, 'POST', request)
607
+ }
608
+
609
+ async deleteMetadataProperty(payload: DeleteMetadataPropertyRequest): Promise<FlyResult<void>> {
610
+ const { app_name, machine_id, key } = payload
611
+ return await this.client.restOrThrow(`apps/${app_name}/machines/${machine_id}/metadata/${key}`, 'DELETE')
612
+ }
613
+
614
+ // --- Org-level ---
615
+
616
+ async listOrgMachines(payload: ListOrgMachinesRequest): Promise<FlyResult<OrgMachinesResponse>> {
617
+ const { org_slug, ...params } = payload
618
+ let path = `orgs/${org_slug}/machines`
619
+ const queryParams: Record<string, string> = {}
620
+ if (params.include_deleted !== undefined) {
621
+ queryParams.include_deleted = String(params.include_deleted)
622
+ }
623
+ if (params.region) {
624
+ queryParams.region = params.region
625
+ }
626
+ if (params.state) {
627
+ queryParams.state = params.state
628
+ }
629
+ if (params.updated_after) {
630
+ queryParams.updated_after = params.updated_after
631
+ }
632
+ if (params.cursor) {
633
+ queryParams.cursor = params.cursor
634
+ }
635
+ if (params.limit !== undefined) {
636
+ queryParams.limit = String(params.limit)
637
+ }
638
+ const query = new URLSearchParams(queryParams).toString()
639
+ if (query) {
640
+ path += `?${query}`
641
+ }
642
+ return await this.client.restOrThrow(path)
643
+ }
644
+ }