npm package diff

Package: @forge/cli

Versions: 10.13.6 - 11.0.0-next.18

File: package/out/installations/graphql-client.js

Index: package/out/installations/graphql-client.js
===================================================================
--- package/out/installations/graphql-client.js
+++ package/out/installations/graphql-client.js
@@ -72,9 +72,9 @@
 }
 exports.InstallationNotFoundError = InstallationNotFoundError;
 class InstallationsGraphqlClient {
     graphqlClient;
-    cloudIdTranslator;
+    sitedProductTranslator;
     bitbucketTranslator;
     pause;
     SITE_RESOURCE_TYPE = 'site';
     WORKSPACE_RESOURCE_TYPE = 'workspace';
@@ -85,11 +85,11 @@
             resourceId: resourceId
         });
         return ari.toString();
     }
-    constructor(graphqlClient, cloudIdTranslator, bitbucketTranslator, pause) {
+    constructor(graphqlClient, sitedProductTranslator, bitbucketTranslator, pause) {
         this.graphqlClient = graphqlClient;
-        this.cloudIdTranslator = cloudIdTranslator;
+        this.sitedProductTranslator = sitedProductTranslator;
         this.bitbucketTranslator = bitbucketTranslator;
         this.pause = pause;
     }
     async buildInstallationContext(product, site) {
@@ -99,9 +99,9 @@
     getProductTranslation(product) {
         if (product && (0, cli_shared_1.isBitbucketProduct)(product)) {
             return this.bitbucketTranslator;
         }
-        return this.cloudIdTranslator;
+        return this.sitedProductTranslator;
     }
     async installAppIntoSite({ environmentKey, site, product, appId, licenseOverride, overrides }) {
         const workspaceAri = await this.buildInstallationContext(product, site);
         const query = `
@@ -259,8 +259,34 @@
             return matchedInstallation;
         }
         throw new InstallationNotFoundError(cli_shared_1.Text.installationId.errors.notFound(installationId));
     }
+    async hasNoAppInstallationsForEnv(appId, appEnv) {
+        const query = `
+      query forge_cli_hasNoAppInstallationsForEnv($filter: AppInstallationsByAppFilter!) {
+        ecosystem {
+          appInstallationsByApp(filter: $filter, first: 1) {
+            totalCount
+          }
+        }
+      }
+    `;
+        const result = (await this.graphqlClient.query(query, {
+            filter: {
+                apps: {
+                    ids: [appId]
+                },
+                appEnvironments: {
+                    types: [appEnv]
+                }
+            }
+        }));
+        const totalCount = result?.ecosystem?.appInstallationsByApp?.totalCount ?? -1;
+        if (totalCount < 0) {
+            throw new MissingAppError();
+        }
+        return totalCount === 0;
+    }
     async getAppInstallationTask(taskId) {
         const query = `
       query forge_cli_getInstallationTask($id: ID!) {
         appInstallationTask(id: $id) {
@@ -314,11 +340,13 @@
         return [...new Set(installationContexts.filter((context) => condition(context)))];
     }
     async getCombinedHostnameMap(installationContexts) {
         const bitbucketAris = this.getResourceArisForProduct(installationContexts, this.bitbucketTranslator.ariBelongsToProduct);
-        const bbWorkspaceAriToHostname = await this.bitbucketTranslator.getSitesForResourceAris(bitbucketAris);
-        const cloudIdAris = this.getResourceArisForProduct(installationContexts, this.cloudIdTranslator.ariBelongsToProduct);
-        const siteAriToHostname = await this.cloudIdTranslator.getSitesForResourceAris(cloudIdAris);
+        const cloudIdAris = this.getResourceArisForProduct(installationContexts, this.sitedProductTranslator.ariBelongsToProduct);
+        const [siteAriToHostname, bbWorkspaceAriToHostname] = await Promise.all([
+            this.sitedProductTranslator.getSitesForResourceAris(cloudIdAris),
+            this.bitbucketTranslator.getSitesForResourceAris(bitbucketAris)
+        ]);
         const combinedAriToHostname = {
             ...siteAriToHostname,
             ...bbWorkspaceAriToHostname
         };
@@ -332,14 +360,21 @@
         const combinedAriToHostname = await this.getCombinedHostnameMap(installationContexts);
         return installationContexts.map((context, i) => {
             const { environment, environmentType, installation } = installations[i];
             const site = combinedAriToHostname[context.toString()];
+            const secondaryProducts = (installation.secondaryInstallationContexts ?? [])
+                .map((context) => (0, cli_shared_1.parseInstallationContext)(context))
+                .map((context) => context.resourceOwner);
             return {
                 id: installation.id,
+                ...(secondaryProducts.length > 0 ? { secondaryProducts } : {}),
                 product: context.resourceOwner,
                 environmentKey: environment,
                 environmentType,
                 context: installation.installationContext,
+                ...(installation.secondaryInstallationContexts?.length
+                    ? { secondaryContexts: installation.secondaryInstallationContexts }
+                    : {}),
                 site,
                 version: installation.appEnvironmentVersion || {
                     isLatest: false,
                     version: '1.0.0'
@@ -354,8 +389,9 @@
           appInstallationsByApp(filter: $filter, first: $first, after: $after) {
             nodes {
               id
               installationContext
+              secondaryInstallationContexts
               appEnvironment {
                 key
                 type
               }
@@ -413,8 +449,9 @@
           environmentByKey(key: $environmentKey) {
             type
             versions(first: $firstN) {
               nodes {
+                primaryProduct
                 permissions {
                   egress {
                     addresses
                   }