@run-cloud/sdk 0.22.0 → 0.23.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/README.md CHANGED
@@ -245,6 +245,52 @@ const restored = await cloud.snapshots.restore(snap.id);
245
245
  Sandbox fields are returned in both the API's `snake_case` and camelCase
246
246
  (`milli_cpu` and `milliCpu` are both present).
247
247
 
248
+ Read fleet history and per-sandbox resource metrics, or control a desktop-image
249
+ sandbox through its short-lived viewer and computer-use endpoints:
250
+
251
+ ```ts
252
+ const overview = await cloud.overview();
253
+ const history = await cloud.sandboxes.history({ range: "24h" });
254
+ const metrics = await cloud.sandboxes.metrics(sandbox.id, { range: "1h" });
255
+ const desktop = await cloud.sandboxes.desktop(sandbox.id, { viewOnly: true });
256
+ const screenshot = await cloud.sandboxes.computer(sandbox.id, {
257
+ action: "screenshot",
258
+ });
259
+ ```
260
+
261
+ Use `credential()` for a lightweight token/product-scope probe and `account()`
262
+ for the caller's full profile and organization memberships. An API key can
263
+ revoke itself:
264
+
265
+ ```ts
266
+ const scope = await cloud.credential();
267
+ const profile = await cloud.account();
268
+ await cloud.revokeCurrentApiKey();
269
+ ```
270
+
271
+ ## Distributed tracing
272
+
273
+ Every SDK-owned HTTP, multipart, byte-download, SSE, and WebSocket transport
274
+ injects W3C trace context. An active OpenTelemetry context is propagated when
275
+ one exists; otherwise the SDK starts the request with a fresh sampled
276
+ `traceparent`. WebSocket exec carries the same context in both the upgrade
277
+ headers and its first command frame.
278
+
279
+ Applications that already use OpenTelemetry can install their preferred global
280
+ propagator and start a span normally:
281
+
282
+ ```ts
283
+ import { trace } from "@opentelemetry/api";
284
+
285
+ await trace.getTracer("worker").startActiveSpan("provision", async (span) => {
286
+ try {
287
+ await cloud.sandboxes.create({ name: "traceable-job" });
288
+ } finally {
289
+ span.end();
290
+ }
291
+ });
292
+ ```
293
+
248
294
  The client reads `RUN_CLOUD_API_KEY` first, then `RUN_CLOUD_API_TOKEN`. Override
249
295
  the API origin with `RUN_CLOUD_API_URL` or by passing `new Client({ apiUrl })`.
250
296
 
