@run-cloud/sdk 0.26.0 → 0.28.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
@@ -51,6 +51,43 @@ await writeFile(
51
51
  await cloud.android.delete(android.id);
52
52
  ```
53
53
 
54
+ ## Xcode builds
55
+
56
+ ```ts
57
+ const submitted = await cloud.xcode.build(process.cwd(), {
58
+ project: "MyApp.xcodeproj",
59
+ scheme: "MyApp",
60
+ sdk: "iphonesimulator",
61
+ idempotencyKey: `xcode-${process.env.GITHUB_SHA ?? "local"}`,
62
+ });
63
+ const completed = await cloud.xcode.wait(submitted.id, {
64
+ onLog: (text) => process.stdout.write(text),
65
+ });
66
+ if (completed.status !== "succeeded") {
67
+ throw new Error(`${completed.failure?.reason}\n${completed.failure?.action}`);
68
+ }
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);
80
+ ```
81
+
82
+ Build records, sanitized logs, failure reasons, and artifacts stay available by
83
+ ID to members of the owning organization. Source packaging honors the root
84
+ `.gitignore`, drops common Xcode and dependency output, and supports explicit
85
+ include, ignore, and additional-file rules. Full options and intentional
86
+ differences are documented at
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.
90
+
54
91
  ## Retry-safe simulator creates
55
92
 
56
93
  Simulator creates are retry-safe when `idempotencyKey` is set. Reuse the same
package/dist/index.d.ts CHANGED
@@ -367,6 +367,7 @@ export interface SandboxHistory {
367
367
  }
368
368
  export interface Asset {
369
369
  id: string;
370
+ orgId?: string | null;
370
371
  name: string;
371
372
  filename: string;
372
373
  contentType: string;
@@ -386,11 +387,21 @@ export interface Asset {
386
387
  retries?: number;
387
388
  throughputBps?: number | null;
388
389
  };
390
+ origin?: {
391
+ kind: "upload";
392
+ } | {
393
+ kind: "xcode-build";
394
+ buildId: string;
395
+ };
396
+ parentAssetId?: string | null;
397
+ immutable?: boolean;
398
+ metadata?: Record<string, unknown>;
389
399
  createdAt: string;
390
400
  /** Authenticated API path; GET follows a short-lived signed storage redirect. */
391
401
  downloadUrl: string;
392
402
  }
393
403
  export interface AssetUploadOptions {
404
+ orgId?: string;
394
405
  name?: string;
395
406
  filename?: string;
396
407
  /** Stable archive/batch identifier shared by every part in one logical upload. */
@@ -420,7 +431,178 @@ export interface MicrophoneAudioResult {
420
431
  pid: number | null;
421
432
  asset: Asset;
422
433
  }
434
+ export type XcodeSdk = "iphonesimulator" | "iphoneos" | "watchsimulator" | "watchos";
435
+ export type XcodeConfiguration = "Debug" | "Release";
436
+ export type XcodeCloudSigningMethod = "app-store-connect" | "release-testing" | "debugging";
437
+ export type XcodeBuildStatus = "uploading" | "queued" | "running" | "succeeded" | "failed" | "cancelled";
438
+ export interface XcodeProjectOptions {
439
+ workspace?: string;
440
+ project?: string;
441
+ scheme?: string;
442
+ sdk?: XcodeSdk;
443
+ configuration?: XcodeConfiguration;
444
+ }
445
+ export interface XcodeGenOptions {
446
+ spec?: string;
447
+ project?: string;
448
+ projectRoot?: string;
449
+ }
450
+ export interface XcodeManualSigningOptions {
451
+ certificateP12Base64: string;
452
+ certificatePassword: string;
453
+ provisioningProfilesBase64?: string[];
454
+ /** Convenience alias for one provisioning profile. */
455
+ provisioningProfileBase64?: string;
456
+ }
457
+ export interface XcodeCloudSigningOptions {
458
+ method: XcodeCloudSigningMethod;
459
+ teamId: string;
460
+ apiKeyId: string;
461
+ apiIssuerId: string;
462
+ apiPrivateKeyBase64: string;
463
+ }
464
+ export interface XcodeAppStoreOptions {
465
+ enabled?: boolean;
466
+ apiKeyId: string;
467
+ apiIssuerId?: string;
468
+ apiPrivateKeyBase64: string;
469
+ waitTimeoutSeconds?: number;
470
+ autoIncrementBuildNumber?: boolean;
471
+ }
472
+ export interface XcodeReactNativeOptions {
473
+ expoAppDir?: string;
474
+ devServerUrl?: string;
475
+ /** Legacy spelling accepted for compatibility. */
476
+ devServerURL?: string;
477
+ }
478
+ export type XcodeUploadOptions = {
479
+ assetName: string;
480
+ signedUploadUrl?: never;
481
+ } | {
482
+ signedUploadUrl: string;
483
+ assetName?: never;
484
+ };
485
+ export interface XcodeAdditionalFile {
486
+ localPath: string;
487
+ remotePath: string;
488
+ }
489
+ export type XcodePathMatcher = string | RegExp | ((relativePath: string) => boolean);
490
+ export interface XcodeSourceOptions {
491
+ ignore?: XcodePathMatcher | XcodePathMatcher[];
492
+ include?: XcodePathMatcher | XcodePathMatcher[];
493
+ additionalFiles?: XcodeAdditionalFile[];
494
+ }
495
+ export interface XcodeBuildOptions extends XcodeProjectOptions {
496
+ orgId?: string;
497
+ xcodegen?: XcodeGenOptions;
498
+ reactNative?: XcodeReactNativeOptions;
499
+ buildSettings?: Record<string, string>;
500
+ signing?: XcodeManualSigningOptions;
501
+ cloudSigning?: XcodeCloudSigningOptions;
502
+ appStore?: XcodeAppStoreOptions;
503
+ /** Legacy spelling accepted for compatibility. */
504
+ appstore?: XcodeAppStoreOptions;
505
+ upload?: XcodeUploadOptions;
506
+ gitInit?: boolean;
507
+ timeoutSeconds?: number;
508
+ source?: XcodeSourceOptions;
509
+ idempotencyKey?: string;
510
+ /** Native shell whose compatible JavaScript bundle should be replaced. */
511
+ reuse?: {
512
+ basisBuildId: string;
513
+ };
514
+ }
515
+ export type XcodeRebundleOptions = Omit<XcodeBuildOptions, "workspace" | "project" | "scheme" | "sdk" | "configuration" | "xcodegen" | "signing" | "cloudSigning" | "appStore" | "appstore" | "reuse">;
516
+ export interface XcodeBuildArtifact {
517
+ kind: "simulator-app" | "device-app" | "signed-ipa" | "watch-app";
518
+ filename: string;
519
+ contentType: string;
520
+ byteSize: number | null;
521
+ available: boolean;
522
+ /** Reusable run.cloud Asset identity for this immutable output. */
523
+ assetId: string | null;
524
+ /** Authenticated endpoint that redirects to a short-lived object URL. */
525
+ downloadUrl: string | null;
526
+ }
527
+ export interface XcodeBuildFailure {
528
+ reason: string;
529
+ category: string;
530
+ stage: string | null;
531
+ action: string;
532
+ }
533
+ export interface XcodeBuild {
534
+ id: string;
535
+ orgId: string;
536
+ createdBy: string;
537
+ idempotencyKey: string;
538
+ status: XcodeBuildStatus;
539
+ result: {
540
+ status: "SUCCEEDED" | "FAILED" | "CANCELLED";
541
+ exitCode: number | null;
542
+ } | null;
543
+ options: Record<string, unknown> & {
544
+ sdk: XcodeSdk;
545
+ };
546
+ source: {
547
+ kind: "source-archive";
548
+ sha256: string;
549
+ byteSize: number;
550
+ };
551
+ artifact: XcodeBuildArtifact;
552
+ reuse: {
553
+ mode: "full" | "rebundle";
554
+ basisBuildId: string | null;
555
+ nativeFingerprint: string | null;
556
+ };
557
+ logs: {
558
+ available: boolean;
559
+ url: string;
560
+ retained: boolean;
561
+ };
562
+ runner: {
563
+ provider: "jenkins";
564
+ job: string;
565
+ queueId: string | null;
566
+ runId: string | null;
567
+ };
568
+ failure: XcodeBuildFailure | null;
569
+ timings: {
570
+ createdAt: string;
571
+ queuedAt: string | null;
572
+ startedAt: string | null;
573
+ completedAt: string | null;
574
+ updatedAt: string;
575
+ };
576
+ }
577
+ export interface XcodeBuildLogChunk {
578
+ text: string;
579
+ nextOffset: number;
580
+ complete: boolean;
581
+ source?: "live" | "retained";
582
+ }
583
+ export interface XcodeBuildEvent {
584
+ sequence: number;
585
+ id: string;
586
+ orgId: string;
587
+ buildId: string;
588
+ type: string;
589
+ status: XcodeBuildStatus;
590
+ stage: string | null;
591
+ data: Record<string, unknown>;
592
+ createdAt: string;
593
+ }
594
+ export interface XcodeBuildEventPage {
595
+ items: XcodeBuildEvent[];
596
+ nextCursor: number;
597
+ }
598
+ export interface XcodeBuildWaitOptions {
599
+ onLog?: (text: string) => void;
600
+ pollIntervalMs?: number;
601
+ timeoutSeconds?: number;
602
+ signal?: AbortSignal;
603
+ }
423
604
  export interface CreateSessionOptions {
605
+ orgId?: string;
424
606
  /** Retry-safe create: reuse this value to receive the original simulator session. */
425
607
  idempotencyKey?: string;
426
608
  model?: string;
@@ -443,6 +625,7 @@ export interface SimulatorStream {
443
625
  }
444
626
  export interface SimulatorSession {
445
627
  id: string;
628
+ orgId: string | null;
446
629
  platform: SimulatorPlatform;
447
630
  status: "active" | "released" | "failed" | string;
448
631
  model?: string | null;
@@ -466,6 +649,65 @@ export interface SimulatorSession {
466
649
  queueAttempts?: number;
467
650
  metering?: Record<string, unknown>;
468
651
  }
652
+ export type RunCloudCapabilityScope = "asset.read" | "mobile.launch" | "xcode.build.create" | "xcode.build.read";
653
+ export interface RunCloudCapabilityResources {
654
+ assetIds?: string[];
655
+ buildIds?: string[];
656
+ idempotencyKeys?: string[];
657
+ }
658
+ export interface RunCloudCapability {
659
+ id: string;
660
+ orgId: string;
661
+ createdBy: string;
662
+ name: string | null;
663
+ scopes: RunCloudCapabilityScope[];
664
+ resources: RunCloudCapabilityResources;
665
+ expiresAt: string;
666
+ lastUsedAt: string | null;
667
+ revokedAt: string | null;
668
+ createdAt: string;
669
+ }
670
+ export interface CreateCapabilityOptions {
671
+ scopes: RunCloudCapabilityScope[];
672
+ resources: RunCloudCapabilityResources;
673
+ orgId?: string;
674
+ name?: string;
675
+ expiresInSeconds?: number;
676
+ }
677
+ export interface MobileLaunch {
678
+ id: string;
679
+ orgId: string;
680
+ idempotencyKey: string;
681
+ status: "provisioning" | "succeeded" | "failed";
682
+ platform: SimulatorPlatform;
683
+ source: {
684
+ assetId: string;
685
+ buildId: string | null;
686
+ };
687
+ sessionId: string;
688
+ session: SimulatorSession | null;
689
+ failure: {
690
+ reason: string;
691
+ code: string;
692
+ action: string;
693
+ } | null;
694
+ createdAt: string;
695
+ completedAt: string | null;
696
+ updatedAt: string;
697
+ }
698
+ export type MobileLaunchSource = {
699
+ assetId: string;
700
+ buildId?: never;
701
+ } | {
702
+ buildId: string;
703
+ assetId?: never;
704
+ };
705
+ export interface MobileLaunchOptions {
706
+ idempotencyKey: string;
707
+ orgId?: string;
708
+ platform?: SimulatorPlatform;
709
+ session?: Omit<CreateSessionOptions, "orgId" | "idempotencyKey" | "installAssets">;
710
+ }
469
711
  /** Confirmation that a URL was dispatched to the authenticated simulator lease. */
470
712
  export interface SimulatorOpenUrlResult {
471
713
  ok: true;
@@ -929,6 +1171,11 @@ export type SimulatorCapacityError = RunCloudError & {
929
1171
  };
930
1172
  /** Narrow a failed simulator create to the public, retry-safe capacity response. */
931
1173
  export declare function isSimulatorCapacityError(error: unknown): error is SimulatorCapacityError;
1174
+ /** Create the source archive accepted by the run.cloud Xcode build endpoint. */
1175
+ export declare function packXcodeSource(sourcePath: string, options?: XcodeSourceOptions): Promise<{
1176
+ archive: Uint8Array;
1177
+ filename: string;
1178
+ }>;
932
1179
  export declare class Client {
933
1180
  readonly ios: IosSimulatorClient;
934
1181
  readonly android: SimulatorClient;
@@ -941,6 +1188,9 @@ export declare class Client {
941
1188
  readonly ci: CiClient;
942
1189
  readonly images: ImageClient;
943
1190
  readonly remotion: RemotionClient;
1191
+ readonly xcode: XcodeBuildsClient;
1192
+ readonly capabilities: CapabilitiesClient;
1193
+ readonly mobile: MobileClient;
944
1194
  private readonly apiKey;
945
1195
  private readonly apiUrl;
946
1196
  private readonly fetchImpl;
@@ -973,7 +1223,7 @@ export declare class Client {
973
1223
  */
974
1224
  setName(name: string): Promise<Account>;
975
1225
  request<T>(method: string, path: string, body?: unknown, headers?: Record<string, string>, abortOptions?: RequestAbortOptions): Promise<T>;
976
- uploadForm<T>(path: string, form: FormData): Promise<T>;
1226
+ uploadForm<T>(path: string, form: FormData, headers?: Record<string, string>): Promise<T>;
977
1227
  requestBytes(path: string, abortOptions?: RequestAbortOptions): Promise<Uint8Array>;
978
1228
  requestTextStream(path: string, signal?: AbortSignal): AsyncGenerator<string>;
979
1229
  /**
@@ -988,6 +1238,31 @@ export declare class Client {
988
1238
  putSigned(url: string, body: Blob, headers: Record<string, string>): Promise<void>;
989
1239
  execStream(path: string, request: Record<string, unknown>, callbacks?: Pick<ExecOptions, "onStdout" | "onStderr" | "signal">): Promise<ExecResult>;
990
1240
  }
1241
+ export declare class XcodeBuildsClient {
1242
+ private readonly client;
1243
+ constructor(client: Client);
1244
+ /** Package a local source tree and submit one idempotent remote Xcode build. */
1245
+ build(sourcePath?: string, options?: XcodeBuildOptions): Promise<XcodeBuild>;
1246
+ /** Reuse a compatible simulator native shell and replace only its embedded JavaScript bundle. */
1247
+ rebundle(sourcePath: string, basisBuildId: string, options?: XcodeRebundleOptions): Promise<XcodeBuild>;
1248
+ get(id: string): Promise<XcodeBuild>;
1249
+ list(options?: {
1250
+ orgId?: string;
1251
+ limit?: number;
1252
+ }): Promise<XcodeBuild[]>;
1253
+ /** Read an ordered, replayable event page. Persist nextCursor after processing the page. */
1254
+ events(options?: {
1255
+ orgId?: string;
1256
+ after?: number;
1257
+ buildId?: string;
1258
+ limit?: number;
1259
+ }): Promise<XcodeBuildEventPage>;
1260
+ logs(id: string, offset?: number, source?: XcodeBuildLogChunk["source"]): Promise<XcodeBuildLogChunk>;
1261
+ /** Poll state and emit sanitized log chunks until the build is terminal. */
1262
+ wait(id: string, options?: XcodeBuildWaitOptions): Promise<XcodeBuild>;
1263
+ cancel(id: string): Promise<XcodeBuild>;
1264
+ downloadArtifact(id: string): Promise<Uint8Array>;
1265
+ }
991
1266
  export declare class SimulatorClient {
992
1267
  protected readonly client: Client;
993
1268
  readonly platform: SimulatorPlatform;
@@ -1000,6 +1275,7 @@ export declare class SimulatorClient {
1000
1275
  setTags(id: string, tags: Record<string, string | null>): Promise<SimulatorSession>;
1001
1276
  list(options?: {
1002
1277
  all?: boolean;
1278
+ orgId?: string;
1003
1279
  }): Promise<SimulatorSession[]>;
1004
1280
  get(id: string): Promise<SimulatorSession>;
1005
1281
  delete(id: string): Promise<SimulatorSession>;
@@ -1062,6 +1338,7 @@ export declare class SimulatorsClient {
1062
1338
  list(options?: {
1063
1339
  platform?: SimulatorPlatform;
1064
1340
  all?: boolean;
1341
+ orgId?: string;
1065
1342
  }): Promise<SimulatorSession[]>;
1066
1343
  get(id: string, options?: {
1067
1344
  platform?: SimulatorPlatform;
@@ -1421,7 +1698,9 @@ export declare class AssetsClient {
1421
1698
  private readonly waitingUploads;
1422
1699
  private readonly defaultUploadRunId;
1423
1700
  constructor(client: Client);
1424
- list(): Promise<Asset[]>;
1701
+ list(options?: {
1702
+ orgId?: string;
1703
+ }): Promise<Asset[]>;
1425
1704
  /** Upload through the buffered multipart endpoint instead of signed storage URLs. */
1426
1705
  uploadDirect(file: Blob, options?: Pick<AssetUploadOptions, "name" | "filename">): Promise<Asset>;
1427
1706
  /** Download an owned asset, following the API's short-lived signed redirect. */
@@ -1438,3 +1717,24 @@ export declare class AssetsClient {
1438
1717
  deleted: boolean;
1439
1718
  }>;
1440
1719
  }
1720
+ export declare class CapabilitiesClient {
1721
+ private readonly client;
1722
+ constructor(client: Client);
1723
+ /** Mint a short-lived bearer token. The token is returned only by this call. */
1724
+ create(options: CreateCapabilityOptions): Promise<{
1725
+ capability: RunCloudCapability;
1726
+ token: string;
1727
+ }>;
1728
+ list(options?: {
1729
+ orgId?: string;
1730
+ active?: boolean;
1731
+ }): Promise<RunCloudCapability[]>;
1732
+ revoke(id: string): Promise<RunCloudCapability>;
1733
+ }
1734
+ export declare class MobileClient {
1735
+ private readonly client;
1736
+ constructor(client: Client);
1737
+ /** Idempotently create a mobile session and install one existing Asset or Xcode build output. */
1738
+ launch(source: MobileLaunchSource, options: MobileLaunchOptions): Promise<MobileLaunch>;
1739
+ getLaunch(id: string): Promise<MobileLaunch>;
1740
+ }