@run-cloud/sdk 0.27.0 → 0.29.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
@@ -67,6 +67,16 @@ if (completed.status !== "succeeded") {
67
67
  throw new Error(`${completed.failure?.reason}\n${completed.failure?.action}`);
68
68
  }
69
69
  await writeFile("MyApp.tar.gz", await cloud.xcode.downloadArtifact(completed.id));
70
+
71
+ const rebuilt = await cloud.xcode.rebundle(process.cwd(), completed.id, {
72
+ idempotencyKey: `rebundle-${completed.id}-${process.env.GITHUB_SHA ?? "local"}`,
73
+ });
74
+ const ready = await cloud.xcode.wait(rebuilt.id);
75
+ const launch = await cloud.mobile.launch(
76
+ { buildId: ready.id },
77
+ { idempotencyKey: `launch-${ready.id}`, orgId: ready.orgId },
78
+ );
79
+ console.log(launch.id, launch.sessionId, launch.status);
70
80
  ```
71
81
 
72
82
  Build records, sanitized logs, failure reasons, and artifacts stay available by
@@ -75,6 +85,8 @@ ID to members of the owning organization. Source packaging honors the root
75
85
  include, ignore, and additional-file rules. Full options and intentional
76
86
  differences are documented at
77
87
  [docs.run.cloud/ios/build-with-xcode](https://docs.run.cloud/ios/build-with-xcode).
88
+ Use `cloud.xcode.events` for replayable lifecycle delivery and
89
+ `cloud.capabilities.create` for short-lived access to selected resources.
78
90
 
79
91
  ## Retry-safe simulator creates
80
92
 
@@ -557,8 +569,10 @@ ends.
557
569
  QuickTime blobs and imports them into Photos. The video is stored as a
558
570
  user-owned run.cloud asset and remains available through `cloud.assets`.
559
571
 
560
- `cloud.ios.uploadMicrophoneAudio(sessionId, audioBlob, { filename, bundleId })`
561
- accepts AAC, M4A, MP3, MP4 audio, and WAV. It relaunches the foreground app
562
- (or `bundleId`) with microphone permission and loops the decoded audio through
563
- the app's `AVAudioEngine` input tap. The uploaded source remains in
564
- `cloud.assets`.
572
+ `cloud.ios.uploadCameraVideo(...)` and `cloud.android.uploadCameraVideo(...)`
573
+ accept MP4 and QuickTime blobs and loop them through the target app camera.
574
+ `cloud.ios.uploadMicrophoneAudio(...)` and
575
+ `cloud.android.uploadMicrophoneAudio(...)` accept AAC, M4A, MP3, MP4 audio,
576
+ and WAV and deliver decoded samples through the target app microphone. Pass
577
+ `bundleId` to name the target app. Both results contain the retained uploaded
578
+ asset; delete it through `cloud.assets` when it is no longer needed.
package/dist/index.d.ts CHANGED
@@ -70,7 +70,7 @@ export type SimulatorInteraction = {
70
70
  enabled: boolean;
71
71
  };
72
72
  export type SimulatorInteractionAction = SimulatorInteraction["action"];
73
- export type SimulatorOperation = SimulatorInteractionAction | "screenshot" | "accessibility" | "install" | "activity" | "metro-tunnel" | "open-url";
73
+ export type SimulatorOperation = SimulatorInteractionAction | "screenshot" | "accessibility" | "install" | "activity" | "camera-video" | "microphone-audio" | "metro-tunnel" | "open-url";
74
74
  export declare const SIMULATOR_SESSION_ERROR_CODES: readonly ["simulator_capacity_unavailable"];
75
75
  export type SimulatorSessionErrorCode = (typeof SIMULATOR_SESSION_ERROR_CODES)[number];
76
76
  export declare const SIMULATOR_OPEN_URL_ERROR_CODES: readonly ["invalid_url", "active_session_not_found", "open_url_scope_required", "simulator_session_ended", "ios_url_handler_not_found", "android_url_handler_not_found", "simulator_unavailable", "open_url_timeout", "ios_open_url_failed", "android_open_url_failed", "open_url_transport_error", "open_url_invalid_response", "open_url_failed"];
@@ -282,6 +282,12 @@ export interface AggregateSimulatorRecordingStartOptions extends SimulatorRecord
282
282
  export interface AggregateSimulatorRecordingRequestOptions extends SimulatorRecordingRequestOptions {
283
283
  platform?: SimulatorPlatform;
284
284
  }
285
+ export interface AggregateSimulatorCameraVideoOptions extends SimulatorCameraVideoOptions {
286
+ platform?: SimulatorPlatform;
287
+ }
288
+ export interface AggregateSimulatorMicrophoneAudioOptions extends SimulatorMicrophoneAudioOptions {
289
+ platform?: SimulatorPlatform;
290
+ }
285
291
  export declare const DEFAULT_SIMULATOR_INTERACTION_TIMEOUT_MS = 15000;
286
292
  export declare const DEFAULT_SIMULATOR_ACCESSIBILITY_TIMEOUT_MS = 20000;
287
293
  export declare function validateSimulatorInteraction(interaction: SimulatorInteraction, timeoutMs?: number): void;
@@ -367,6 +373,7 @@ export interface SandboxHistory {
367
373
  }
368
374
  export interface Asset {
369
375
  id: string;
376
+ orgId?: string | null;
370
377
  name: string;
371
378
  filename: string;
372
379
  contentType: string;
@@ -386,11 +393,21 @@ export interface Asset {
386
393
  retries?: number;
387
394
  throughputBps?: number | null;
388
395
  };
396
+ origin?: {
397
+ kind: "upload";
398
+ } | {
399
+ kind: "xcode-build";
400
+ buildId: string;
401
+ };
402
+ parentAssetId?: string | null;
403
+ immutable?: boolean;
404
+ metadata?: Record<string, unknown>;
389
405
  createdAt: string;
390
406
  /** Authenticated API path; GET follows a short-lived signed storage redirect. */
391
407
  downloadUrl: string;
392
408
  }
393
409
  export interface AssetUploadOptions {
410
+ orgId?: string;
394
411
  name?: string;
395
412
  filename?: string;
396
413
  /** Stable archive/batch identifier shared by every part in one logical upload. */
@@ -411,13 +428,31 @@ export interface VideoUploadResult {
411
428
  byteSize: number;
412
429
  asset: Asset;
413
430
  }
431
+ export interface CameraVideoResult {
432
+ ok: true;
433
+ platform: SimulatorPlatform;
434
+ sessionId: string;
435
+ bundleId: string | null;
436
+ filename: string;
437
+ contentType: "video/mp4" | "video/quicktime";
438
+ byteSize: number;
439
+ source: "video";
440
+ pid: number | null;
441
+ asset: Asset;
442
+ }
414
443
  export interface MicrophoneAudioResult {
415
444
  ok: true;
445
+ platform: SimulatorPlatform;
446
+ sessionId: string;
416
447
  bundleId: string;
417
448
  filename: string;
418
449
  contentType: string;
419
450
  byteSize: number;
420
451
  pid: number | null;
452
+ sampleRate?: number;
453
+ channels?: number;
454
+ sampleCount?: number;
455
+ durationMs?: number;
421
456
  asset: Asset;
422
457
  }
423
458
  export type XcodeSdk = "iphonesimulator" | "iphoneos" | "watchsimulator" | "watchos";
@@ -496,13 +531,20 @@ export interface XcodeBuildOptions extends XcodeProjectOptions {
496
531
  timeoutSeconds?: number;
497
532
  source?: XcodeSourceOptions;
498
533
  idempotencyKey?: string;
534
+ /** Native shell whose compatible JavaScript bundle should be replaced. */
535
+ reuse?: {
536
+ basisBuildId: string;
537
+ };
499
538
  }
539
+ export type XcodeRebundleOptions = Omit<XcodeBuildOptions, "workspace" | "project" | "scheme" | "sdk" | "configuration" | "xcodegen" | "signing" | "cloudSigning" | "appStore" | "appstore" | "reuse">;
500
540
  export interface XcodeBuildArtifact {
501
541
  kind: "simulator-app" | "device-app" | "signed-ipa" | "watch-app";
502
542
  filename: string;
503
543
  contentType: string;
504
544
  byteSize: number | null;
505
545
  available: boolean;
546
+ /** Reusable run.cloud Asset identity for this immutable output. */
547
+ assetId: string | null;
506
548
  /** Authenticated endpoint that redirects to a short-lived object URL. */
507
549
  downloadUrl: string | null;
508
550
  }
@@ -531,6 +573,11 @@ export interface XcodeBuild {
531
573
  byteSize: number;
532
574
  };
533
575
  artifact: XcodeBuildArtifact;
576
+ reuse: {
577
+ mode: "full" | "rebundle";
578
+ basisBuildId: string | null;
579
+ nativeFingerprint: string | null;
580
+ };
534
581
  logs: {
535
582
  available: boolean;
536
583
  url: string;
@@ -555,6 +602,22 @@ export interface XcodeBuildLogChunk {
555
602
  text: string;
556
603
  nextOffset: number;
557
604
  complete: boolean;
605
+ source?: "live" | "retained";
606
+ }
607
+ export interface XcodeBuildEvent {
608
+ sequence: number;
609
+ id: string;
610
+ orgId: string;
611
+ buildId: string;
612
+ type: string;
613
+ status: XcodeBuildStatus;
614
+ stage: string | null;
615
+ data: Record<string, unknown>;
616
+ createdAt: string;
617
+ }
618
+ export interface XcodeBuildEventPage {
619
+ items: XcodeBuildEvent[];
620
+ nextCursor: number;
558
621
  }
559
622
  export interface XcodeBuildWaitOptions {
560
623
  onLog?: (text: string) => void;
@@ -563,6 +626,7 @@ export interface XcodeBuildWaitOptions {
563
626
  signal?: AbortSignal;
564
627
  }
565
628
  export interface CreateSessionOptions {
629
+ orgId?: string;
566
630
  /** Retry-safe create: reuse this value to receive the original simulator session. */
567
631
  idempotencyKey?: string;
568
632
  model?: string;
@@ -585,6 +649,7 @@ export interface SimulatorStream {
585
649
  }
586
650
  export interface SimulatorSession {
587
651
  id: string;
652
+ orgId: string | null;
588
653
  platform: SimulatorPlatform;
589
654
  status: "active" | "released" | "failed" | string;
590
655
  model?: string | null;
@@ -608,6 +673,65 @@ export interface SimulatorSession {
608
673
  queueAttempts?: number;
609
674
  metering?: Record<string, unknown>;
610
675
  }
676
+ export type RunCloudCapabilityScope = "asset.read" | "mobile.launch" | "xcode.build.create" | "xcode.build.read";
677
+ export interface RunCloudCapabilityResources {
678
+ assetIds?: string[];
679
+ buildIds?: string[];
680
+ idempotencyKeys?: string[];
681
+ }
682
+ export interface RunCloudCapability {
683
+ id: string;
684
+ orgId: string;
685
+ createdBy: string;
686
+ name: string | null;
687
+ scopes: RunCloudCapabilityScope[];
688
+ resources: RunCloudCapabilityResources;
689
+ expiresAt: string;
690
+ lastUsedAt: string | null;
691
+ revokedAt: string | null;
692
+ createdAt: string;
693
+ }
694
+ export interface CreateCapabilityOptions {
695
+ scopes: RunCloudCapabilityScope[];
696
+ resources: RunCloudCapabilityResources;
697
+ orgId?: string;
698
+ name?: string;
699
+ expiresInSeconds?: number;
700
+ }
701
+ export interface MobileLaunch {
702
+ id: string;
703
+ orgId: string;
704
+ idempotencyKey: string;
705
+ status: "provisioning" | "succeeded" | "failed";
706
+ platform: SimulatorPlatform;
707
+ source: {
708
+ assetId: string;
709
+ buildId: string | null;
710
+ };
711
+ sessionId: string;
712
+ session: SimulatorSession | null;
713
+ failure: {
714
+ reason: string;
715
+ code: string;
716
+ action: string;
717
+ } | null;
718
+ createdAt: string;
719
+ completedAt: string | null;
720
+ updatedAt: string;
721
+ }
722
+ export type MobileLaunchSource = {
723
+ assetId: string;
724
+ buildId?: never;
725
+ } | {
726
+ buildId: string;
727
+ assetId?: never;
728
+ };
729
+ export interface MobileLaunchOptions {
730
+ idempotencyKey: string;
731
+ orgId?: string;
732
+ platform?: SimulatorPlatform;
733
+ session?: Omit<CreateSessionOptions, "orgId" | "idempotencyKey" | "installAssets">;
734
+ }
611
735
  /** Confirmation that a URL was dispatched to the authenticated simulator lease. */
612
736
  export interface SimulatorOpenUrlResult {
613
737
  ok: true;
@@ -622,6 +746,16 @@ export interface SimulatorInstallOptions {
622
746
  filename?: string;
623
747
  name?: string;
624
748
  }
749
+ export interface SimulatorCameraVideoOptions {
750
+ filename?: string;
751
+ name?: string;
752
+ bundleId?: string;
753
+ }
754
+ export interface SimulatorMicrophoneAudioOptions {
755
+ filename?: string;
756
+ name?: string;
757
+ bundleId?: string;
758
+ }
625
759
  export interface SimulatorInstallResult {
626
760
  ok: true;
627
761
  platform: SimulatorPlatform;
@@ -1089,6 +1223,8 @@ export declare class Client {
1089
1223
  readonly images: ImageClient;
1090
1224
  readonly remotion: RemotionClient;
1091
1225
  readonly xcode: XcodeBuildsClient;
1226
+ readonly capabilities: CapabilitiesClient;
1227
+ readonly mobile: MobileClient;
1092
1228
  private readonly apiKey;
1093
1229
  private readonly apiUrl;
1094
1230
  private readonly fetchImpl;
@@ -1141,12 +1277,21 @@ export declare class XcodeBuildsClient {
1141
1277
  constructor(client: Client);
1142
1278
  /** Package a local source tree and submit one idempotent remote Xcode build. */
1143
1279
  build(sourcePath?: string, options?: XcodeBuildOptions): Promise<XcodeBuild>;
1280
+ /** Reuse a compatible simulator native shell and replace only its embedded JavaScript bundle. */
1281
+ rebundle(sourcePath: string, basisBuildId: string, options?: XcodeRebundleOptions): Promise<XcodeBuild>;
1144
1282
  get(id: string): Promise<XcodeBuild>;
1145
1283
  list(options?: {
1146
1284
  orgId?: string;
1147
1285
  limit?: number;
1148
1286
  }): Promise<XcodeBuild[]>;
1149
- logs(id: string, offset?: number): Promise<XcodeBuildLogChunk>;
1287
+ /** Read an ordered, replayable event page. Persist nextCursor after processing the page. */
1288
+ events(options?: {
1289
+ orgId?: string;
1290
+ after?: number;
1291
+ buildId?: string;
1292
+ limit?: number;
1293
+ }): Promise<XcodeBuildEventPage>;
1294
+ logs(id: string, offset?: number, source?: XcodeBuildLogChunk["source"]): Promise<XcodeBuildLogChunk>;
1150
1295
  /** Poll state and emit sanitized log chunks until the build is terminal. */
1151
1296
  wait(id: string, options?: XcodeBuildWaitOptions): Promise<XcodeBuild>;
1152
1297
  cancel(id: string): Promise<XcodeBuild>;
@@ -1164,11 +1309,16 @@ export declare class SimulatorClient {
1164
1309
  setTags(id: string, tags: Record<string, string | null>): Promise<SimulatorSession>;
1165
1310
  list(options?: {
1166
1311
  all?: boolean;
1312
+ orgId?: string;
1167
1313
  }): Promise<SimulatorSession[]>;
1168
1314
  get(id: string): Promise<SimulatorSession>;
1169
1315
  delete(id: string): Promise<SimulatorSession>;
1170
1316
  installAsset(id: string, assetId: string): Promise<SimulatorInstallResult>;
1171
1317
  install(id: string, application: Blob, options?: SimulatorInstallOptions): Promise<SimulatorInstallResult>;
1318
+ /** Upload a deterministic video and present it to the app as live camera input. */
1319
+ uploadCameraVideo(id: string, video: Blob, options?: SimulatorCameraVideoOptions): Promise<CameraVideoResult>;
1320
+ /** Upload audio and deliver its decoded samples to the app microphone. */
1321
+ uploadMicrophoneAudio(id: string, audio: Blob, options?: SimulatorMicrophoneAudioOptions): Promise<MicrophoneAudioResult>;
1172
1322
  keepAlive(id: string): Promise<SimulatorActivityResult>;
1173
1323
  openMetroTunnel(id: string, options: SimulatorMetroTunnelOptions): Promise<SimulatorMetroTunnel>;
1174
1324
  openUrl(id: string, url: string): Promise<SimulatorOpenUrlResult>;
@@ -1211,11 +1361,6 @@ export declare class IosSimulatorClient extends SimulatorClient {
1211
1361
  filename?: string;
1212
1362
  name?: string;
1213
1363
  }): Promise<VideoUploadResult>;
1214
- uploadMicrophoneAudio(id: string, audio: Blob, options?: {
1215
- filename?: string;
1216
- name?: string;
1217
- bundleId?: string;
1218
- }): Promise<MicrophoneAudioResult>;
1219
1364
  }
1220
1365
  export declare class SimulatorsClient {
1221
1366
  private readonly client;
@@ -1226,6 +1371,7 @@ export declare class SimulatorsClient {
1226
1371
  list(options?: {
1227
1372
  platform?: SimulatorPlatform;
1228
1373
  all?: boolean;
1374
+ orgId?: string;
1229
1375
  }): Promise<SimulatorSession[]>;
1230
1376
  get(id: string, options?: {
1231
1377
  platform?: SimulatorPlatform;
@@ -1242,6 +1388,8 @@ export declare class SimulatorsClient {
1242
1388
  install(id: string, application: Blob, options?: SimulatorInstallOptions & {
1243
1389
  platform?: SimulatorPlatform;
1244
1390
  }): Promise<SimulatorInstallResult>;
1391
+ uploadCameraVideo(id: string, video: Blob, options?: AggregateSimulatorCameraVideoOptions): Promise<CameraVideoResult>;
1392
+ uploadMicrophoneAudio(id: string, audio: Blob, options?: AggregateSimulatorMicrophoneAudioOptions): Promise<MicrophoneAudioResult>;
1245
1393
  keepAlive(id: string, options?: {
1246
1394
  platform?: SimulatorPlatform;
1247
1395
  }): Promise<SimulatorActivityResult>;
@@ -1585,7 +1733,9 @@ export declare class AssetsClient {
1585
1733
  private readonly waitingUploads;
1586
1734
  private readonly defaultUploadRunId;
1587
1735
  constructor(client: Client);
1588
- list(): Promise<Asset[]>;
1736
+ list(options?: {
1737
+ orgId?: string;
1738
+ }): Promise<Asset[]>;
1589
1739
  /** Upload through the buffered multipart endpoint instead of signed storage URLs. */
1590
1740
  uploadDirect(file: Blob, options?: Pick<AssetUploadOptions, "name" | "filename">): Promise<Asset>;
1591
1741
  /** Download an owned asset, following the API's short-lived signed redirect. */
@@ -1602,3 +1752,24 @@ export declare class AssetsClient {
1602
1752
  deleted: boolean;
1603
1753
  }>;
1604
1754
  }
1755
+ export declare class CapabilitiesClient {
1756
+ private readonly client;
1757
+ constructor(client: Client);
1758
+ /** Mint a short-lived bearer token. The token is returned only by this call. */
1759
+ create(options: CreateCapabilityOptions): Promise<{
1760
+ capability: RunCloudCapability;
1761
+ token: string;
1762
+ }>;
1763
+ list(options?: {
1764
+ orgId?: string;
1765
+ active?: boolean;
1766
+ }): Promise<RunCloudCapability[]>;
1767
+ revoke(id: string): Promise<RunCloudCapability>;
1768
+ }
1769
+ export declare class MobileClient {
1770
+ private readonly client;
1771
+ constructor(client: Client);
1772
+ /** Idempotently create a mobile session and install one existing Asset or Xcode build output. */
1773
+ launch(source: MobileLaunchSource, options: MobileLaunchOptions): Promise<MobileLaunch>;
1774
+ getLaunch(id: string): Promise<MobileLaunch>;
1775
+ }