@@ -308,11 +354,31 @@ const result = await cloud.remotion.render({
308
354
  console.log(result.outputFile);
309
355
  ```
310
356
 
311
- `remotionVersion` selects Remotion's matching public, versioned renderer image;
312
- all Remotion packages in a project should use that exact version. You can pass
313
- `image` instead to use a custom compatible runtime. Signed URLs are written to
357
+ `remotionVersion` selects Remotion's matching public runtime image and installs
358
+ that exact renderer during sandbox startup; all Remotion packages in a project
359
+ should use the same version. You can pass `image` instead to use a custom
360
+ runtime that already includes the renderer. Signed URLs are written to
314
361
  a private guest file and are not included in command logs.
315
362
 
363
+ For repeated renders, create a version-pinned snapshot once and persist its ID:
364
+
365
+ ```ts
366
+ const runtime = await cloud.remotion.createRuntimeSnapshot({
367
+ remotionVersion: "4.0.507",
368
+ });
369
+
370
+ const result = await cloud.remotion.render({
371
+ serveUrl: "https://example.com/remotion-bundle",
372
+ composition: "ProductDemo",
373
+ snapshotId: runtime.id,
374
+ codec: "h264",
375
+ output: { uploadUrl: presignedPutUrl, downloadUrl: finalObjectUrl },
376
+ });
377
+ ```
378
+
379
+ The snapshot is private to the caller's run.cloud organization. Create one per
380
+ Remotion version and delete obsolete snapshots with `cloud.snapshots.delete()`.
381
+
316
382
  For a smaller migration from `@remotion/lambda/client`, switch the import and
317
383
  add `s3Output`; existing `region` and `functionName` fields may remain while
318
384
  compute moves to run.cloud:
@@ -394,6 +460,15 @@ finite sandbox timeouts remain the cleanup backstop.
394
460
 
395
461
  `cloud.assets.upload(blob, options)` verifies the uploaded size and MD5 before
396
462
  returning a ready asset. Re-uploading the same bytes reuses the verified object.
463
+ `cloud.assets.uploadDirect(blob, options)` uses the API's buffered multipart
464
+ endpoint when a signed-storage transfer is not suitable, and
465
+ `cloud.assets.download(id)` returns the owned asset as a `Uint8Array`:
466
+
467
+ ```ts
468
+ const asset = await cloud.assets.uploadDirect(blob, { filename: "app.tar.gz" });
469
+ await writeFile("app.tar.gz", await cloud.assets.download(asset.id));
470
+ ```
471
+
397
472
  For multipart archives, `cloud.assets.uploadBatch(parts, { uploadBatchId,
398
473
  uploadRunId })` numbers the parts, records per-part transfer telemetry, and
399
474
  limits direct storage transfers to six at a time.
@@ -37,7 +37,7 @@ export interface RenderMediaOnLambdaInput extends CompatibilityClientOptions {
37
37
  * upload and download locations. run.cloud never owns the bucket.
38
38
  */
39
39
  s3Output: LambdaCompatibleS3Output;
40
- runCloud?: Pick<RemotionRenderOptions, "image" | "remotionVersion" | "cpu" | "memory" | "disk" | "timeoutSeconds" | "startupTimeoutSeconds" | "region" | "name" | "idempotencyKey"> & {
40
+ runCloud?: Pick<RemotionRenderOptions, "image" | "snapshotId" | "remotionVersion" | "cpu" | "memory" | "disk" | "timeoutSeconds" | "startupTimeoutSeconds" | "region" | "name" | "idempotencyKey"> & {
41
41
  /**
42
42
  * Enables multi-sandbox rendering. createChunkOutput presigns temporary
43
43
  * video/audio objects in the customer's own S3 bucket.
@@ -33,7 +33,9 @@ export async function renderMediaOnLambda(input) {
33
33
  ...runCloud,
34
34
  distributed,
35
35
  remotionVersion: runCloud.remotionVersion ??
36
- (runCloud.image ? undefined : remotionVersionFromFunctionName(input.functionName)),
36
+ (runCloud.image || runCloud.snapshotId
37
+ ? undefined
38
+ : remotionVersionFromFunctionName(input.functionName)),
37
39
  });
38
40
  return {
39
41
  renderId: handle.renderId,
@@ -61,7 +63,7 @@ export async function deleteRender(input) {
61
63
  export function remotionVersionFromFunctionName(functionName) {
62
64
  const match = functionName?.match(/^remotion-render-(\d+)-(\d+)-(\d+)(?:-|$)/);
63
65
  if (!match) {
64
- throw new TypeError("functionName must use Remotion's naming convention, or runCloud.remotionVersion/image must be supplied");
66
+ throw new TypeError("functionName must use Remotion's naming convention, or runCloud.remotionVersion/image/snapshotId must be supplied");
65
67
  }
66
68
  return `${match[1]}.${match[2]}.${match[3]}`;
67
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"remotion-lambda.js","sourceRoot":"","sources":["../../src/compat/remotion-lambda.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remotion-lambda.js","sourceRoot":"","sources":["../../src/compat/remotion-lambda.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -337,6 +337,34 @@ export interface Account {
337
337
  run_cloud_metering_status?: string;
338
338
  [key: string]: unknown;
339
339
  }
340
+ /** Lightweight credential probe used by login and token-validation flows. */
341
+ export interface CredentialAccount {
342
+ userId: string;
343
+ products: string[];
344
+ runCloud: boolean;
345
+ orgs: string[];
346
+ }
347
+ /** Organization-wide live sandbox capacity and estimated lifetime usage. */
348
+ export interface RunCloudOverview {
349
+ total: number;
350
+ byState: Record<string, number>;
351
+ reservedMilliCpu: number;
352
+ reservedMemMb: number;
353
+ billedSeconds: number;
354
+ estimatedCostUsd: number;
355
+ actualCpuSeconds: number;
356
+ }
357
+ export type SandboxMetricRange = "1h" | "6h" | "24h" | "7d" | "30d" | "all";
358
+ export type SandboxHistoryRange = SandboxMetricRange;
359
+ export interface SandboxHistoryPoint {
360
+ timestamp: string;
361
+ count: number;
362
+ }
363
+ export interface SandboxHistory {
364
+ range: SandboxHistoryRange;
365
+ created: number;
366
+ points: SandboxHistoryPoint[];
367
+ }
340
368
  export interface Asset {
341
369
  id: string;
342
370
  name: string;
@@ -565,6 +593,65 @@ export interface SandboxTunnel {
565
593
  expiresAt: string;
566
594
  createdAt: string;
567
595
  }
596
+ export interface SandboxMetric {
597
+ timestamp: string;
598
+ state: string;
599
+ cpu_millicores: number;
600
+ cpu_throttled_millicores: number;
601
+ cpu_throttled_periods: number;
602
+ cpu_throttling_valid: boolean;
603
+ memory_bytes: number;
604
+ memory_oom_events: number;
605
+ memory_oom_kills: number;
606
+ memory_events_valid: boolean;
607
+ network_rx_bytes_per_second: number;
608
+ network_tx_bytes_per_second: number;
609
+ network_rx_bytes: number;
610
+ network_tx_bytes: number;
611
+ network_valid: boolean;
612
+ io_read_bytes_per_second: number;
613
+ io_write_bytes_per_second: number;
614
+ io_read_bytes: number;
615
+ io_write_bytes: number;
616
+ io_valid: boolean;
617
+ cpu_pressure_usec_per_second: number;
618
+ memory_pressure_usec_per_second: number;
619
+ io_pressure_usec_per_second: number;
620
+ pressure_valid: boolean;
621
+ disk_used_bytes: number;
622
+ disk_total_bytes: number;
623
+ disk_valid: boolean;
624
+ }
625
+ export interface SandboxMetrics {
626
+ range: SandboxMetricRange;
627
+ current: SandboxMetric | null;
628
+ history: SandboxMetric[];
629
+ }
630
+ export interface SandboxDesktop {
631
+ url: string;
632
+ expiresAt: string;
633
+ viewOnly: boolean;
634
+ }
635
+ export type SandboxComputerAction = {
636
+ action: "screenshot";
637
+ } | {
638
+ action: "click";
639
+ x: number;
640
+ y: number;
641
+ } | {
642
+ action: "type";
643
+ text: string;
644
+ } | {
645
+ action: "key";
646
+ keys: string;
647
+ };
648
+ export interface SandboxComputerResult {
649
+ error?: string;
650
+ /** Base64-encoded PNG when action is screenshot. */
651
+ image?: string;
652
+ x?: number;
653
+ y?: number;
654
+ }
568
655
  /**
569
656
  * A persistent published web app: a stable `<name>-box.run.cloud` hostname
570
657
  * routed to one port on an already-running, idle-pause-disabled sandbox.
@@ -824,12 +911,17 @@ export declare class Client {
824
911
  usage(options?: {
825
912
  orgId?: string;
826
913
  }): Promise<UsageReport>;
914
+ /** Validate the current credential and return its product/org scope. */
915
+ credential(): Promise<CredentialAccount>;
916
+ /** Revoke the API key making this request. Session credentials are a no-op. */
917
+ revokeCurrentApiKey(): Promise<void>;
918
+ /** Aggregate live fleet capacity and estimated usage for the caller's organizations. */
919
+ overview(): Promise<RunCloudOverview>;
827
920
  /**
828
921
  * The caller's profile, org memberships (with role), and sign-in
829
922
  * providers. Backed by `/run-cloud/me` — the richer, deliberately-designed
830
923
  * profile route, not the older `/run-cloud/account` (a thin credential
831
- * probe the `newly` CLI still calls directly; nothing in this SDK targets
832
- * it as of this method's repoint in 0.17.0).
924
+ * probe exposed separately through `credential()`).
833
925
  */
834
926
  account(): Promise<Account>;
835
927
  /**
@@ -977,6 +1069,20 @@ export declare class SandboxClient {
977
1069
  name?: string;
978
1070
  }): Promise<Sandbox[]>;
979
1071
  get(id: string): Promise<Sandbox>;
1072
+ /** Organization-scoped live sandbox counts over a bounded time range. */
1073
+ history(options?: {
1074
+ range?: SandboxHistoryRange;
1075
+ }): Promise<SandboxHistory>;
1076
+ /** Current and time-bucketed resource metrics for one owned sandbox. */
1077
+ metrics(id: string, options?: {
1078
+ range?: SandboxMetricRange;
1079
+ }): Promise<SandboxMetrics>;
1080
+ /** Mint a short-lived noVNC capability for a running desktop-image sandbox. */
1081
+ desktop(id: string, options?: {
1082
+ viewOnly?: boolean;
1083
+ }): Promise<SandboxDesktop>;
1084
+ /** Perform one owner-gated computer-use action in a desktop-image sandbox. */
1085
+ computer(id: string, action: SandboxComputerAction): Promise<SandboxComputerResult>;
980
1086
  /**
981
1087
  * Halt a sandbox, keeping its disk and memory. Compute billing stops; a
982
1088
  * `resume` brings back the same sandbox. Idle sandboxes pause themselves
@@ -1090,6 +1196,9 @@ export declare class SnapshotsClient {
1090
1196
  cpu?: number;
1091
1197
  memory?: number;
1092
1198
  disk?: number;
1199
+ idlePauseSeconds?: number;
1200
+ timeoutSeconds?: number;
1201
+ idempotencyKey?: string;
1093
1202
  }): Promise<Sandbox>;
1094
1203
  }
1095
1204
  export declare class BoxClient {
@@ -1259,6 +1368,10 @@ export declare class AssetsClient {
1259
1368
  private readonly defaultUploadRunId;
1260
1369
  constructor(client: Client);
1261
1370
  list(): Promise<Asset[]>;
1371
+ /** Upload through the buffered multipart endpoint instead of signed storage URLs. */
1372
+ uploadDirect(file: Blob, options?: Pick<AssetUploadOptions, "name" | "filename">): Promise<Asset>;
1373
+ /** Download an owned asset, following the API's short-lived signed redirect. */
1374
+ download(id: string): Promise<Uint8Array>;
1262
1375
  upload(file: Blob, options?: AssetUploadOptions): Promise<Asset>;
1263
1376
  uploadBatch(items: AssetUploadItem[], options?: {
1264
1377
  uploadBatchId?: string;
package/dist/index.js CHANGED
@@ -1,7 +1,22 @@
1
1
  import WebSocket from "ws";
2
- import { createHash, randomUUID } from "node:crypto";
2
+ import { context, propagation } from "@opentelemetry/api";
3
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
3
4
  import { RemotionClient } from "./remotion.js";
4
5
  export * from "./remotion.js";
6
+ function randomW3cId(bytes) {
7
+ const value = randomBytes(bytes);
8
+ if (value.every((byte) => byte === 0))
9
+ value[value.length - 1] = 1;
10
+ return value.toString("hex");
11
+ }
12
+ function outboundTraceHeaders() {
13
+ const carrier = {};
14
+ propagation.inject(context.active(), carrier);
15
+ if (!carrier.traceparent) {
16
+ carrier.traceparent = `00-${randomW3cId(16)}-${randomW3cId(8)}-01`;
17
+ }
18
+ return carrier;
19
+ }
5
20
  export const SIMULATOR_KEYS = [
6
21
  "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
7
22
  "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
@@ -727,18 +742,29 @@ export class Client {
727
742
  this.secrets = new SecretsClient(this);
728
743
  this.ci = new CiClient(this);
729
744
  this.images = new ImageClient(this);
730
- this.remotion = new RemotionClient(this.sandboxes);
745
+ this.remotion = new RemotionClient(this.sandboxes, this.snapshots);
731
746
  }
732
747
  async usage(options = {}) {
733
748
  const query = options.orgId ? `?orgId=${encodeURIComponent(options.orgId)}` : "";
734
749
  return await this.request("GET", `/run-cloud/usage${query}`);
735
750
  }
751
+ /** Validate the current credential and return its product/org scope. */
752
+ async credential() {
753
+ return await this.request("GET", "/run-cloud/account");
754
+ }
755
+ /** Revoke the API key making this request. Session credentials are a no-op. */
756
+ async revokeCurrentApiKey() {
757
+ await this.request("DELETE", "/run-cloud/api-keys/self");
758
+ }
759
+ /** Aggregate live fleet capacity and estimated usage for the caller's organizations. */
760
+ async overview() {
761
+ return await this.request("GET", "/run-cloud/overview");
762
+ }
736
763
  /**
737
764
  * The caller's profile, org memberships (with role), and sign-in
738
765
  * providers. Backed by `/run-cloud/me` — the richer, deliberately-designed
739
766
  * profile route, not the older `/run-cloud/account` (a thin credential
740
- * probe the `newly` CLI still calls directly; nothing in this SDK targets
741
- * it as of this method's repoint in 0.17.0).
767
+ * probe exposed separately through `credential()`).
742
768
  */
743
769
  async account() {
744
770
  const raw = await this.request("GET", "/run-cloud/me");
@@ -766,6 +792,7 @@ export class Client {
766
792
  Authorization: `Bearer ${this.apiKey}`,
767
793
  ...(body === undefined ? {} : { "Content-Type": "application/json" }),
768
794
  ...headers,
795
+ ...outboundTraceHeaders(),
769
796
  },
770
797
  body: body === undefined ? undefined : JSON.stringify(body),
771
798
  signal: operation.signal,
@@ -810,7 +837,10 @@ export class Client {
810
837
  async uploadForm(path, form) {
811
838
  const response = await this.fetchImpl(`${this.apiUrl}${path}`, {
812
839
  method: "POST",
813
- headers: { Authorization: `Bearer ${this.apiKey}` },
840
+ headers: {
841
+ Authorization: `Bearer ${this.apiKey}`,
842
+ ...outboundTraceHeaders(),
843
+ },
814
844
  body: form,
815
845
  });
816
846
  if (!response.ok)
@@ -825,6 +855,7 @@ export class Client {
825
855
  headers: {
826
856
  Authorization: `Bearer ${this.apiKey}`,
827
857
  ...abortOptions.headers,
858
+ ...outboundTraceHeaders(),
828
859
  },
829
860
  signal: operation.signal,
830
861
  });
@@ -863,6 +894,7 @@ export class Client {
863
894
  headers: {
864
895
  Authorization: `Bearer ${this.apiKey}`,
865
896
  Accept: "text/event-stream",
897
+ ...outboundTraceHeaders(),
866
898
  },
867
899
  signal,
868
900
  });
@@ -903,7 +935,10 @@ export class Client {
903
935
  async requestTextWithHeaders(path) {
904
936
  const response = await this.fetchImpl(`${this.apiUrl}${path}`, {
905
937
  method: "GET",
906
- headers: { Authorization: `Bearer ${this.apiKey}` },
938
+ headers: {
939
+ Authorization: `Bearer ${this.apiKey}`,
940
+ ...outboundTraceHeaders(),
941
+ },
907
942
  });
908
943
  if (!response.ok)
909
944
  throw await apiError(response);
@@ -917,9 +952,13 @@ export class Client {
917
952
  async execStream(path, request, callbacks = {}) {
918
953
  const url = new URL(`${this.apiUrl}${path}`);
919
954
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
955
+ const traceHeaders = outboundTraceHeaders();
920
956
  return await new Promise((resolve, reject) => {
921
957
  const socket = this.webSocketFactory(url.toString(), {
922
- headers: { Authorization: `Bearer ${this.apiKey}` },
958
+ headers: {
959
+ Authorization: `Bearer ${this.apiKey}`,
960
+ ...traceHeaders,
961
+ },
923
962
  });
924
963
  const stdout = [];
925
964
  const stderr = [];
@@ -954,7 +993,10 @@ export class Client {
954
993
  return;
955
994
  }
956
995
  callbacks.signal?.addEventListener("abort", abort, { once: true });
957
- socket.once("open", () => socket.send(JSON.stringify(request)));
996
+ socket.once("open", () => socket.send(JSON.stringify({
997
+ ...request,
998
+ ...traceHeaders,
999
+ })));
958
1000
  socket.on("message", (raw) => {
959
1001
  let frame;
960
1002
  try {
@@ -1483,6 +1525,24 @@ export class SandboxClient {
1483
1525
  const raw = await this.client.request("GET", `/run-cloud/sandboxes/${encodeURIComponent(id)}`);
1484
1526
  return normalizeSandbox(raw);
1485
1527
  }
1528
+ /** Organization-scoped live sandbox counts over a bounded time range. */
1529
+ async history(options = {}) {
1530
+ const query = options.range ? `?range=${encodeURIComponent(options.range)}` : "";
1531
+ return await this.client.request("GET", `/run-cloud/sandboxes/history${query}`);
1532
+ }
1533
+ /** Current and time-bucketed resource metrics for one owned sandbox. */
1534
+ async metrics(id, options = {}) {
1535
+ const query = options.range ? `?range=${encodeURIComponent(options.range)}` : "";
1536
+ return await this.client.request("GET", `/run-cloud/sandboxes/${encodeURIComponent(id)}/metrics${query}`);
1537
+ }
1538
+ /** Mint a short-lived noVNC capability for a running desktop-image sandbox. */
1539
+ async desktop(id, options = {}) {
1540
+ return await this.client.request("POST", `/run-cloud/sandboxes/${encodeURIComponent(id)}/desktop`, options);
1541
+ }
1542
+ /** Perform one owner-gated computer-use action in a desktop-image sandbox. */
1543
+ async computer(id, action) {
1544
+ return await this.client.request("POST", `/run-cloud/sandboxes/${encodeURIComponent(id)}/computer`, action);
1545
+ }
1486
1546
  /**
1487
1547
  * Halt a sandbox, keeping its disk and memory. Compute billing stops; a
1488
1548
  * `resume` brings back the same sandbox. Idle sandboxes pause themselves
@@ -1730,6 +1790,7 @@ export class SnapshotsClient {
1730
1790
  await this.client.request("DELETE", `/run-cloud/snapshots/${encodeURIComponent(id)}`);
1731
1791
  }
1732
1792
  async restore(id, options = {}) {
1793
+ const { idempotencyKey } = options;
1733
1794
  const raw = await this.client.request("POST", `/run-cloud/snapshots/${encodeURIComponent(id)}/restore`, {
1734
1795
  ...(options.name === undefined ? {} : { name: options.name }),
1735
1796
  ...(options.region === undefined ? {} : { region: options.region }),
@@ -1737,7 +1798,13 @@ export class SnapshotsClient {
1737
1798
  ...(options.cpu === undefined ? {} : { cpu: options.cpu }),
1738
1799
  ...(options.memory === undefined ? {} : { memory: options.memory }),
1739
1800
  ...(options.disk === undefined ? {} : { disk: options.disk }),
1740
- });
1801
+ ...(options.idlePauseSeconds === undefined
1802
+ ? {}
1803
+ : { idlePauseSeconds: options.idlePauseSeconds }),
1804
+ ...(options.timeoutSeconds === undefined
1805
+ ? {}
1806
+ : { timeoutSeconds: options.timeoutSeconds }),
1807
+ }, idempotencyKey ? { "Idempotency-Key": idempotencyKey } : undefined);
1741
1808
  return normalizeSandbox(raw);
1742
1809
  }
1743
1810
  }
@@ -1968,6 +2035,18 @@ export class AssetsClient {
1968
2035
  async list() {
1969
2036
  return await this.client.request("GET", "/run-cloud/assets");
1970
2037
  }
2038
+ /** Upload through the buffered multipart endpoint instead of signed storage URLs. */
2039
+ async uploadDirect(file, options = {}) {
2040
+ const form = new FormData();
2041
+ if (options.name !== undefined)
2042
+ form.append("name", options.name);
2043
+ form.append("file", file, options.filename ?? "app.bin");
2044
+ return await this.client.uploadForm("/run-cloud/assets", form);
2045
+ }
2046
+ /** Download an owned asset, following the API's short-lived signed redirect. */
2047
+ async download(id) {
2048
+ return await this.client.requestBytes(`/run-cloud/assets/${encodeURIComponent(id)}/download`);
2049
+ }
1971
2050
  async upload(file, options = {}) {
1972
2051
  return await this.withUploadSlot(async () => {
1973
2052
  const filename = options.filename ?? "app.bin";