From 7073e407d339b00f628bc6471f0e8e6235e92257 Mon Sep 17 00:00:00 2001
From: Gabriel Donadel <donadeldev@gmail.com>
Date: Thu, 6 Mar 2025 10:45:34 -0500
Subject: [PATCH 1/8] Add share command

---
 packages/eas-cli/src/commands/share.ts        | 157 ++++++++++++++++++
 .../graphql/mutations/ShareBuildMutation.ts   |  42 +++++
 2 files changed, 199 insertions(+)
 create mode 100644 packages/eas-cli/src/commands/share.ts
 create mode 100644 packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts

diff --git a/packages/eas-cli/src/commands/share.ts b/packages/eas-cli/src/commands/share.ts
new file mode 100644
index 0000000000..aceb0b8ff4
--- /dev/null
+++ b/packages/eas-cli/src/commands/share.ts
@@ -0,0 +1,157 @@
+import { Platform } from '@expo/eas-build-job';
+import { Flags } from '@oclif/core';
+import fg from 'fast-glob';
+import fs from 'fs-extra';
+import path from 'path';
+
+import EasCommand from '../commandUtils/EasCommand';
+import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
+import { EASNonInteractiveFlag } from '../commandUtils/flags';
+import { UploadSessionType } from '../graphql/generated';
+import { ShareBuildMutation } from '../graphql/mutations/ShareBuildMutation';
+import Log from '../log';
+import { promptAsync } from '../prompts';
+import { uploadFileAtPathToGCSAsync } from '../uploads';
+import { createProgressTracker } from '../utils/progress';
+
+export default class BuildUpload extends EasCommand {
+  static override description = 'upload a local build and generate a sharable link';
+
+  static override flags = {
+    platform: Flags.enum<Platform.IOS | Platform.ANDROID>({
+      char: 'p',
+      options: [Platform.IOS, Platform.ANDROID],
+    }),
+    'build-path': Flags.string({
+      description: 'Path for the local build',
+    }),
+    ...EASNonInteractiveFlag,
+  };
+
+  static override contextDefinition = {
+    ...this.ContextOptions.ProjectId,
+    ...this.ContextOptions.LoggedIn,
+  };
+
+  async runAsync(): Promise<void> {
+    const { flags } = await this.parse(BuildUpload);
+    const { 'build-path': buildPath } = flags;
+    const {
+      projectId,
+      loggedIn: { graphqlClient },
+    } = await this.getContextAsync(BuildUpload, {
+      nonInteractive: false,
+    });
+
+    const platform = await this.selectPlatformAsync(flags.platform);
+    const localBuildPath = await resolveLocalBuildPathAsync({
+      platform,
+      buildPath,
+    });
+
+    Log.log('Uploading your app archive to EAS Share');
+    const bucketKey = await uploadAppArchiveAsync(graphqlClient, localBuildPath);
+
+    // @TODO: use Share build mutation
+    const { debugInfoUrl } = await ShareBuildMutation.uploadLocalBuildAsync(
+      graphqlClient,
+      projectId,
+      { bucketKey },
+      {
+        // @TODO: read the fingerprint from the local build
+        hash: '',
+      }
+    );
+
+    Log.withTick(`Here is a sharable link of your build: ${debugInfoUrl}`);
+  }
+
+  private async selectPlatformAsync(platform?: Platform): Promise<Platform> {
+    if (platform) {
+      return platform;
+    }
+    const { resolvedPlatform } = await promptAsync({
+      type: 'select',
+      message: 'Select platform',
+      name: 'resolvedPlatform',
+      choices: [
+        { title: 'Android', value: Platform.ANDROID },
+        { title: 'iOS', value: Platform.IOS },
+      ],
+    });
+    return resolvedPlatform;
+  }
+}
+
+async function resolveLocalBuildPathAsync({
+  platform,
+  buildPath,
+}: {
+  platform: Platform;
+  buildPath?: string;
+}): Promise<string> {
+  const applicationArchivePatternOrPath =
+    buildPath ?? platform === Platform.ANDROID
+      ? 'android/app/build/outputs/**/*.{apk,aab}'
+      : 'ios/build/Build/Products/*simulator/*.app';
+
+  const applicationArchives = await findArtifactsAsync({
+    rootDir: process.cwd(),
+    patternOrPath: applicationArchivePatternOrPath,
+  });
+
+  const count = applicationArchives.length;
+  Log.log(
+    `Found ${count} application archive${count > 1 ? 's' : ''}:\n- ${applicationArchives.join(
+      '\n- '
+    )}`
+  );
+  return applicationArchives[0];
+}
+
+async function findArtifactsAsync({
+  rootDir,
+  patternOrPath,
+}: {
+  rootDir: string;
+  patternOrPath: string;
+}): Promise<string[]> {
+  const files: string[] = path.isAbsolute(patternOrPath)
+    ? (await fs.pathExists(patternOrPath))
+      ? [patternOrPath]
+      : []
+    : await fg(patternOrPath, { cwd: rootDir, onlyFiles: false });
+  if (files.length === 0) {
+    throw new Error(`Found no application archives for "${patternOrPath}".`);
+  }
+
+  return files.map(filePath => {
+    // User may provide an absolute path as input in which case
+    // fg will return an absolute path.
+    if (path.isAbsolute(filePath)) {
+      return filePath;
+    }
+
+    // User may also provide a relative path in which case
+    // fg will return a path relative to rootDir.
+    return path.join(rootDir, filePath);
+  });
+}
+
+async function uploadAppArchiveAsync(
+  graphqlClient: ExpoGraphqlClient,
+  path: string
+): Promise<string> {
+  const fileSize = (await fs.stat(path)).size;
+  const bucketKey = await uploadFileAtPathToGCSAsync(
+    graphqlClient,
+    UploadSessionType.EasSubmitGcsAppArchive,
+    path,
+    createProgressTracker({
+      total: fileSize,
+      message: 'Uploading to EAS Share',
+      completedMessage: 'Uploaded to EAS Share',
+    })
+  );
+  return bucketKey;
+}
diff --git a/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts b/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts
new file mode 100644
index 0000000000..2514bf81ab
--- /dev/null
+++ b/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts
@@ -0,0 +1,42 @@
+import { FingerprintSource } from '@expo/eas-build-job';
+import { print } from 'graphql';
+import gql from 'graphql-tag';
+
+import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
+import { withErrorHandlingAsync } from '../client';
+import { CreateFingeprintMutation, FingerprintFragment } from '../generated';
+import { FingerprintFragmentNode } from '../types/Fingerprint';
+
+export const ShareBuildMutation = {
+  async uploadLocalBuildAsync(
+    graphqlClient: ExpoGraphqlClient,
+    appId: string,
+    buildSource: {
+      bucketKey: string;
+    },
+    fingerprintData: { hash: string; source?: FingerprintSource }
+  ): Promise<FingerprintFragment> {
+    const data = await withErrorHandlingAsync(
+      graphqlClient
+        .mutation<CreateFingeprintMutation>(
+          gql`
+            mutation CreateFingeprintMutation(
+              $fingerprintData: CreateFingerprintInput!
+              $appId: ID!
+            ) {
+              fingerprint {
+                createOrGetExistingFingerprint(fingerprintData: $fingerprintData, appId: $appId) {
+                  id
+                  ...FingerprintFragment
+                }
+              }
+            }
+            ${print(FingerprintFragmentNode)}
+          `,
+          { appId, fingerprintData }
+        )
+        .toPromise()
+    );
+    return data.fingerprint.createOrGetExistingFingerprint;
+  },
+};

From cad966e0757a2859bc32533f7dd63f498768209f Mon Sep 17 00:00:00 2001
From: Gabriel Donadel <donadeldev@gmail.com>
Date: Mon, 10 Mar 2025 14:20:31 -0400
Subject: [PATCH 2/8] Use EasShareGcsAppArchive upload type

---
 packages/eas-cli/graphql.schema.json      | 1543 ++++++++++++++++++---
 packages/eas-cli/src/commands/share.ts    |    2 +-
 packages/eas-cli/src/graphql/generated.ts |  161 ++-
 3 files changed, 1523 insertions(+), 183 deletions(-)

diff --git a/packages/eas-cli/graphql.schema.json b/packages/eas-cli/graphql.schema.json
index ef6a2413c7..e3af8f6664 100644
--- a/packages/eas-cli/graphql.schema.json
+++ b/packages/eas-cli/graphql.schema.json
@@ -1893,6 +1893,18 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "pendingSentryInstallation",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "OBJECT",
+              "name": "PendingSentryInstallation",
+              "ofType": null
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "profileImageUrl",
             "description": null,
@@ -1941,6 +1953,18 @@
             "isDeprecated": true,
             "deprecationReason": "Legacy access tokens are deprecated"
           },
+          {
+            "name": "sentryInstallation",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "OBJECT",
+              "name": "SentryInstallation",
+              "ofType": null
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "snacks",
             "description": "Snacks associated with this account",
@@ -6665,7 +6689,7 @@
         "fields": [
           {
             "name": "createAndroidFcm",
-            "description": "Create an FCM credential",
+            "description": "Create an FCM V0/Legacy credential",
             "args": [
               {
                 "name": "accountId",
@@ -6709,12 +6733,12 @@
                 "ofType": null
               }
             },
-            "isDeprecated": false,
-            "deprecationReason": null
+            "isDeprecated": true,
+            "deprecationReason": "FCM Legacy credentials are no longer supported by Google. Use createFcmV1Credential instead."
           },
           {
             "name": "deleteAndroidFcm",
-            "description": "Delete an FCM credential",
+            "description": "Delete an FCM V0/Legacy credential",
             "args": [
               {
                 "name": "id",
@@ -9703,6 +9727,18 @@
                 "isDeprecated": false,
                 "deprecationReason": null
               },
+              {
+                "name": "filter",
+                "description": null,
+                "type": {
+                  "kind": "INPUT_OBJECT",
+                  "name": "RuntimeFilterInput",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
               {
                 "name": "first",
                 "description": null,
@@ -9772,6 +9808,18 @@
             "isDeprecated": true,
             "deprecationReason": "Classic updates have been deprecated."
           },
+          {
+            "name": "sentryProject",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "OBJECT",
+              "name": "SentryProject",
+              "ofType": null
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "slug",
             "description": null,
@@ -18475,6 +18523,18 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "cliVersion",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "SCALAR",
+              "name": "String",
+              "ofType": null
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "completedAt",
             "description": null,
@@ -18668,8 +18728,8 @@
               "name": "String",
               "ofType": null
             },
-            "isDeprecated": false,
-            "deprecationReason": null
+            "isDeprecated": true,
+            "deprecationReason": "Use 'githubRepository' field instead"
           },
           {
             "name": "id",
@@ -23886,6 +23946,65 @@
         "enumValues": null,
         "possibleTypes": null
       },
+      {
+        "kind": "INPUT_OBJECT",
+        "name": "CreateSentryProjectInput",
+        "description": null,
+        "fields": null,
+        "inputFields": [
+          {
+            "name": "appId",
+            "description": null,
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "sentryProjectId",
+            "description": null,
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "sentryProjectSlug",
+            "description": null,
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "interfaces": null,
+        "enumValues": null,
+        "possibleTypes": null
+      },
       {
         "kind": "INPUT_OBJECT",
         "name": "CreateSharedEnvironmentVariableInput",
@@ -25356,7 +25475,7 @@
       },
       {
         "kind": "OBJECT",
-        "name": "DeleteUpdateBranchResult",
+        "name": "DeleteSentryProjectResult",
         "description": null,
         "fields": [
           {
@@ -25383,7 +25502,7 @@
       },
       {
         "kind": "OBJECT",
-        "name": "DeleteUpdateChannelResult",
+        "name": "DeleteUpdateBranchResult",
         "description": null,
         "fields": [
           {
@@ -25410,11 +25529,11 @@
       },
       {
         "kind": "OBJECT",
-        "name": "DeleteUpdateGroupResult",
+        "name": "DeleteUpdateChannelResult",
         "description": null,
         "fields": [
           {
-            "name": "group",
+            "name": "id",
             "description": null,
             "args": [],
             "type": {
@@ -25437,11 +25556,11 @@
       },
       {
         "kind": "OBJECT",
-        "name": "DeleteWebhookResult",
+        "name": "DeleteUpdateGroupResult",
         "description": null,
         "fields": [
           {
-            "name": "id",
+            "name": "group",
             "description": null,
             "args": [],
             "type": {
@@ -25464,25 +25583,9 @@
       },
       {
         "kind": "OBJECT",
-        "name": "DeleteWorkerDeploymentResult",
+        "name": "DeleteWebhookResult",
         "description": null,
         "fields": [
-          {
-            "name": "deploymentIdentifier",
-            "description": null,
-            "args": [],
-            "type": {
-              "kind": "NON_NULL",
-              "name": null,
-              "ofType": {
-                "kind": "SCALAR",
-                "name": "WorkerDeploymentIdentifier",
-                "ofType": null
-              }
-            },
-            "isDeprecated": false,
-            "deprecationReason": null
-          },
           {
             "name": "id",
             "description": null,
@@ -25507,121 +25610,164 @@
       },
       {
         "kind": "OBJECT",
-        "name": "Deployment",
-        "description": "Represents a Deployment - a set of Builds with the same Runtime Version and Channel",
+        "name": "DeleteWorkerDeploymentResult",
+        "description": null,
         "fields": [
           {
-            "name": "buildCount",
-            "description": null,
-            "args": [
-              {
-                "name": "statuses",
-                "description": null,
-                "type": {
-                  "kind": "LIST",
-                  "name": null,
-                  "ofType": {
-                    "kind": "NON_NULL",
-                    "name": null,
-                    "ofType": {
-                      "kind": "ENUM",
-                      "name": "BuildStatus",
-                      "ofType": null
-                    }
-                  }
-                },
-                "defaultValue": null,
-                "isDeprecated": false,
-                "deprecationReason": null
-              }
-            ],
-            "type": {
-              "kind": "NON_NULL",
-              "name": null,
-              "ofType": {
-                "kind": "SCALAR",
-                "name": "Int",
-                "ofType": null
-              }
-            },
-            "isDeprecated": false,
-            "deprecationReason": null
-          },
-          {
-            "name": "builds",
-            "description": null,
-            "args": [
-              {
-                "name": "after",
-                "description": null,
-                "type": {
-                  "kind": "SCALAR",
-                  "name": "String",
-                  "ofType": null
-                },
-                "defaultValue": null,
-                "isDeprecated": false,
-                "deprecationReason": null
-              },
-              {
-                "name": "before",
-                "description": null,
-                "type": {
-                  "kind": "SCALAR",
-                  "name": "String",
-                  "ofType": null
-                },
-                "defaultValue": null,
-                "isDeprecated": false,
-                "deprecationReason": null
-              },
-              {
-                "name": "first",
-                "description": null,
-                "type": {
-                  "kind": "SCALAR",
-                  "name": "Int",
-                  "ofType": null
-                },
-                "defaultValue": null,
-                "isDeprecated": false,
-                "deprecationReason": null
-              },
-              {
-                "name": "last",
-                "description": null,
-                "type": {
-                  "kind": "SCALAR",
-                  "name": "Int",
-                  "ofType": null
-                },
-                "defaultValue": null,
-                "isDeprecated": false,
-                "deprecationReason": null
-              }
-            ],
-            "type": {
-              "kind": "NON_NULL",
-              "name": null,
-              "ofType": {
-                "kind": "OBJECT",
-                "name": "DeploymentBuildsConnection",
-                "ofType": null
-              }
-            },
-            "isDeprecated": false,
-            "deprecationReason": null
-          },
-          {
-            "name": "channel",
+            "name": "deploymentIdentifier",
             "description": null,
             "args": [],
             "type": {
               "kind": "NON_NULL",
               "name": null,
               "ofType": {
-                "kind": "OBJECT",
-                "name": "UpdateChannel",
+                "kind": "SCALAR",
+                "name": "WorkerDeploymentIdentifier",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "id",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
+      {
+        "kind": "OBJECT",
+        "name": "Deployment",
+        "description": "Represents a Deployment - a set of Builds with the same Runtime Version and Channel",
+        "fields": [
+          {
+            "name": "buildCount",
+            "description": null,
+            "args": [
+              {
+                "name": "statuses",
+                "description": null,
+                "type": {
+                  "kind": "LIST",
+                  "name": null,
+                  "ofType": {
+                    "kind": "NON_NULL",
+                    "name": null,
+                    "ofType": {
+                      "kind": "ENUM",
+                      "name": "BuildStatus",
+                      "ofType": null
+                    }
+                  }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Int",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "builds",
+            "description": null,
+            "args": [
+              {
+                "name": "after",
+                "description": null,
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "String",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "before",
+                "description": null,
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "String",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "first",
+                "description": null,
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Int",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "last",
+                "description": null,
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Int",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "DeploymentBuildsConnection",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "channel",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "UpdateChannel",
                 "ofType": null
               }
             },
@@ -27284,6 +27430,18 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "LogRocketOrganizationEntity",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "LogRocketProjectEntity",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "UserInvitationEntity",
             "description": null,
@@ -30148,6 +30306,65 @@
         "enumValues": null,
         "possibleTypes": null
       },
+      {
+        "kind": "OBJECT",
+        "name": "GenerateSentryTokenResult",
+        "description": null,
+        "fields": [
+          {
+            "name": "installationId",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "orgSlug",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "token",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
       {
         "kind": "OBJECT",
         "name": "GetSignedAssetUploadSpecificationsResult",
@@ -36863,6 +37080,81 @@
         "enumValues": null,
         "possibleTypes": null
       },
+      {
+        "kind": "INPUT_OBJECT",
+        "name": "LinkSentryInstallationToExpoAccountInput",
+        "description": null,
+        "fields": null,
+        "inputFields": [
+          {
+            "name": "accountId",
+            "description": null,
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "code",
+            "description": null,
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "installationId",
+            "description": null,
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "sentryOrgSlug",
+            "description": null,
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "interfaces": null,
+        "enumValues": null,
+        "possibleTypes": null
+      },
       {
         "kind": "INPUT_OBJECT",
         "name": "LinkSharedEnvironmentVariableInput",
@@ -39446,6 +39738,97 @@
         "enumValues": null,
         "possibleTypes": null
       },
+      {
+        "kind": "OBJECT",
+        "name": "PendingSentryInstallation",
+        "description": null,
+        "fields": [
+          {
+            "name": "account",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "Account",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "createdAt",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "DateTime",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "id",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "installationId",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "orgSlug",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
       {
         "kind": "ENUM",
         "name": "Permission",
@@ -40352,6 +40735,26 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "platform",
+            "description": null,
+            "type": {
+              "kind": "LIST",
+              "name": null,
+              "ofType": {
+                "kind": "NON_NULL",
+                "name": null,
+                "ofType": {
+                  "kind": "ENUM",
+                  "name": "UserAgentPlatform",
+                  "ofType": null
+                }
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "requestId",
             "description": null,
@@ -41317,7 +41720,7 @@
           },
           {
             "name": "androidFcm",
-            "description": "Mutations that modify an FCM credential",
+            "description": "Mutations that modify an FCM V0/Legacy credential",
             "args": [],
             "type": {
               "kind": "NON_NULL",
@@ -41993,6 +42396,38 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "sentryInstallation",
+            "description": "Mutations for Sentry installations",
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "SentryInstallationMutation",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "sentryProject",
+            "description": "Mutations for Sentry projects",
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "SentryProjectMutation",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "submission",
             "description": "Mutations that modify an EAS Submit submission",
@@ -43318,6 +43753,22 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "isFingerprint",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "updatedAt",
             "description": null,
@@ -43603,6 +44054,26 @@
             "defaultValue": null,
             "isDeprecated": false,
             "deprecationReason": null
+          },
+          {
+            "name": "runtimeVersions",
+            "description": null,
+            "type": {
+              "kind": "LIST",
+              "name": null,
+              "ofType": {
+                "kind": "NON_NULL",
+                "name": null,
+                "ofType": {
+                  "kind": "SCALAR",
+                  "name": "String",
+                  "ofType": null
+                }
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
           }
         ],
         "interfaces": null,
@@ -44642,52 +45113,311 @@
       },
       {
         "kind": "OBJECT",
-        "name": "SecondFactorInitiationResult",
+        "name": "SecondFactorInitiationResult",
+        "description": null,
+        "fields": [
+          {
+            "name": "configurationResults",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "SecondFactorDeviceConfigurationResult",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "plaintextBackupCodes",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "SCALAR",
+                    "name": "String",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
+      {
+        "kind": "ENUM",
+        "name": "SecondFactorMethod",
+        "description": null,
+        "fields": null,
+        "inputFields": null,
+        "interfaces": null,
+        "enumValues": [
+          {
+            "name": "AUTHENTICATOR",
+            "description": "Google Authenticator (TOTP)",
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "SMS",
+            "description": "SMS",
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "possibleTypes": null
+      },
+      {
+        "kind": "OBJECT",
+        "name": "SecondFactorRegenerateBackupCodesResult",
+        "description": null,
+        "fields": [
+          {
+            "name": "plaintextBackupCodes",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "SCALAR",
+                    "name": "String",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
+      {
+        "kind": "OBJECT",
+        "name": "SentryInstallation",
+        "description": null,
+        "fields": [
+          {
+            "name": "account",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "Account",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "createdAt",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "DateTime",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "id",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "installationId",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "orgSlug",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
+      {
+        "kind": "OBJECT",
+        "name": "SentryInstallationMutation",
         "description": null,
         "fields": [
           {
-            "name": "configurationResults",
-            "description": null,
-            "args": [],
-            "type": {
-              "kind": "NON_NULL",
-              "name": null,
-              "ofType": {
-                "kind": "LIST",
-                "name": null,
-                "ofType": {
+            "name": "confirmPendingSentryInstallation",
+            "description": "Confirm a pending Sentry installation",
+            "args": [
+              {
+                "name": "installationId",
+                "description": null,
+                "type": {
                   "kind": "NON_NULL",
                   "name": null,
                   "ofType": {
-                    "kind": "OBJECT",
-                    "name": "SecondFactorDeviceConfigurationResult",
+                    "kind": "SCALAR",
+                    "name": "ID",
                     "ofType": null
                   }
-                }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "SentryInstallation",
+                "ofType": null
               }
             },
             "isDeprecated": false,
             "deprecationReason": null
           },
           {
-            "name": "plaintextBackupCodes",
-            "description": null,
-            "args": [],
+            "name": "generateSentryToken",
+            "description": "Generate a Sentry token for an installation",
+            "args": [
+              {
+                "name": "accountId",
+                "description": null,
+                "type": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "SCALAR",
+                    "name": "ID",
+                    "ofType": null
+                  }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
             "type": {
               "kind": "NON_NULL",
               "name": null,
               "ofType": {
-                "kind": "LIST",
-                "name": null,
-                "ofType": {
+                "kind": "OBJECT",
+                "name": "GenerateSentryTokenResult",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "linkSentryInstallationToExpoAccount",
+            "description": "Link a Sentry installation to an Expo account",
+            "args": [
+              {
+                "name": "input",
+                "description": null,
+                "type": {
                   "kind": "NON_NULL",
                   "name": null,
                   "ofType": {
-                    "kind": "SCALAR",
-                    "name": "String",
+                    "kind": "INPUT_OBJECT",
+                    "name": "LinkSentryInstallationToExpoAccountInput",
                     "ofType": null
                   }
-                }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "PendingSentryInstallation",
+                "ofType": null
               }
             },
             "isDeprecated": false,
@@ -44700,52 +45430,194 @@
         "possibleTypes": null
       },
       {
-        "kind": "ENUM",
-        "name": "SecondFactorMethod",
+        "kind": "OBJECT",
+        "name": "SentryProject",
         "description": null,
-        "fields": null,
-        "inputFields": null,
-        "interfaces": null,
-        "enumValues": [
+        "fields": [
           {
-            "name": "AUTHENTICATOR",
-            "description": "Google Authenticator (TOTP)",
+            "name": "app",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "App",
+                "ofType": null
+              }
+            },
             "isDeprecated": false,
             "deprecationReason": null
           },
           {
-            "name": "SMS",
-            "description": "SMS",
+            "name": "createdAt",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "DateTime",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "id",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "sentryInstallationId",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "ID",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "sentryProjectId",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "sentryProjectSlug",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "updatedAt",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "DateTime",
+                "ofType": null
+              }
+            },
             "isDeprecated": false,
             "deprecationReason": null
           }
         ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
         "possibleTypes": null
       },
       {
         "kind": "OBJECT",
-        "name": "SecondFactorRegenerateBackupCodesResult",
+        "name": "SentryProjectMutation",
         "description": null,
         "fields": [
           {
-            "name": "plaintextBackupCodes",
-            "description": null,
-            "args": [],
+            "name": "createSentryProject",
+            "description": "Create a Sentry project",
+            "args": [
+              {
+                "name": "input",
+                "description": null,
+                "type": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "INPUT_OBJECT",
+                    "name": "CreateSentryProjectInput",
+                    "ofType": null
+                  }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
             "type": {
               "kind": "NON_NULL",
               "name": null,
               "ofType": {
-                "kind": "LIST",
-                "name": null,
-                "ofType": {
+                "kind": "OBJECT",
+                "name": "SentryProject",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "deleteSentryProject",
+            "description": "Delete a Sentry project by ID",
+            "args": [
+              {
+                "name": "sentryProjectId",
+                "description": null,
+                "type": {
                   "kind": "NON_NULL",
                   "name": null,
                   "ofType": {
                     "kind": "SCALAR",
-                    "name": "String",
+                    "name": "ID",
                     "ofType": null
                   }
-                }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "DeleteSentryProjectResult",
+                "ofType": null
               }
             },
             "isDeprecated": false,
@@ -49935,6 +50807,12 @@
             "isDeprecated": true,
             "deprecationReason": "Use EAS_BUILD_GCS_PROJECT_SOURCES instead."
           },
+          {
+            "name": "EAS_SHARE_GCS_APP_ARCHIVE",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "EAS_SUBMIT_APP_ARCHIVE",
             "description": null,
@@ -52225,6 +53103,41 @@
         ],
         "possibleTypes": null
       },
+      {
+        "kind": "ENUM",
+        "name": "UserAgentPlatform",
+        "description": null,
+        "fields": null,
+        "inputFields": null,
+        "interfaces": null,
+        "enumValues": [
+          {
+            "name": "ANDROID",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "APPLE",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "UNKNOWN",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "WEB",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "possibleTypes": null
+      },
       {
         "kind": "OBJECT",
         "name": "UserAppPinMutation",
@@ -56974,6 +57887,22 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "platform",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "ENUM",
+                "name": "UserAgentPlatform",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "region",
             "description": null,
@@ -57395,6 +58324,104 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "byPathname",
+            "description": null,
+            "args": [
+              {
+                "name": "limit",
+                "description": null,
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Int",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "orderBy",
+                "description": null,
+                "type": {
+                  "kind": "INPUT_OBJECT",
+                  "name": "RequestsOrderBy",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "WorkerDeploymentRequestsPathnameEdge",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "byPlatform",
+            "description": null,
+            "args": [
+              {
+                "name": "limit",
+                "description": null,
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Int",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "orderBy",
+                "description": null,
+                "type": {
+                  "kind": "INPUT_OBJECT",
+                  "name": "RequestsOrderBy",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "WorkerDeploymentRequestsPlatformEdge",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "byResponseType",
             "description": null,
@@ -58440,6 +59467,92 @@
         "enumValues": null,
         "possibleTypes": null
       },
+      {
+        "kind": "OBJECT",
+        "name": "WorkerDeploymentRequestsPathnameEdge",
+        "description": null,
+        "fields": [
+          {
+            "name": "node",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "WorkerDeploymentRequestsAggregationNode",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "pathname",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
+      {
+        "kind": "OBJECT",
+        "name": "WorkerDeploymentRequestsPlatformEdge",
+        "description": null,
+        "fields": [
+          {
+            "name": "node",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "WorkerDeploymentRequestsAggregationNode",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "platform",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "ENUM",
+                "name": "UserAgentPlatform",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
       {
         "kind": "OBJECT",
         "name": "WorkerDeploymentRequestsResponseTypeEdge",
@@ -58671,6 +59784,54 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "byPathname",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "WorkerDeploymentRequestsPathnameEdge",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "byPlatform",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "WorkerDeploymentRequestsPlatformEdge",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "byResponseType",
             "description": null,
@@ -59700,6 +60861,12 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "FINGERPRINT",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "GET_BUILD",
             "description": null,
@@ -60490,6 +61657,18 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "triggeringLabelName",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "SCALAR",
+              "name": "String",
+              "ofType": null
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "updatedAt",
             "description": null,
@@ -60914,6 +62093,12 @@
         "inputFields": null,
         "interfaces": null,
         "enumValues": [
+          {
+            "name": "GITHUB_PULL_REQUEST_LABELED",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "GITHUB_PULL_REQUEST_OPENED",
             "description": null,
diff --git a/packages/eas-cli/src/commands/share.ts b/packages/eas-cli/src/commands/share.ts
index aceb0b8ff4..f3475bcd08 100644
--- a/packages/eas-cli/src/commands/share.ts
+++ b/packages/eas-cli/src/commands/share.ts
@@ -145,7 +145,7 @@ async function uploadAppArchiveAsync(
   const fileSize = (await fs.stat(path)).size;
   const bucketKey = await uploadFileAtPathToGCSAsync(
     graphqlClient,
-    UploadSessionType.EasSubmitGcsAppArchive,
+    UploadSessionType.EasShareGcsAppArchive,
     path,
     createProgressTracker({
       total: fileSize,
diff --git a/packages/eas-cli/src/graphql/generated.ts b/packages/eas-cli/src/graphql/generated.ts
index a71f81f8d9..127ec1f441 100644
--- a/packages/eas-cli/src/graphql/generated.ts
+++ b/packages/eas-cli/src/graphql/generated.ts
@@ -147,10 +147,12 @@ export type Account = {
   owner?: Maybe<User>;
   /** Owning UserActor of this account if personal account */
   ownerUserActor?: Maybe<UserActor>;
+  pendingSentryInstallation?: Maybe<PendingSentryInstallation>;
   profileImageUrl: Scalars['String']['output'];
   pushSecurityEnabled: Scalars['Boolean']['output'];
   /** @deprecated Legacy access tokens are deprecated */
   requiresAccessTokenForPushSecurity: Scalars['Boolean']['output'];
+  sentryInstallation?: Maybe<SentryInstallation>;
   /** Snacks associated with this account */
   snacks: Array<Snack>;
   /** SSO configuration for this account */
@@ -1053,9 +1055,12 @@ export type AndroidFcmInput = {
 
 export type AndroidFcmMutation = {
   __typename?: 'AndroidFcmMutation';
-  /** Create an FCM credential */
+  /**
+   * Create an FCM V0/Legacy credential
+   * @deprecated FCM Legacy credentials are no longer supported by Google. Use createFcmV1Credential instead.
+   */
   createAndroidFcm: AndroidFcm;
-  /** Delete an FCM credential */
+  /** Delete an FCM V0/Legacy credential */
   deleteAndroidFcm: DeleteAndroidFcmResult;
 };
 
@@ -1342,6 +1347,7 @@ export type App = Project & {
    * @deprecated Classic updates have been deprecated.
    */
   sdkVersion: Scalars['String']['output'];
+  sentryProject?: Maybe<SentryProject>;
   slug: Scalars['String']['output'];
   /** EAS Submissions associated with this app */
   submissions: Array<Submission>;
@@ -1525,6 +1531,7 @@ export type AppLikedByArgs = {
 export type AppRuntimesArgs = {
   after?: InputMaybe<Scalars['String']['input']>;
   before?: InputMaybe<Scalars['String']['input']>;
+  filter?: InputMaybe<RuntimeFilterInput>;
   first?: InputMaybe<Scalars['Int']['input']>;
   last?: InputMaybe<Scalars['Int']['input']>;
 };
@@ -2749,6 +2756,7 @@ export type Build = ActivityTimelineProjectActivity & BuildOrBuildJob & {
   /** @deprecated Use 'updateChannel' field instead. */
   channel?: Maybe<Scalars['String']['output']>;
   childBuild?: Maybe<Build>;
+  cliVersion?: Maybe<Scalars['String']['output']>;
   completedAt?: Maybe<Scalars['DateTime']['output']>;
   createdAt: Scalars['DateTime']['output'];
   customNodeVersion?: Maybe<Scalars['String']['output']>;
@@ -2764,6 +2772,7 @@ export type Build = ActivityTimelineProjectActivity & BuildOrBuildJob & {
   gitCommitHash?: Maybe<Scalars['String']['output']>;
   gitCommitMessage?: Maybe<Scalars['String']['output']>;
   gitRef?: Maybe<Scalars['String']['output']>;
+  /** @deprecated Use 'githubRepository' field instead */
   githubRepositoryOwnerAndName?: Maybe<Scalars['String']['output']>;
   id: Scalars['ID']['output'];
   /** Queue position is 1-indexed */
@@ -3472,6 +3481,12 @@ export type CreateIosSubmissionInput = {
   submittedBuildId?: InputMaybe<Scalars['ID']['input']>;
 };
 
+export type CreateSentryProjectInput = {
+  appId: Scalars['ID']['input'];
+  sentryProjectId: Scalars['String']['input'];
+  sentryProjectSlug: Scalars['String']['input'];
+};
+
 export type CreateSharedEnvironmentVariableInput = {
   environments?: InputMaybe<Array<EnvironmentVariableEnvironment>>;
   fileName?: InputMaybe<Scalars['String']['input']>;
@@ -3691,6 +3706,11 @@ export type DeleteSsoUserResult = {
   id: Scalars['ID']['output'];
 };
 
+export type DeleteSentryProjectResult = {
+  __typename?: 'DeleteSentryProjectResult';
+  id: Scalars['ID']['output'];
+};
+
 export type DeleteUpdateBranchResult = {
   __typename?: 'DeleteUpdateBranchResult';
   id: Scalars['ID']['output'];
@@ -4001,6 +4021,8 @@ export enum EntityTypeName {
   CustomerEntity = 'CustomerEntity',
   GoogleServiceAccountKeyEntity = 'GoogleServiceAccountKeyEntity',
   IosAppCredentialsEntity = 'IosAppCredentialsEntity',
+  LogRocketOrganizationEntity = 'LogRocketOrganizationEntity',
+  LogRocketProjectEntity = 'LogRocketProjectEntity',
   UserInvitationEntity = 'UserInvitationEntity',
   UserPermissionEntity = 'UserPermissionEntity',
   WorkerCustomDomainEntity = 'WorkerCustomDomainEntity',
@@ -4388,6 +4410,13 @@ export type GenerateLogRocketReplayTokenResult = {
   replayToken: Scalars['String']['output'];
 };
 
+export type GenerateSentryTokenResult = {
+  __typename?: 'GenerateSentryTokenResult';
+  installationId: Scalars['ID']['output'];
+  orgSlug: Scalars['String']['output'];
+  token: Scalars['String']['output'];
+};
+
 export type GetSignedAssetUploadSpecificationsResult = {
   __typename?: 'GetSignedAssetUploadSpecificationsResult';
   specifications: Array<Scalars['String']['output']>;
@@ -5287,6 +5316,13 @@ export type LinkLogRocketOrganizationToExpoAccountInput = {
   state: Scalars['String']['input'];
 };
 
+export type LinkSentryInstallationToExpoAccountInput = {
+  accountId: Scalars['ID']['input'];
+  code: Scalars['String']['input'];
+  installationId: Scalars['ID']['input'];
+  sentryOrgSlug: Scalars['String']['input'];
+};
+
 export type LinkSharedEnvironmentVariableInput = {
   appId: Scalars['ID']['input'];
   environment?: InputMaybe<EnvironmentVariableEnvironment>;
@@ -5695,6 +5731,15 @@ export type PaymentDetails = {
   id: Scalars['ID']['output'];
 };
 
+export type PendingSentryInstallation = {
+  __typename?: 'PendingSentryInstallation';
+  account: Account;
+  createdAt: Scalars['DateTime']['output'];
+  id: Scalars['ID']['output'];
+  installationId: Scalars['String']['output'];
+  orgSlug: Scalars['String']['output'];
+};
+
 export enum Permission {
   Admin = 'ADMIN',
   Own = 'OWN',
@@ -5797,6 +5842,7 @@ export type RequestsFilters = {
   method?: InputMaybe<Array<RequestMethod>>;
   os?: InputMaybe<Array<UserAgentOs>>;
   pathname?: InputMaybe<Scalars['String']['input']>;
+  platform?: InputMaybe<Array<UserAgentPlatform>>;
   requestId?: InputMaybe<Array<Scalars['WorkerDeploymentRequestID']['input']>>;
   responseType?: InputMaybe<Array<ResponseType>>;
   status?: InputMaybe<Array<Scalars['Int']['input']>>;
@@ -5945,7 +5991,7 @@ export type RootMutation = {
   androidAppBuildCredentials: AndroidAppBuildCredentialsMutation;
   /** Mutations that modify the credentials for an Android app */
   androidAppCredentials: AndroidAppCredentialsMutation;
-  /** Mutations that modify an FCM credential */
+  /** Mutations that modify an FCM V0/Legacy credential */
   androidFcm: AndroidFcmMutation;
   /** Mutations that modify a Keystore */
   androidKeystore: AndroidKeystoreMutation;
@@ -6021,6 +6067,10 @@ export type RootMutation = {
   notificationSubscription: NotificationSubscriptionMutation;
   /** Mutations that create, update, and delete Robots */
   robot: RobotMutation;
+  /** Mutations for Sentry installations */
+  sentryInstallation: SentryInstallationMutation;
+  /** Mutations for Sentry projects */
+  sentryProject: SentryProjectMutation;
   /** Mutations that modify an EAS Submit submission */
   submission: SubmissionMutation;
   update: UpdateMutation;
@@ -6211,6 +6261,7 @@ export type Runtime = {
   fingerprint?: Maybe<Fingerprint>;
   firstBuildCreatedAt?: Maybe<Scalars['DateTime']['output']>;
   id: Scalars['ID']['output'];
+  isFingerprint: Scalars['Boolean']['output'];
   updatedAt: Scalars['DateTime']['output'];
   updates: AppUpdatesConnection;
   version: Scalars['String']['output'];
@@ -6264,6 +6315,7 @@ export type RuntimeEdge = {
 export type RuntimeFilterInput = {
   /** Only return runtimes shared with this branch */
   branchId?: InputMaybe<Scalars['String']['input']>;
+  runtimeVersions?: InputMaybe<Array<Scalars['String']['input']>>;
 };
 
 export type RuntimeQuery = {
@@ -6423,6 +6475,69 @@ export type SecondFactorRegenerateBackupCodesResult = {
   plaintextBackupCodes: Array<Scalars['String']['output']>;
 };
 
+export type SentryInstallation = {
+  __typename?: 'SentryInstallation';
+  account: Account;
+  createdAt: Scalars['DateTime']['output'];
+  id: Scalars['ID']['output'];
+  installationId: Scalars['String']['output'];
+  orgSlug: Scalars['String']['output'];
+};
+
+export type SentryInstallationMutation = {
+  __typename?: 'SentryInstallationMutation';
+  /** Confirm a pending Sentry installation */
+  confirmPendingSentryInstallation: SentryInstallation;
+  /** Generate a Sentry token for an installation */
+  generateSentryToken: GenerateSentryTokenResult;
+  /** Link a Sentry installation to an Expo account */
+  linkSentryInstallationToExpoAccount: PendingSentryInstallation;
+};
+
+
+export type SentryInstallationMutationConfirmPendingSentryInstallationArgs = {
+  installationId: Scalars['ID']['input'];
+};
+
+
+export type SentryInstallationMutationGenerateSentryTokenArgs = {
+  accountId: Scalars['ID']['input'];
+};
+
+
+export type SentryInstallationMutationLinkSentryInstallationToExpoAccountArgs = {
+  input: LinkSentryInstallationToExpoAccountInput;
+};
+
+export type SentryProject = {
+  __typename?: 'SentryProject';
+  app: App;
+  createdAt: Scalars['DateTime']['output'];
+  id: Scalars['ID']['output'];
+  sentryInstallationId: Scalars['ID']['output'];
+  sentryProjectId: Scalars['String']['output'];
+  sentryProjectSlug: Scalars['String']['output'];
+  updatedAt: Scalars['DateTime']['output'];
+};
+
+export type SentryProjectMutation = {
+  __typename?: 'SentryProjectMutation';
+  /** Create a Sentry project */
+  createSentryProject: SentryProject;
+  /** Delete a Sentry project by ID */
+  deleteSentryProject: DeleteSentryProjectResult;
+};
+
+
+export type SentryProjectMutationCreateSentryProjectArgs = {
+  input: CreateSentryProjectInput;
+};
+
+
+export type SentryProjectMutationDeleteSentryProjectArgs = {
+  sentryProjectId: Scalars['ID']['input'];
+};
+
 export type Snack = Project & {
   __typename?: 'Snack';
   /** Description of the Snack */
@@ -7162,6 +7277,7 @@ export enum UploadSessionType {
   EasBuildGcsProjectSources = 'EAS_BUILD_GCS_PROJECT_SOURCES',
   /** @deprecated Use EAS_BUILD_GCS_PROJECT_SOURCES instead. */
   EasBuildProjectSources = 'EAS_BUILD_PROJECT_SOURCES',
+  EasShareGcsAppArchive = 'EAS_SHARE_GCS_APP_ARCHIVE',
   /** @deprecated Use EAS_SUBMIT_GCS_APP_ARCHIVE instead. */
   EasSubmitAppArchive = 'EAS_SUBMIT_APP_ARCHIVE',
   EasSubmitGcsAppArchive = 'EAS_SUBMIT_GCS_APP_ARCHIVE',
@@ -7492,6 +7608,13 @@ export enum UserAgentOs {
   Windows = 'WINDOWS'
 }
 
+export enum UserAgentPlatform {
+  Android = 'ANDROID',
+  Apple = 'APPLE',
+  Unknown = 'UNKNOWN',
+  Web = 'WEB'
+}
+
 export type UserAppPinMutation = {
   __typename?: 'UserAppPinMutation';
   pinApp: Scalars['ID']['output'];
@@ -8108,6 +8231,7 @@ export type WorkerDeploymentRequestNode = {
   method: Scalars['String']['output'];
   os?: Maybe<UserAgentOs>;
   pathname: Scalars['String']['output'];
+  platform: UserAgentPlatform;
   region?: Maybe<Scalars['String']['output']>;
   requestId: Scalars['WorkerDeploymentRequestID']['output'];
   requestTimestamp: Scalars['DateTime']['output'];
@@ -8126,6 +8250,8 @@ export type WorkerDeploymentRequests = {
   byCountry: Array<WorkerDeploymentRequestsCountryEdge>;
   byMethod: Array<WorkerDeploymentRequestsMethodEdge>;
   byOS: Array<WorkerDeploymentRequestsOperatingSystemEdge>;
+  byPathname: Array<WorkerDeploymentRequestsPathnameEdge>;
+  byPlatform: Array<WorkerDeploymentRequestsPlatformEdge>;
   byResponseType: Array<WorkerDeploymentRequestsResponseTypeEdge>;
   byStatusType: Array<WorkerDeploymentRequestsStatusTypeEdge>;
   interval: Scalars['Int']['output'];
@@ -8172,6 +8298,18 @@ export type WorkerDeploymentRequestsByOsArgs = {
 };
 
 
+export type WorkerDeploymentRequestsByPathnameArgs = {
+  limit?: InputMaybe<Scalars['Int']['input']>;
+  orderBy?: InputMaybe<RequestsOrderBy>;
+};
+
+
+export type WorkerDeploymentRequestsByPlatformArgs = {
+  limit?: InputMaybe<Scalars['Int']['input']>;
+  orderBy?: InputMaybe<RequestsOrderBy>;
+};
+
+
 export type WorkerDeploymentRequestsByResponseTypeArgs = {
   limit?: InputMaybe<Scalars['Int']['input']>;
   orderBy?: InputMaybe<RequestsOrderBy>;
@@ -8262,6 +8400,18 @@ export type WorkerDeploymentRequestsOperatingSystemEdge = {
   os?: Maybe<UserAgentOs>;
 };
 
+export type WorkerDeploymentRequestsPathnameEdge = {
+  __typename?: 'WorkerDeploymentRequestsPathnameEdge';
+  node: WorkerDeploymentRequestsAggregationNode;
+  pathname: Scalars['String']['output'];
+};
+
+export type WorkerDeploymentRequestsPlatformEdge = {
+  __typename?: 'WorkerDeploymentRequestsPlatformEdge';
+  node: WorkerDeploymentRequestsAggregationNode;
+  platform: UserAgentPlatform;
+};
+
 export type WorkerDeploymentRequestsResponseTypeEdge = {
   __typename?: 'WorkerDeploymentRequestsResponseTypeEdge';
   node: WorkerDeploymentRequestsAggregationNode;
@@ -8282,6 +8432,8 @@ export type WorkerDeploymentRequestsTimeseriesEdge = {
   byCountry: Array<WorkerDeploymentRequestsCountryEdge>;
   byMethod: Array<WorkerDeploymentRequestsMethodEdge>;
   byOS: Array<WorkerDeploymentRequestsOperatingSystemEdge>;
+  byPathname: Array<WorkerDeploymentRequestsPathnameEdge>;
+  byPlatform: Array<WorkerDeploymentRequestsPlatformEdge>;
   byResponseType: Array<WorkerDeploymentRequestsResponseTypeEdge>;
   byStatusType: Array<WorkerDeploymentRequestsStatusTypeEdge>;
   node?: Maybe<WorkerDeploymentRequestsAggregationNode>;
@@ -8405,6 +8557,7 @@ export enum WorkflowJobType {
   Build = 'BUILD',
   Custom = 'CUSTOM',
   Deploy = 'DEPLOY',
+  Fingerprint = 'FINGERPRINT',
   GetBuild = 'GET_BUILD',
   MaestroTest = 'MAESTRO_TEST',
   RequireApproval = 'REQUIRE_APPROVAL',
@@ -8503,6 +8656,7 @@ export type WorkflowRun = ActivityTimelineProjectActivity & {
   sourceExpiresAt?: Maybe<Scalars['DateTime']['output']>;
   status: WorkflowRunStatus;
   triggerEventType: WorkflowRunTriggerEventType;
+  triggeringLabelName?: Maybe<Scalars['String']['output']>;
   updatedAt: Scalars['DateTime']['output'];
   workflow: Workflow;
   workflowRevision?: Maybe<WorkflowRevision>;
@@ -8570,6 +8724,7 @@ export enum WorkflowRunStatus {
 }
 
 export enum WorkflowRunTriggerEventType {
+  GithubPullRequestLabeled = 'GITHUB_PULL_REQUEST_LABELED',
   GithubPullRequestOpened = 'GITHUB_PULL_REQUEST_OPENED',
   GithubPullRequestReopened = 'GITHUB_PULL_REQUEST_REOPENED',
   GithubPullRequestSynchronize = 'GITHUB_PULL_REQUEST_SYNCHRONIZE',

From 6c97875e9f4b6fbf29e2726df4c54931fdb4921a Mon Sep 17 00:00:00 2001
From: Gabriel Donadel <donadeldev@gmail.com>
Date: Wed, 12 Mar 2025 15:22:19 -0400
Subject: [PATCH 3/8] Add share build mutation

---
 packages/eas-cli/graphql.schema.json          | 210 ++++++++++++++++++
 packages/eas-cli/src/commands/share.ts        |  17 +-
 packages/eas-cli/src/graphql/generated.ts     |  38 ++++
 .../graphql/mutations/ShareBuildMutation.ts   |  49 ++--
 4 files changed, 287 insertions(+), 27 deletions(-)

diff --git a/packages/eas-cli/graphql.schema.json b/packages/eas-cli/graphql.schema.json
index e3af8f6664..2ad781f7c7 100644
--- a/packages/eas-cli/graphql.schema.json
+++ b/packages/eas-cli/graphql.schema.json
@@ -20890,6 +20890,12 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "LOCAL",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "REPACK",
             "description": null,
@@ -21105,6 +21111,83 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "createShareBuild",
+            "description": "Create an local build",
+            "args": [
+              {
+                "name": "appId",
+                "description": null,
+                "type": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "SCALAR",
+                    "name": "ID",
+                    "ofType": null
+                  }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "artifactSource",
+                "description": null,
+                "type": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "INPUT_OBJECT",
+                    "name": "ShareArchiveSourceInput",
+                    "ofType": null
+                  }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "job",
+                "description": null,
+                "type": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "INPUT_OBJECT",
+                    "name": "ShareJobInput",
+                    "ofType": null
+                  }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "metadata",
+                "description": null,
+                "type": {
+                  "kind": "INPUT_OBJECT",
+                  "name": "BuildMetadataInput",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "CreateBuildResult",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "deleteBuild",
             "description": "Delete an EAS Build build",
@@ -45629,6 +45712,133 @@
         "enumValues": null,
         "possibleTypes": null
       },
+      {
+        "kind": "INPUT_OBJECT",
+        "name": "ShareArchiveSourceInput",
+        "description": null,
+        "fields": null,
+        "inputFields": [
+          {
+            "name": "bucketKey",
+            "description": null,
+            "type": {
+              "kind": "SCALAR",
+              "name": "String",
+              "ofType": null
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "type",
+            "description": null,
+            "type": {
+              "kind": "ENUM",
+              "name": "ShareArchiveSourceType",
+              "ofType": null
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "interfaces": null,
+        "enumValues": null,
+        "possibleTypes": null
+      },
+      {
+        "kind": "ENUM",
+        "name": "ShareArchiveSourceType",
+        "description": null,
+        "fields": null,
+        "inputFields": null,
+        "interfaces": null,
+        "enumValues": [
+          {
+            "name": "GCS",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "possibleTypes": null
+      },
+      {
+        "kind": "INPUT_OBJECT",
+        "name": "ShareJobInput",
+        "description": null,
+        "fields": null,
+        "inputFields": [
+          {
+            "name": "developmentClient",
+            "description": null,
+            "type": {
+              "kind": "SCALAR",
+              "name": "Boolean",
+              "ofType": null
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "experimental",
+            "description": null,
+            "type": {
+              "kind": "SCALAR",
+              "name": "JSONObject",
+              "ofType": null
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "platform",
+            "description": null,
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "ENUM",
+                "name": "AppPlatform",
+                "ofType": null
+              }
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "simulator",
+            "description": null,
+            "type": {
+              "kind": "SCALAR",
+              "name": "Boolean",
+              "ofType": null
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "triggeredBy",
+            "description": null,
+            "type": {
+              "kind": "ENUM",
+              "name": "BuildTrigger",
+              "ofType": null
+            },
+            "defaultValue": null,
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "interfaces": null,
+        "enumValues": null,
+        "possibleTypes": null
+      },
       {
         "kind": "OBJECT",
         "name": "Snack",
diff --git a/packages/eas-cli/src/commands/share.ts b/packages/eas-cli/src/commands/share.ts
index f3475bcd08..4f1d2dea47 100644
--- a/packages/eas-cli/src/commands/share.ts
+++ b/packages/eas-cli/src/commands/share.ts
@@ -4,11 +4,13 @@ import fg from 'fast-glob';
 import fs from 'fs-extra';
 import path from 'path';
 
+import { getBuildLogsUrl } from '../build/utils/url';
 import EasCommand from '../commandUtils/EasCommand';
 import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
 import { EASNonInteractiveFlag } from '../commandUtils/flags';
-import { UploadSessionType } from '../graphql/generated';
+import { DistributionType, ShareArchiveSourceType, UploadSessionType } from '../graphql/generated';
 import { ShareBuildMutation } from '../graphql/mutations/ShareBuildMutation';
+import { toAppPlatform } from '../graphql/types/AppPlatform';
 import Log from '../log';
 import { promptAsync } from '../prompts';
 import { uploadFileAtPathToGCSAsync } from '../uploads';
@@ -52,18 +54,15 @@ export default class BuildUpload extends EasCommand {
     Log.log('Uploading your app archive to EAS Share');
     const bucketKey = await uploadAppArchiveAsync(graphqlClient, localBuildPath);
 
-    // @TODO: use Share build mutation
-    const { debugInfoUrl } = await ShareBuildMutation.uploadLocalBuildAsync(
+    const build = await ShareBuildMutation.uploadLocalBuildAsync(
       graphqlClient,
       projectId,
-      { bucketKey },
-      {
-        // @TODO: read the fingerprint from the local build
-        hash: '',
-      }
+      { platform: toAppPlatform(platform), simulator: platform === Platform.IOS },
+      { type: ShareArchiveSourceType.Gcs, bucketKey },
+      { distribution: DistributionType.Internal }
     );
 
-    Log.withTick(`Here is a sharable link of your build: ${debugInfoUrl}`);
+    Log.withTick(`Here is a sharable link of your build: ${getBuildLogsUrl(build)}`);
   }
 
   private async selectPlatformAsync(platform?: Platform): Promise<Platform> {
diff --git a/packages/eas-cli/src/graphql/generated.ts b/packages/eas-cli/src/graphql/generated.ts
index 127ec1f441..8c5f5a0cda 100644
--- a/packages/eas-cli/src/graphql/generated.ts
+++ b/packages/eas-cli/src/graphql/generated.ts
@@ -3029,6 +3029,7 @@ export type BuildMetrics = {
 export enum BuildMode {
   Build = 'BUILD',
   Custom = 'CUSTOM',
+  Local = 'LOCAL',
   Repack = 'REPACK',
   Resign = 'RESIGN'
 }
@@ -3046,6 +3047,8 @@ export type BuildMutation = {
   createAndroidBuild: CreateBuildResult;
   /** Create an iOS build */
   createIosBuild: CreateBuildResult;
+  /** Create an local build */
+  createShareBuild: CreateBuildResult;
   /** Delete an EAS Build build */
   deleteBuild: Build;
   /** Retry an Android EAS Build */
@@ -3083,6 +3086,14 @@ export type BuildMutationCreateIosBuildArgs = {
 };
 
 
+export type BuildMutationCreateShareBuildArgs = {
+  appId: Scalars['ID']['input'];
+  artifactSource: ShareArchiveSourceInput;
+  job: ShareJobInput;
+  metadata?: InputMaybe<BuildMetadataInput>;
+};
+
+
 export type BuildMutationDeleteBuildArgs = {
   buildId: Scalars['ID']['input'];
 };
@@ -6538,6 +6549,23 @@ export type SentryProjectMutationDeleteSentryProjectArgs = {
   sentryProjectId: Scalars['ID']['input'];
 };
 
+export type ShareArchiveSourceInput = {
+  bucketKey?: InputMaybe<Scalars['String']['input']>;
+  type?: InputMaybe<ShareArchiveSourceType>;
+};
+
+export enum ShareArchiveSourceType {
+  Gcs = 'GCS'
+}
+
+export type ShareJobInput = {
+  developmentClient?: InputMaybe<Scalars['Boolean']['input']>;
+  experimental?: InputMaybe<Scalars['JSONObject']['input']>;
+  platform: AppPlatform;
+  simulator?: InputMaybe<Scalars['Boolean']['input']>;
+  triggeredBy?: InputMaybe<BuildTrigger>;
+};
+
 export type Snack = Project & {
   __typename?: 'Snack';
   /** Description of the Snack */
@@ -9437,6 +9465,16 @@ export type SetRolloutPercentageMutationVariables = Exact<{
 
 export type SetRolloutPercentageMutation = { __typename?: 'RootMutation', update: { __typename?: 'UpdateMutation', setRolloutPercentage: { __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, rolloutPercentage?: number | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null, rolloutControlUpdate?: { __typename?: 'Update', id: string } | null, fingerprint?: { __typename?: 'Fingerprint', id: string, hash: string, debugInfoUrl?: string | null, source?: { __typename?: 'FingerprintSource', type: FingerprintSourceType, bucketKey: string, isDebugFingerprint?: boolean | null } | null } | null } } };
 
+export type UploadLocalBuildMutationVariables = Exact<{
+  appId: Scalars['ID']['input'];
+  jobInput: ShareJobInput;
+  artifactSource: ShareArchiveSourceInput;
+  metadata?: InputMaybe<BuildMetadataInput>;
+}>;
+
+
+export type UploadLocalBuildMutation = { __typename?: 'RootMutation', build: { __typename?: 'BuildMutation', createShareBuild: { __typename?: 'CreateBuildResult', build: { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, channel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, expirationDate?: any | null, isForIosSimulator: boolean, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null, buildArtifactsUrl?: string | null } | null, initiatingActor?: { __typename: 'Robot', id: string, displayName: string } | { __typename: 'SSOUser', id: string, displayName: string } | { __typename: 'User', id: string, displayName: string } | null, project: { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } } | { __typename: 'Snack', id: string, name: string, slug: string }, metrics?: { __typename?: 'BuildMetrics', buildWaitTime?: number | null, buildQueueTime?: number | null, buildDuration?: number | null } | null } } } };
+
 export type CreateAndroidSubmissionMutationVariables = Exact<{
   appId: Scalars['ID']['input'];
   config: AndroidSubmissionConfigInput;
diff --git a/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts b/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts
index 2514bf81ab..ce7e3a4789 100644
--- a/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts
+++ b/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts
@@ -1,42 +1,55 @@
-import { FingerprintSource } from '@expo/eas-build-job';
 import { print } from 'graphql';
 import gql from 'graphql-tag';
 
 import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
 import { withErrorHandlingAsync } from '../client';
-import { CreateFingeprintMutation, FingerprintFragment } from '../generated';
-import { FingerprintFragmentNode } from '../types/Fingerprint';
+import {
+  BuildFragment,
+  BuildMetadataInput,
+  ShareArchiveSourceInput,
+  ShareJobInput,
+  UploadLocalBuildMutation,
+} from '../generated';
+import { BuildFragmentNode } from '../types/Build';
 
 export const ShareBuildMutation = {
   async uploadLocalBuildAsync(
     graphqlClient: ExpoGraphqlClient,
     appId: string,
-    buildSource: {
-      bucketKey: string;
-    },
-    fingerprintData: { hash: string; source?: FingerprintSource }
-  ): Promise<FingerprintFragment> {
+    job: ShareJobInput,
+    artifactSource: ShareArchiveSourceInput,
+    metadata: BuildMetadataInput
+  ): Promise<BuildFragment> {
     const data = await withErrorHandlingAsync(
       graphqlClient
-        .mutation<CreateFingeprintMutation>(
+        .mutation<UploadLocalBuildMutation>(
           gql`
-            mutation CreateFingeprintMutation(
-              $fingerprintData: CreateFingerprintInput!
+            mutation uploadLocalBuildMutation(
               $appId: ID!
+              $jobInput: ShareJobInput!
+              $artifactSource: ShareArchiveSourceInput!
+              $metadata: BuildMetadataInput
             ) {
-              fingerprint {
-                createOrGetExistingFingerprint(fingerprintData: $fingerprintData, appId: $appId) {
-                  id
-                  ...FingerprintFragment
+              build {
+                createShareBuild(
+                  appId: $appId
+                  job: $jobInput
+                  artifactSource: $artifactSource
+                  metadata: $metadata
+                ) {
+                  build {
+                    id
+                    ...BuildFragment
+                  }
                 }
               }
             }
-            ${print(FingerprintFragmentNode)}
+            ${print(BuildFragmentNode)}
           `,
-          { appId, fingerprintData }
+          { appId, jobInput: job, artifactSource, metadata }
         )
         .toPromise()
     );
-    return data.fingerprint.createOrGetExistingFingerprint;
+    return data.build.createShareBuild.build;
   },
 };

From f1ad7427abcec96198108bf24084065c83b5cc81 Mon Sep 17 00:00:00 2001
From: Gabriel Donadel <donadeldev@gmail.com>
Date: Tue, 18 Mar 2025 01:53:01 -0300
Subject: [PATCH 4/8] Fix app file extension not persisting

---
 packages/eas-cli/src/commands/share.ts        | 66 ++++++++++++-------
 packages/eas-cli/src/graphql/generated.ts     |  4 ++
 .../mutations/UploadSessionMutation.ts        |  8 ++-
 packages/eas-cli/src/uploads.ts               |  6 +-
 4 files changed, 56 insertions(+), 28 deletions(-)

diff --git a/packages/eas-cli/src/commands/share.ts b/packages/eas-cli/src/commands/share.ts
index 4f1d2dea47..b9555cac95 100644
--- a/packages/eas-cli/src/commands/share.ts
+++ b/packages/eas-cli/src/commands/share.ts
@@ -46,12 +46,9 @@ export default class BuildUpload extends EasCommand {
     });
 
     const platform = await this.selectPlatformAsync(flags.platform);
-    const localBuildPath = await resolveLocalBuildPathAsync({
-      platform,
-      buildPath,
-    });
+    const localBuildPath = await resolveLocalBuildPathAsync(platform, buildPath);
 
-    Log.log('Uploading your app archive to EAS Share');
+    Log.log('Uploading your app archive to EAS');
     const bucketKey = await uploadAppArchiveAsync(graphqlClient, localBuildPath);
 
     const build = await ShareBuildMutation.uploadLocalBuildAsync(
@@ -82,30 +79,54 @@ export default class BuildUpload extends EasCommand {
   }
 }
 
-async function resolveLocalBuildPathAsync({
-  platform,
-  buildPath,
-}: {
-  platform: Platform;
-  buildPath?: string;
-}): Promise<string> {
+async function resolveLocalBuildPathAsync(
+  platform: Platform,
+  inputBuildPath?: string
+): Promise<string> {
   const applicationArchivePatternOrPath =
-    buildPath ?? platform === Platform.ANDROID
+    inputBuildPath ?? platform === Platform.ANDROID
       ? 'android/app/build/outputs/**/*.{apk,aab}'
       : 'ios/build/Build/Products/*simulator/*.app';
 
-  const applicationArchives = await findArtifactsAsync({
+  let applicationArchives = await findArtifactsAsync({
     rootDir: process.cwd(),
     patternOrPath: applicationArchivePatternOrPath,
   });
 
-  const count = applicationArchives.length;
-  Log.log(
-    `Found ${count} application archive${count > 1 ? 's' : ''}:\n- ${applicationArchives.join(
-      '\n- '
-    )}`
-  );
-  return applicationArchives[0];
+  if (applicationArchives.length === 0 && !inputBuildPath) {
+    Log.warn(`No application archives found at ${applicationArchivePatternOrPath}.`);
+    const { path } = await promptAsync({
+      type: 'text',
+      name: 'path',
+      message: 'Provide a path to the application archive:',
+      validate: value => (value ? true : 'Path may not be empty.'),
+    });
+    applicationArchives = await findArtifactsAsync({
+      rootDir: process.cwd(),
+      patternOrPath: path,
+    });
+  }
+
+  if (applicationArchives.length === 1) {
+    return applicationArchives[0];
+  }
+
+  if (applicationArchives.length > 1) {
+    const { path } = await promptAsync({
+      type: 'select',
+      name: 'path',
+      message: 'Found multiple application archives. Select one:',
+      choices: applicationArchives.map(archivePath => {
+        return {
+          title: archivePath,
+          value: archivePath,
+        };
+      }),
+    });
+    return path;
+  }
+
+  throw new Error(`Found no application archives at ${inputBuildPath}.`);
 }
 
 async function findArtifactsAsync({
@@ -120,9 +141,6 @@ async function findArtifactsAsync({
       ? [patternOrPath]
       : []
     : await fg(patternOrPath, { cwd: rootDir, onlyFiles: false });
-  if (files.length === 0) {
-    throw new Error(`Found no application archives for "${patternOrPath}".`);
-  }
 
   return files.map(filePath => {
     // User may provide an absolute path as input in which case
diff --git a/packages/eas-cli/src/graphql/generated.ts b/packages/eas-cli/src/graphql/generated.ts
index 8c5f5a0cda..e2356e12d2 100644
--- a/packages/eas-cli/src/graphql/generated.ts
+++ b/packages/eas-cli/src/graphql/generated.ts
@@ -7297,6 +7297,7 @@ export type UploadSessionCreateAppScopedUploadSessionArgs = {
 
 
 export type UploadSessionCreateUploadSessionArgs = {
+  filename?: InputMaybe<Scalars['String']['input']>;
   type: UploadSessionType;
 };
 
@@ -7670,7 +7671,9 @@ export type UserAuditLog = {
   targetEntityMutationType: TargetEntityMutationType;
   targetEntityTypeName: UserEntityTypeName;
   targetEntityTypePublicName: Scalars['String']['output'];
+  /** @deprecated Use userActor instead */
   user: User;
+  userActor: UserActor;
   websiteMessage: Scalars['String']['output'];
 };
 
@@ -9497,6 +9500,7 @@ export type CreateIosSubmissionMutation = { __typename?: 'RootMutation', submiss
 
 export type CreateUploadSessionMutationVariables = Exact<{
   type: UploadSessionType;
+  filename?: InputMaybe<Scalars['String']['input']>;
 }>;
 
 
diff --git a/packages/eas-cli/src/graphql/mutations/UploadSessionMutation.ts b/packages/eas-cli/src/graphql/mutations/UploadSessionMutation.ts
index f5703e3f24..9aa8188019 100644
--- a/packages/eas-cli/src/graphql/mutations/UploadSessionMutation.ts
+++ b/packages/eas-cli/src/graphql/mutations/UploadSessionMutation.ts
@@ -20,20 +20,22 @@ export interface SignedUrl {
 export const UploadSessionMutation = {
   async createUploadSessionAsync(
     graphqlClient: ExpoGraphqlClient,
-    type: UploadSessionType
+    type: UploadSessionType,
+    filename?: string
   ): Promise<SignedUrl> {
     const data = await withErrorHandlingAsync(
       graphqlClient
         .mutation<CreateUploadSessionMutation, CreateUploadSessionMutationVariables>(
           gql`
-            mutation CreateUploadSessionMutation($type: UploadSessionType!) {
+            mutation CreateUploadSessionMutation($type: UploadSessionType!, $filename: String) {
               uploadSession {
-                createUploadSession(type: $type)
+                createUploadSession(type: $type, filename: $filename)
               }
             }
           `,
           {
             type,
+            filename,
           }
         )
         .toPromise()
diff --git a/packages/eas-cli/src/uploads.ts b/packages/eas-cli/src/uploads.ts
index e4427b696e..8c68eac6d9 100644
--- a/packages/eas-cli/src/uploads.ts
+++ b/packages/eas-cli/src/uploads.ts
@@ -20,7 +20,11 @@ export async function uploadFileAtPathToGCSAsync(
   path: string,
   handleProgressEvent: ProgressHandler = () => {}
 ): Promise<string> {
-  const signedUrl = await UploadSessionMutation.createUploadSessionAsync(graphqlClient, type);
+  const signedUrl = await UploadSessionMutation.createUploadSessionAsync(
+    graphqlClient,
+    type,
+    type === UploadSessionType.EasShareGcsAppArchive ? path : undefined
+  );
 
   await uploadWithSignedUrlWithProgressAsync(path, signedUrl, handleProgressEvent);
   return signedUrl.bucketKey;

From 0fc5321e2b2ad0109c7a4b6a260292158a126b89 Mon Sep 17 00:00:00 2001
From: Gabriel Donadel <donadeldev@gmail.com>
Date: Thu, 20 Mar 2025 11:38:03 -0300
Subject: [PATCH 5/8] Add function to extract App Metadata

---
 packages/eas-cli/graphql.schema.json   | 28 +++++++++
 packages/eas-cli/package.json          |  1 +
 packages/eas-cli/src/commands/share.ts | 82 ++++++++++++++++++++++++--
 3 files changed, 107 insertions(+), 4 deletions(-)

diff --git a/packages/eas-cli/graphql.schema.json b/packages/eas-cli/graphql.schema.json
index 2ad781f7c7..94d438aacc 100644
--- a/packages/eas-cli/graphql.schema.json
+++ b/packages/eas-cli/graphql.schema.json
@@ -50956,6 +50956,18 @@
             "name": "createUploadSession",
             "description": "Create an Upload Session",
             "args": [
+              {
+                "name": "filename",
+                "description": null,
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "String",
+                  "ofType": null
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
               {
                 "name": "type",
                 "description": null,
@@ -53575,6 +53587,22 @@
                 "ofType": null
               }
             },
+            "isDeprecated": true,
+            "deprecationReason": "Use userActor instead"
+          },
+          {
+            "name": "userActor",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "INTERFACE",
+                "name": "UserActor",
+                "ofType": null
+              }
+            },
             "isDeprecated": false,
             "deprecationReason": null
           },
diff --git a/packages/eas-cli/package.json b/packages/eas-cli/package.json
index b4cbe34f7a..49e531db54 100644
--- a/packages/eas-cli/package.json
+++ b/packages/eas-cli/package.json
@@ -68,6 +68,7 @@
     "nanoid": "3.3.8",
     "node-fetch": "2.6.7",
     "node-forge": "1.3.1",
+    "node-stream-zip": "1.15.0",
     "nullthrows": "1.1.1",
     "ora": "5.1.0",
     "pkg-dir": "4.2.0",
diff --git a/packages/eas-cli/src/commands/share.ts b/packages/eas-cli/src/commands/share.ts
index b9555cac95..29fb3f7aab 100644
--- a/packages/eas-cli/src/commands/share.ts
+++ b/packages/eas-cli/src/commands/share.ts
@@ -2,6 +2,7 @@ import { Platform } from '@expo/eas-build-job';
 import { Flags } from '@oclif/core';
 import fg from 'fast-glob';
 import fs from 'fs-extra';
+import StreamZip from 'node-stream-zip';
 import path from 'path';
 
 import { getBuildLogsUrl } from '../build/utils/url';
@@ -9,6 +10,7 @@ import EasCommand from '../commandUtils/EasCommand';
 import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
 import { EASNonInteractiveFlag } from '../commandUtils/flags';
 import { DistributionType, ShareArchiveSourceType, UploadSessionType } from '../graphql/generated';
+import { FingerprintMutation } from '../graphql/mutations/FingerprintMutation';
 import { ShareBuildMutation } from '../graphql/mutations/ShareBuildMutation';
 import { toAppPlatform } from '../graphql/types/AppPlatform';
 import Log from '../log';
@@ -48,15 +50,25 @@ export default class BuildUpload extends EasCommand {
     const platform = await this.selectPlatformAsync(flags.platform);
     const localBuildPath = await resolveLocalBuildPathAsync(platform, buildPath);
 
+    const { fingerprintHash, developmentClient, simulator } = await extractAppMetadataAsync(
+      localBuildPath,
+      platform
+    );
+    if (fingerprintHash) {
+      await FingerprintMutation.createFingerprintAsync(graphqlClient, projectId, {
+        hash: fingerprintHash,
+      });
+    }
+
     Log.log('Uploading your app archive to EAS');
     const bucketKey = await uploadAppArchiveAsync(graphqlClient, localBuildPath);
 
     const build = await ShareBuildMutation.uploadLocalBuildAsync(
       graphqlClient,
       projectId,
-      { platform: toAppPlatform(platform), simulator: platform === Platform.IOS },
+      { platform: toAppPlatform(platform), simulator },
       { type: ShareArchiveSourceType.Gcs, bucketKey },
-      { distribution: DistributionType.Internal }
+      { distribution: DistributionType.Internal, fingerprintHash, developmentClient }
     );
 
     Log.withTick(`Here is a sharable link of your build: ${getBuildLogsUrl(build)}`);
@@ -84,9 +96,10 @@ async function resolveLocalBuildPathAsync(
   inputBuildPath?: string
 ): Promise<string> {
   const applicationArchivePatternOrPath =
-    inputBuildPath ?? platform === Platform.ANDROID
+    inputBuildPath ??
+    (platform === Platform.ANDROID
       ? 'android/app/build/outputs/**/*.{apk,aab}'
-      : 'ios/build/Build/Products/*simulator/*.app';
+      : 'ios/build/Build/Products/*simulator/*.app');
 
   let applicationArchives = await findArtifactsAsync({
     rootDir: process.cwd(),
@@ -172,3 +185,64 @@ async function uploadAppArchiveAsync(
   );
   return bucketKey;
 }
+
+type AppMetadata = {
+  fingerprintHash?: string;
+  developmentClient: boolean;
+  simulator: boolean;
+};
+
+async function extractAppMetadataAsync(
+  buildPath: string,
+  platform: Platform
+): Promise<AppMetadata> {
+  let developmentClient = false;
+  let fingerprintHash: string | undefined;
+  let simulator = platform === Platform.IOS;
+
+  let basePath = platform === Platform.ANDROID ? 'assets/' : buildPath;
+  const fingerprintFilePath =
+    platform === Platform.ANDROID ? 'fingerprint' : 'EXUpdates.bundle/fingerprint';
+  const devMenuBundlePath =
+    platform === Platform.ANDROID ? 'EXDevMenuApp.android.js' : 'EXDevMenu.bundle';
+
+  const buildExtension = path.extname(buildPath);
+  // check extension if, .apk, .ipa [] = .aab
+  if (['.apk', '.ipa'].includes(buildExtension)) {
+    const zip = new StreamZip.async({ file: buildPath });
+    try {
+      if (buildExtension === '.ipa') {
+        const entries = await zip.entries();
+        basePath =
+          Object.keys(entries).find(
+            entry => entry.startsWith('Payload/') && entry.endsWith('.app/')
+          ) ?? basePath;
+      }
+
+      developmentClient = Boolean(await zip.entry(path.join(basePath, devMenuBundlePath)));
+      if (await zip.entry(path.join(basePath, fingerprintFilePath))) {
+        fingerprintHash = (await zip.entryData(path.join(basePath, fingerprintFilePath))).toString(
+          'utf-8'
+        );
+      }
+    } catch (err) {
+      Log.error(`Error reading ${buildExtension}: ${err}`);
+    } finally {
+      await zip.close();
+    }
+  } else if (buildExtension === '.app') {
+    developmentClient = await fs.exists(path.join(basePath, devMenuBundlePath));
+
+    if (await fs.exists(path.join(basePath, fingerprintFilePath))) {
+      fingerprintHash = await fs.readFile(path.join(basePath, fingerprintFilePath), 'utf8');
+    }
+  } else {
+    //TODO: extract from .tar
+  }
+
+  return {
+    developmentClient,
+    fingerprintHash,
+    simulator,
+  };
+}

From f0ec5f5b562c1c61bc06ff9f4d810843d9d0e317 Mon Sep 17 00:00:00 2001
From: Gabriel Donadel <donadeldev@gmail.com>
Date: Thu, 20 Mar 2025 20:19:59 -0300
Subject: [PATCH 6/8] Add tar support

---
 packages/eas-cli/src/commands/share.ts | 40 ++++++++++++++++++++++----
 yarn.lock                              |  5 ++++
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/packages/eas-cli/src/commands/share.ts b/packages/eas-cli/src/commands/share.ts
index 29fb3f7aab..4dc6836ee1 100644
--- a/packages/eas-cli/src/commands/share.ts
+++ b/packages/eas-cli/src/commands/share.ts
@@ -4,6 +4,7 @@ import fg from 'fast-glob';
 import fs from 'fs-extra';
 import StreamZip from 'node-stream-zip';
 import path from 'path';
+import tar from 'tar';
 
 import { getBuildLogsUrl } from '../build/utils/url';
 import EasCommand from '../commandUtils/EasCommand';
@@ -198,17 +199,16 @@ async function extractAppMetadataAsync(
 ): Promise<AppMetadata> {
   let developmentClient = false;
   let fingerprintHash: string | undefined;
-  let simulator = platform === Platform.IOS;
+  const simulator = platform === Platform.IOS;
 
   let basePath = platform === Platform.ANDROID ? 'assets/' : buildPath;
   const fingerprintFilePath =
     platform === Platform.ANDROID ? 'fingerprint' : 'EXUpdates.bundle/fingerprint';
   const devMenuBundlePath =
-    platform === Platform.ANDROID ? 'EXDevMenuApp.android.js' : 'EXDevMenu.bundle';
+    platform === Platform.ANDROID ? 'EXDevMenuApp.android.js' : 'EXDevMenu.bundle/';
 
   const buildExtension = path.extname(buildPath);
-  // check extension if, .apk, .ipa [] = .aab
-  if (['.apk', '.ipa'].includes(buildExtension)) {
+  if (['.apk', '.ipa', '.aab'].includes(buildExtension)) {
     const zip = new StreamZip.async({ file: buildPath });
     try {
       if (buildExtension === '.ipa') {
@@ -237,7 +237,37 @@ async function extractAppMetadataAsync(
       fingerprintHash = await fs.readFile(path.join(basePath, fingerprintFilePath), 'utf8');
     }
   } else {
-    //TODO: extract from .tar
+    // Use tar to list files in the archive
+    try {
+      let fingerprintHashPromise: Promise<string> | undefined;
+      await tar.list({
+        file: buildPath,
+        // eslint-disable-next-line async-protect/async-suffix
+        onentry: entry => {
+          if (entry.path.endsWith(devMenuBundlePath)) {
+            developmentClient = true;
+          }
+          if (entry.path.endsWith(fingerprintFilePath)) {
+            fingerprintHashPromise = new Promise<string>(async (resolve, reject) => {
+              try {
+                let content = '';
+                for await (const chunk of entry) {
+                  content += chunk.toString('utf8');
+                }
+                resolve(content);
+              } catch (error) {
+                reject(error);
+              }
+            });
+          }
+        },
+      });
+      if (fingerprintHashPromise !== undefined) {
+        fingerprintHash = await fingerprintHashPromise;
+      }
+    } catch (err) {
+      Log.error(`Error reading ${buildExtension}: ${err}`);
+    }
   }
 
   return {
diff --git a/yarn.lock b/yarn.lock
index 74ec939181..8d0374e1df 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10960,6 +10960,11 @@ node-rsa@^1.1.1:
   dependencies:
     asn1 "^0.2.4"
 
+node-stream-zip@1.15.0:
+  version "1.15.0"
+  resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.15.0.tgz#158adb88ed8004c6c49a396b50a6a5de3bca33ea"
+  integrity sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==
+
 nopt@^5.0.0:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"

From 1089c53987edded5495c997ace28224dc3da8b60 Mon Sep 17 00:00:00 2001
From: Gabriel Donadel <donadeldev@gmail.com>
Date: Mon, 24 Mar 2025 14:35:29 -0300
Subject: [PATCH 7/8] Use shareLocalBuild

---
 packages/eas-cli/graphql.schema.json          | 182 ++++++++++--------
 packages/eas-cli/src/graphql/generated.ts     |  32 +--
 .../graphql/mutations/ShareBuildMutation.ts   |   4 +-
 3 files changed, 123 insertions(+), 95 deletions(-)

diff --git a/packages/eas-cli/graphql.schema.json b/packages/eas-cli/graphql.schema.json
index 94d438aacc..7b8a429339 100644
--- a/packages/eas-cli/graphql.schema.json
+++ b/packages/eas-cli/graphql.schema.json
@@ -9599,6 +9599,18 @@
             "isDeprecated": true,
             "deprecationReason": "No longer supported"
           },
+          {
+            "name": "profileImageUrl",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "SCALAR",
+              "name": "String",
+              "ofType": null
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "published",
             "description": "Whether there have been any classic update publishes",
@@ -21112,11 +21124,11 @@
             "deprecationReason": null
           },
           {
-            "name": "createShareBuild",
-            "description": "Create an local build",
+            "name": "deleteBuild",
+            "description": "Delete an EAS Build build",
             "args": [
               {
-                "name": "appId",
+                "name": "buildId",
                 "description": null,
                 "type": {
                   "kind": "NON_NULL",
@@ -21130,32 +21142,33 @@
                 "defaultValue": null,
                 "isDeprecated": false,
                 "deprecationReason": null
-              },
-              {
-                "name": "artifactSource",
-                "description": null,
-                "type": {
-                  "kind": "NON_NULL",
-                  "name": null,
-                  "ofType": {
-                    "kind": "INPUT_OBJECT",
-                    "name": "ShareArchiveSourceInput",
-                    "ofType": null
-                  }
-                },
-                "defaultValue": null,
-                "isDeprecated": false,
-                "deprecationReason": null
-              },
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "Build",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "retryAndroidBuild",
+            "description": "Retry an Android EAS Build",
+            "args": [
               {
-                "name": "job",
+                "name": "buildId",
                 "description": null,
                 "type": {
                   "kind": "NON_NULL",
                   "name": null,
                   "ofType": {
-                    "kind": "INPUT_OBJECT",
-                    "name": "ShareJobInput",
+                    "kind": "SCALAR",
+                    "name": "ID",
                     "ofType": null
                   }
                 },
@@ -21164,11 +21177,11 @@
                 "deprecationReason": null
               },
               {
-                "name": "metadata",
+                "name": "jobOverrides",
                 "description": null,
                 "type": {
                   "kind": "INPUT_OBJECT",
-                  "name": "BuildMetadataInput",
+                  "name": "AndroidJobOverridesInput",
                   "ofType": null
                 },
                 "defaultValue": null,
@@ -21181,7 +21194,7 @@
               "name": null,
               "ofType": {
                 "kind": "OBJECT",
-                "name": "CreateBuildResult",
+                "name": "Build",
                 "ofType": null
               }
             },
@@ -21189,8 +21202,8 @@
             "deprecationReason": null
           },
           {
-            "name": "deleteBuild",
-            "description": "Delete an EAS Build build",
+            "name": "retryBuild",
+            "description": "Retry an EAS Build build",
             "args": [
               {
                 "name": "buildId",
@@ -21218,12 +21231,12 @@
                 "ofType": null
               }
             },
-            "isDeprecated": false,
-            "deprecationReason": null
+            "isDeprecated": true,
+            "deprecationReason": "Use retryAndroidBuild and retryIosBuild instead"
           },
           {
-            "name": "retryAndroidBuild",
-            "description": "Retry an Android EAS Build",
+            "name": "retryIosBuild",
+            "description": "Retry an iOS EAS Build",
             "args": [
               {
                 "name": "buildId",
@@ -21246,7 +21259,7 @@
                 "description": null,
                 "type": {
                   "kind": "INPUT_OBJECT",
-                  "name": "AndroidJobOverridesInput",
+                  "name": "IosJobOverridesInput",
                   "ofType": null
                 },
                 "defaultValue": null,
@@ -21267,11 +21280,11 @@
             "deprecationReason": null
           },
           {
-            "name": "retryBuild",
-            "description": "Retry an EAS Build build",
+            "name": "shareLocalBuild",
+            "description": "Share a local build",
             "args": [
               {
-                "name": "buildId",
+                "name": "appId",
                 "description": null,
                 "type": {
                   "kind": "NON_NULL",
@@ -21285,33 +21298,16 @@
                 "defaultValue": null,
                 "isDeprecated": false,
                 "deprecationReason": null
-              }
-            ],
-            "type": {
-              "kind": "NON_NULL",
-              "name": null,
-              "ofType": {
-                "kind": "OBJECT",
-                "name": "Build",
-                "ofType": null
-              }
-            },
-            "isDeprecated": true,
-            "deprecationReason": "Use retryAndroidBuild and retryIosBuild instead"
-          },
-          {
-            "name": "retryIosBuild",
-            "description": "Retry an iOS EAS Build",
-            "args": [
+              },
               {
-                "name": "buildId",
+                "name": "artifactSource",
                 "description": null,
                 "type": {
                   "kind": "NON_NULL",
                   "name": null,
                   "ofType": {
-                    "kind": "SCALAR",
-                    "name": "ID",
+                    "kind": "INPUT_OBJECT",
+                    "name": "ShareArchiveSourceInput",
                     "ofType": null
                   }
                 },
@@ -21320,11 +21316,27 @@
                 "deprecationReason": null
               },
               {
-                "name": "jobOverrides",
+                "name": "job",
+                "description": null,
+                "type": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "INPUT_OBJECT",
+                    "name": "ShareJobInput",
+                    "ofType": null
+                  }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              },
+              {
+                "name": "metadata",
                 "description": null,
                 "type": {
                   "kind": "INPUT_OBJECT",
-                  "name": "IosJobOverridesInput",
+                  "name": "BuildMetadataInput",
                   "ofType": null
                 },
                 "defaultValue": null,
@@ -21337,7 +21349,7 @@
               "name": null,
               "ofType": {
                 "kind": "OBJECT",
-                "name": "Build",
+                "name": "CreateBuildResult",
                 "ofType": null
               }
             },
@@ -45722,9 +45734,13 @@
             "name": "bucketKey",
             "description": null,
             "type": {
-              "kind": "SCALAR",
-              "name": "String",
-              "ofType": null
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
             },
             "defaultValue": null,
             "isDeprecated": false,
@@ -45734,9 +45750,13 @@
             "name": "type",
             "description": null,
             "type": {
-              "kind": "ENUM",
-              "name": "ShareArchiveSourceType",
-              "ofType": null
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "ENUM",
+                "name": "ShareArchiveSourceType",
+                "ofType": null
+              }
             },
             "defaultValue": null,
             "isDeprecated": false,
@@ -45821,18 +45841,6 @@
             "defaultValue": null,
             "isDeprecated": false,
             "deprecationReason": null
-          },
-          {
-            "name": "triggeredBy",
-            "description": null,
-            "type": {
-              "kind": "ENUM",
-              "name": "BuildTrigger",
-              "ofType": null
-            },
-            "defaultValue": null,
-            "isDeprecated": false,
-            "deprecationReason": null
           }
         ],
         "interfaces": null,
@@ -61907,6 +61915,18 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "triggeringSchedule",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "SCALAR",
+              "name": "String",
+              "ofType": null
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "updatedAt",
             "description": null,
@@ -62366,6 +62386,12 @@
             "description": null,
             "isDeprecated": false,
             "deprecationReason": null
+          },
+          {
+            "name": "SCHEDULE",
+            "description": null,
+            "isDeprecated": false,
+            "deprecationReason": null
           }
         ],
         "possibleTypes": null
diff --git a/packages/eas-cli/src/graphql/generated.ts b/packages/eas-cli/src/graphql/generated.ts
index e2356e12d2..7636dc7fb7 100644
--- a/packages/eas-cli/src/graphql/generated.ts
+++ b/packages/eas-cli/src/graphql/generated.ts
@@ -1323,6 +1323,7 @@ export type App = Project & {
   privacy: Scalars['String']['output'];
   /** @deprecated No longer supported */
   privacySetting: AppPrivacy;
+  profileImageUrl?: Maybe<Scalars['String']['output']>;
   /**
    * Whether there have been any classic update publishes
    * @deprecated Classic updates have been deprecated.
@@ -3047,8 +3048,6 @@ export type BuildMutation = {
   createAndroidBuild: CreateBuildResult;
   /** Create an iOS build */
   createIosBuild: CreateBuildResult;
-  /** Create an local build */
-  createShareBuild: CreateBuildResult;
   /** Delete an EAS Build build */
   deleteBuild: Build;
   /** Retry an Android EAS Build */
@@ -3060,6 +3059,8 @@ export type BuildMutation = {
   retryBuild: Build;
   /** Retry an iOS EAS Build */
   retryIosBuild: Build;
+  /** Share a local build */
+  shareLocalBuild: CreateBuildResult;
   /** Update metadata for EAS Build build */
   updateBuildMetadata: Build;
 };
@@ -3086,14 +3087,6 @@ export type BuildMutationCreateIosBuildArgs = {
 };
 
 
-export type BuildMutationCreateShareBuildArgs = {
-  appId: Scalars['ID']['input'];
-  artifactSource: ShareArchiveSourceInput;
-  job: ShareJobInput;
-  metadata?: InputMaybe<BuildMetadataInput>;
-};
-
-
 export type BuildMutationDeleteBuildArgs = {
   buildId: Scalars['ID']['input'];
 };
@@ -3116,6 +3109,14 @@ export type BuildMutationRetryIosBuildArgs = {
 };
 
 
+export type BuildMutationShareLocalBuildArgs = {
+  appId: Scalars['ID']['input'];
+  artifactSource: ShareArchiveSourceInput;
+  job: ShareJobInput;
+  metadata?: InputMaybe<BuildMetadataInput>;
+};
+
+
 export type BuildMutationUpdateBuildMetadataArgs = {
   buildId: Scalars['ID']['input'];
   metadata: BuildMetadataInput;
@@ -6550,8 +6551,8 @@ export type SentryProjectMutationDeleteSentryProjectArgs = {
 };
 
 export type ShareArchiveSourceInput = {
-  bucketKey?: InputMaybe<Scalars['String']['input']>;
-  type?: InputMaybe<ShareArchiveSourceType>;
+  bucketKey: Scalars['String']['input'];
+  type: ShareArchiveSourceType;
 };
 
 export enum ShareArchiveSourceType {
@@ -6563,7 +6564,6 @@ export type ShareJobInput = {
   experimental?: InputMaybe<Scalars['JSONObject']['input']>;
   platform: AppPlatform;
   simulator?: InputMaybe<Scalars['Boolean']['input']>;
-  triggeredBy?: InputMaybe<BuildTrigger>;
 };
 
 export type Snack = Project & {
@@ -8688,6 +8688,7 @@ export type WorkflowRun = ActivityTimelineProjectActivity & {
   status: WorkflowRunStatus;
   triggerEventType: WorkflowRunTriggerEventType;
   triggeringLabelName?: Maybe<Scalars['String']['output']>;
+  triggeringSchedule?: Maybe<Scalars['String']['output']>;
   updatedAt: Scalars['DateTime']['output'];
   workflow: Workflow;
   workflowRevision?: Maybe<WorkflowRevision>;
@@ -8760,7 +8761,8 @@ export enum WorkflowRunTriggerEventType {
   GithubPullRequestReopened = 'GITHUB_PULL_REQUEST_REOPENED',
   GithubPullRequestSynchronize = 'GITHUB_PULL_REQUEST_SYNCHRONIZE',
   GithubPush = 'GITHUB_PUSH',
-  Manual = 'MANUAL'
+  Manual = 'MANUAL',
+  Schedule = 'SCHEDULE'
 }
 
 export type WorkflowRunsConnection = {
@@ -9476,7 +9478,7 @@ export type UploadLocalBuildMutationVariables = Exact<{
 }>;
 
 
-export type UploadLocalBuildMutation = { __typename?: 'RootMutation', build: { __typename?: 'BuildMutation', createShareBuild: { __typename?: 'CreateBuildResult', build: { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, channel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, expirationDate?: any | null, isForIosSimulator: boolean, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null, buildArtifactsUrl?: string | null } | null, initiatingActor?: { __typename: 'Robot', id: string, displayName: string } | { __typename: 'SSOUser', id: string, displayName: string } | { __typename: 'User', id: string, displayName: string } | null, project: { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } } | { __typename: 'Snack', id: string, name: string, slug: string }, metrics?: { __typename?: 'BuildMetrics', buildWaitTime?: number | null, buildQueueTime?: number | null, buildDuration?: number | null } | null } } } };
+export type UploadLocalBuildMutation = { __typename?: 'RootMutation', build: { __typename?: 'BuildMutation', shareLocalBuild: { __typename?: 'CreateBuildResult', build: { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, channel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, expirationDate?: any | null, isForIosSimulator: boolean, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null, buildArtifactsUrl?: string | null } | null, initiatingActor?: { __typename: 'Robot', id: string, displayName: string } | { __typename: 'SSOUser', id: string, displayName: string } | { __typename: 'User', id: string, displayName: string } | null, project: { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } } | { __typename: 'Snack', id: string, name: string, slug: string }, metrics?: { __typename?: 'BuildMetrics', buildWaitTime?: number | null, buildQueueTime?: number | null, buildDuration?: number | null } | null } } } };
 
 export type CreateAndroidSubmissionMutationVariables = Exact<{
   appId: Scalars['ID']['input'];
diff --git a/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts b/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts
index ce7e3a4789..e98228ba53 100644
--- a/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts
+++ b/packages/eas-cli/src/graphql/mutations/ShareBuildMutation.ts
@@ -31,7 +31,7 @@ export const ShareBuildMutation = {
               $metadata: BuildMetadataInput
             ) {
               build {
-                createShareBuild(
+                shareLocalBuild(
                   appId: $appId
                   job: $jobInput
                   artifactSource: $artifactSource
@@ -50,6 +50,6 @@ export const ShareBuildMutation = {
         )
         .toPromise()
     );
-    return data.build.createShareBuild.build;
+    return data.build.shareLocalBuild.build;
   },
 };

From 0fb1cce770f8c4de9b7ff462e3f2fba6e8e8eecc Mon Sep 17 00:00:00 2001
From: Gabriel Donadel <donadeldev@gmail.com>
Date: Tue, 25 Mar 2025 10:24:07 -0300
Subject: [PATCH 8/8] Add fingerprint flag

---
 packages/eas-cli/src/commands/share.ts | 36 ++++++++++++++++++++------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/packages/eas-cli/src/commands/share.ts b/packages/eas-cli/src/commands/share.ts
index 4dc6836ee1..29fb944b49 100644
--- a/packages/eas-cli/src/commands/share.ts
+++ b/packages/eas-cli/src/commands/share.ts
@@ -30,6 +30,9 @@ export default class BuildUpload extends EasCommand {
     'build-path': Flags.string({
       description: 'Path for the local build',
     }),
+    fingerprint: Flags.string({
+      description: 'Fingerprint hash of the local build',
+    }),
     ...EASNonInteractiveFlag,
   };
 
@@ -40,7 +43,7 @@ export default class BuildUpload extends EasCommand {
 
   async runAsync(): Promise<void> {
     const { flags } = await this.parse(BuildUpload);
-    const { 'build-path': buildPath } = flags;
+    const { 'build-path': buildPath, fingerprint: manualFingerprintHash } = flags;
     const {
       projectId,
       loggedIn: { graphqlClient },
@@ -51,13 +54,30 @@ export default class BuildUpload extends EasCommand {
     const platform = await this.selectPlatformAsync(flags.platform);
     const localBuildPath = await resolveLocalBuildPathAsync(platform, buildPath);
 
-    const { fingerprintHash, developmentClient, simulator } = await extractAppMetadataAsync(
-      localBuildPath,
-      platform
-    );
-    if (fingerprintHash) {
+    const {
+      fingerprintHash: buildFingerprintHash,
+      developmentClient,
+      simulator,
+    } = await extractAppMetadataAsync(localBuildPath, platform);
+
+    let fingerprint = manualFingerprintHash ?? buildFingerprintHash;
+    if (fingerprint) {
+      if (
+        manualFingerprintHash &&
+        buildFingerprintHash &&
+        manualFingerprintHash !== buildFingerprintHash
+      ) {
+        const selectedAnswer = await promptAsync({
+          name: 'fingerprint',
+          message: `The provided fingerprint hash ${manualFingerprintHash} does not match the fingerprint hash of the build ${buildFingerprintHash}. Which fingerprint do you want to use?`,
+          type: 'select',
+          choices: [{ title: manualFingerprintHash }, { title: buildFingerprintHash }],
+        });
+        fingerprint = String(selectedAnswer.fingerprint);
+      }
+
       await FingerprintMutation.createFingerprintAsync(graphqlClient, projectId, {
-        hash: fingerprintHash,
+        hash: fingerprint,
       });
     }
 
@@ -69,7 +89,7 @@ export default class BuildUpload extends EasCommand {
       projectId,
       { platform: toAppPlatform(platform), simulator },
       { type: ShareArchiveSourceType.Gcs, bucketKey },
-      { distribution: DistributionType.Internal, fingerprintHash, developmentClient }
+      { distribution: DistributionType.Internal, fingerprintHash: fingerprint, developmentClient }
     );
 
     Log.withTick(`Here is a sharable link of your build: ${getBuildLogsUrl(build)}`);