@forge/cli 10.13.6 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +251 -0
  2. package/LICENSE.txt +7 -0
  3. package/npm-shrinkwrap.json +142 -130
  4. package/out/autocomplete/autocomplete-config.json +26 -0
  5. package/out/command-line/command.d.ts +15 -2
  6. package/out/command-line/command.d.ts.map +1 -1
  7. package/out/command-line/command.js +29 -6
  8. package/out/command-line/controller/deploy-controller.d.ts.map +1 -1
  9. package/out/command-line/controller/deploy-controller.js +4 -7
  10. package/out/command-line/controller/install-controller.d.ts +3 -3
  11. package/out/command-line/controller/install-controller.d.ts.map +1 -1
  12. package/out/command-line/controller/install-controller.js +16 -13
  13. package/out/command-line/controller/version-controller.d.ts +36 -0
  14. package/out/command-line/controller/version-controller.d.ts.map +1 -0
  15. package/out/command-line/controller/version-controller.js +114 -0
  16. package/out/command-line/dependency-injection.d.ts +4 -1
  17. package/out/command-line/dependency-injection.d.ts.map +1 -1
  18. package/out/command-line/dependency-injection.js +14 -6
  19. package/out/command-line/index.d.ts +1 -1
  20. package/out/command-line/index.d.ts.map +1 -1
  21. package/out/command-line/index.js +6 -4
  22. package/out/command-line/register-app-commands.d.ts.map +1 -1
  23. package/out/command-line/register-app-commands.js +9 -1
  24. package/out/command-line/register-installation-commands.d.ts +2 -10
  25. package/out/command-line/register-installation-commands.d.ts.map +1 -1
  26. package/out/command-line/register-installation-commands.js +29 -32
  27. package/out/command-line/register-version-commands.d.ts +4 -0
  28. package/out/command-line/register-version-commands.d.ts.map +1 -0
  29. package/out/command-line/register-version-commands.js +76 -0
  30. package/out/command-line/register-webtrigger-commands.d.ts +1 -1
  31. package/out/command-line/register-webtrigger-commands.d.ts.map +1 -1
  32. package/out/command-line/register-webtrigger-commands.js +13 -5
  33. package/out/command-line/view/deploy-view.d.ts +1 -1
  34. package/out/command-line/view/deploy-view.d.ts.map +1 -1
  35. package/out/command-line/view/deploy-view.js +2 -2
  36. package/out/command-line/view/version-view.d.ts +26 -0
  37. package/out/command-line/view/version-view.d.ts.map +1 -0
  38. package/out/command-line/view/version-view.js +198 -0
  39. package/out/environment/graphql-client.d.ts +1 -0
  40. package/out/environment/graphql-client.d.ts.map +1 -1
  41. package/out/environment/graphql-client.js +3 -1
  42. package/out/environment/list-environment.d.ts +1 -0
  43. package/out/environment/list-environment.d.ts.map +1 -1
  44. package/out/installations/graphql-client.d.ts +6 -5
  45. package/out/installations/graphql-client.d.ts.map +1 -1
  46. package/out/installations/graphql-client.js +44 -7
  47. package/out/installations/installation-helper.d.ts.map +1 -1
  48. package/out/installations/installation-helper.js +1 -1
  49. package/out/installations/site-translation/bitbucket.d.ts +3 -4
  50. package/out/installations/site-translation/bitbucket.d.ts.map +1 -1
  51. package/out/installations/site-translation/bitbucket.js +1 -1
  52. package/out/installations/site-translation/index.d.ts +1 -1
  53. package/out/installations/site-translation/index.d.ts.map +1 -1
  54. package/out/installations/site-translation/index.js +1 -1
  55. package/out/installations/site-translation/site-translation.d.ts +3 -4
  56. package/out/installations/site-translation/site-translation.d.ts.map +1 -1
  57. package/out/installations/site-translation/sited-products.d.ts +29 -0
  58. package/out/installations/site-translation/sited-products.d.ts.map +1 -0
  59. package/out/installations/site-translation/sited-products.js +133 -0
  60. package/out/service/installation-service.d.ts +18 -4
  61. package/out/service/installation-service.d.ts.map +1 -1
  62. package/out/service/installation-service.js +44 -10
  63. package/out/service/tunnel-service.d.ts.map +1 -1
  64. package/out/service/tunnel-service.js +1 -1
  65. package/out/service/version-service.d.ts +77 -0
  66. package/out/service/version-service.d.ts.map +1 -0
  67. package/out/service/version-service.js +163 -0
  68. package/out/version/graphql-client.d.ts +25 -0
  69. package/out/version/graphql-client.d.ts.map +1 -0
  70. package/out/version/graphql-client.js +144 -0
  71. package/package.json +13 -11
  72. package/out/installations/site-translation/cloudid-products.d.ts +0 -25
  73. package/out/installations/site-translation/cloudid-products.d.ts.map +0 -1
  74. package/out/installations/site-translation/cloudid-products.js +0 -103
@@ -73,7 +73,7 @@ class InstallationNotFoundError extends cli_shared_1.UserError {
73
73
  exports.InstallationNotFoundError = InstallationNotFoundError;
74
74
  class InstallationsGraphqlClient {
75
75
  graphqlClient;
76
- cloudIdTranslator;
76
+ sitedProductTranslator;
77
77
  bitbucketTranslator;
78
78
  pause;
79
79
  SITE_RESOURCE_TYPE = 'site';
@@ -86,9 +86,9 @@ class InstallationsGraphqlClient {
86
86
  });
87
87
  return ari.toString();
88
88
  }
89
- constructor(graphqlClient, cloudIdTranslator, bitbucketTranslator, pause) {
89
+ constructor(graphqlClient, sitedProductTranslator, bitbucketTranslator, pause) {
90
90
  this.graphqlClient = graphqlClient;
91
- this.cloudIdTranslator = cloudIdTranslator;
91
+ this.sitedProductTranslator = sitedProductTranslator;
92
92
  this.bitbucketTranslator = bitbucketTranslator;
93
93
  this.pause = pause;
94
94
  }
@@ -100,7 +100,7 @@ class InstallationsGraphqlClient {
100
100
  if (product && (0, cli_shared_1.isBitbucketProduct)(product)) {
101
101
  return this.bitbucketTranslator;
102
102
  }
103
- return this.cloudIdTranslator;
103
+ return this.sitedProductTranslator;
104
104
  }
105
105
  async installAppIntoSite({ environmentKey, site, product, appId, licenseOverride, overrides }) {
106
106
  const workspaceAri = await this.buildInstallationContext(product, site);
@@ -260,6 +260,32 @@ class InstallationsGraphqlClient {
260
260
  }
261
261
  throw new InstallationNotFoundError(cli_shared_1.Text.installationId.errors.notFound(installationId));
262
262
  }
263
+ async hasNoAppInstallationsForEnv(appId, appEnv) {
264
+ const query = `
265
+ query forge_cli_hasNoAppInstallationsForEnv($filter: AppInstallationsByAppFilter!) {
266
+ ecosystem {
267
+ appInstallationsByApp(filter: $filter, first: 1) {
268
+ totalCount
269
+ }
270
+ }
271
+ }
272
+ `;
273
+ const result = (await this.graphqlClient.query(query, {
274
+ filter: {
275
+ apps: {
276
+ ids: [appId]
277
+ },
278
+ appEnvironments: {
279
+ types: [appEnv]
280
+ }
281
+ }
282
+ }));
283
+ const totalCount = result?.ecosystem?.appInstallationsByApp?.totalCount ?? -1;
284
+ if (totalCount < 0) {
285
+ throw new MissingAppError();
286
+ }
287
+ return totalCount === 0;
288
+ }
263
289
  async getAppInstallationTask(taskId) {
264
290
  const query = `
265
291
  query forge_cli_getInstallationTask($id: ID!) {
@@ -315,9 +341,11 @@ class InstallationsGraphqlClient {
315
341
  }
316
342
  async getCombinedHostnameMap(installationContexts) {
317
343
  const bitbucketAris = this.getResourceArisForProduct(installationContexts, this.bitbucketTranslator.ariBelongsToProduct);
318
- const bbWorkspaceAriToHostname = await this.bitbucketTranslator.getSitesForResourceAris(bitbucketAris);
319
- const cloudIdAris = this.getResourceArisForProduct(installationContexts, this.cloudIdTranslator.ariBelongsToProduct);
320
- const siteAriToHostname = await this.cloudIdTranslator.getSitesForResourceAris(cloudIdAris);
344
+ const cloudIdAris = this.getResourceArisForProduct(installationContexts, this.sitedProductTranslator.ariBelongsToProduct);
345
+ const [siteAriToHostname, bbWorkspaceAriToHostname] = await Promise.all([
346
+ this.sitedProductTranslator.getSitesForResourceAris(cloudIdAris),
347
+ this.bitbucketTranslator.getSitesForResourceAris(bitbucketAris)
348
+ ]);
321
349
  const combinedAriToHostname = {
322
350
  ...siteAriToHostname,
323
351
  ...bbWorkspaceAriToHostname
@@ -333,12 +361,19 @@ class InstallationsGraphqlClient {
333
361
  return installationContexts.map((context, i) => {
334
362
  const { environment, environmentType, installation } = installations[i];
335
363
  const site = combinedAriToHostname[context.toString()];
364
+ const secondaryProducts = (installation.secondaryInstallationContexts ?? [])
365
+ .map((context) => (0, cli_shared_1.parseInstallationContext)(context))
366
+ .map((context) => context.resourceOwner);
336
367
  return {
337
368
  id: installation.id,
369
+ ...(secondaryProducts.length > 0 ? { secondaryProducts } : {}),
338
370
  product: context.resourceOwner,
339
371
  environmentKey: environment,
340
372
  environmentType,
341
373
  context: installation.installationContext,
374
+ ...(installation.secondaryInstallationContexts?.length
375
+ ? { secondaryContexts: installation.secondaryInstallationContexts }
376
+ : {}),
342
377
  site,
343
378
  version: installation.appEnvironmentVersion || {
344
379
  isLatest: false,
@@ -355,6 +390,7 @@ class InstallationsGraphqlClient {
355
390
  nodes {
356
391
  id
357
392
  installationContext
393
+ secondaryInstallationContexts
358
394
  appEnvironment {
359
395
  key
360
396
  type
@@ -414,6 +450,7 @@ class InstallationsGraphqlClient {
414
450
  type
415
451
  versions(first: $firstN) {
416
452
  nodes {
453
+ primaryProduct
417
454
  permissions {
418
455
  egress {
419
456
  addresses
@@ -1 +1 @@
1
- {"version":3,"file":"installation-helper.d.ts","sourceRoot":"","sources":["../../src/installations/installation-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAyC,EAAE,EAAmB,MAAM,mBAAmB,CAAC;AAE/F,wBAAgB,sBAAsB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAWtE;AAED,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,EAAE,EACN,aAAa,EAAE,YAAY,EAAE,EAC7B,uBAAuB,EAAE,MAAM,EAC/B,yBAAyB,EAAE,MAAM,GAChC,OAAO,CAAC,YAAY,CAAC,CAmBvB"}
1
+ {"version":3,"file":"installation-helper.d.ts","sourceRoot":"","sources":["../../src/installations/installation-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAiD,EAAE,EAAmB,MAAM,mBAAmB,CAAC;AAEvG,wBAAgB,sBAAsB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAWtE;AAED,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,EAAE,EACN,aAAa,EAAE,YAAY,EAAE,EAC7B,uBAAuB,EAAE,MAAM,EAC/B,yBAAyB,EAAE,MAAM,GAChC,OAAO,CAAC,YAAY,CAAC,CAmBvB"}
@@ -19,7 +19,7 @@ async function selectSingleInstallation(ui, installations, installationTableProm
19
19
  names: [
20
20
  (0, cli_shared_1.environmentToOption)(environmentKey),
21
21
  site,
22
- (0, cli_shared_1.capitalise)(product),
22
+ (0, cli_shared_1.productDisplayName)(product),
23
23
  cli_shared_1.Text.install.booleanToScope(version.isLatest),
24
24
  (0, semver_1.major)(version.version).toString()
25
25
  ],
@@ -1,16 +1,15 @@
1
1
  /// <reference types="node" />
2
2
  import { SiteTranslator } from './site-translation';
3
3
  import { URL } from 'url';
4
- import { Ari } from '@forge/util/packages/ari';
5
- import { EnrichedAri } from '@forge/cli-shared';
4
+ import { Ari, AnyAri } from '@forge/util/packages/ari';
6
5
  export declare class InvalidWorkspaceError extends Error {
7
6
  constructor(url: URL);
8
7
  }
9
8
  export declare const getBitbucketEndpoint: () => string;
10
9
  export declare class BitbucketTranslator implements SiteTranslator {
11
- ariBelongsToProduct(ari: EnrichedAri): boolean;
10
+ ariBelongsToProduct(ari: AnyAri): boolean;
12
11
  buildInstallationContext(product: string, site: URL): Promise<Ari>;
13
- getSitesForResourceAris(aris: EnrichedAri[]): Promise<Record<string, string>>;
12
+ getSitesForResourceAris(aris: AnyAri[]): Promise<Record<string, string>>;
14
13
  private getWorkspaceId;
15
14
  getWorkspaceUrl(workspaceId: string): Promise<URL | null>;
16
15
  private decorateWorkspaceId;
@@ -1 +1 @@
1
- {"version":3,"file":"bitbucket.d.ts","sourceRoot":"","sources":["../../../src/installations/site-translation/bitbucket.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAU,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,WAAW,EAA0B,MAAM,mBAAmB,CAAC;AAExE,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,GAAG,EAAE,GAAG;CAGrB;AAOD,eAAO,MAAM,oBAAoB,QAAO,MAEvC,CAAC;AAEF,qBAAa,mBAAoB,YAAW,cAAc;IACjD,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO;IAIxC,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAUlE,uBAAuB,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAc5E,cAAc;IAwBf,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAsBtE,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,iBAAiB;CAG1B"}
1
+ {"version":3,"file":"bitbucket.d.ts","sourceRoot":"","sources":["../../../src/installations/site-translation/bitbucket.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAGvD,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,GAAG,EAAE,GAAG;CAGrB;AAOD,eAAO,MAAM,oBAAoB,QAAO,MAEvC,CAAC;AAEF,qBAAa,mBAAoB,YAAW,cAAc;IACjD,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAInC,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAUlE,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAcvE,cAAc;IAwBf,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAsBtE,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,iBAAiB;CAG1B"}
@@ -94,7 +94,7 @@ class BitbucketTranslator {
94
94
  if (workspaceURL.hostname !== BITBUCKET_URL.hostname) {
95
95
  throw new InvalidWorkspaceError(workspaceURL);
96
96
  }
97
- const pathnames = workspaceURL.pathname.substr(1).split('/');
97
+ const pathnames = workspaceURL.pathname.substring(1).split('/');
98
98
  if (!pathnames.length) {
99
99
  throw new InvalidWorkspaceError(workspaceURL);
100
100
  }
@@ -1,4 +1,4 @@
1
1
  export * from './bitbucket';
2
- export * from './cloudid-products';
2
+ export * from './sited-products';
3
3
  export * from './site-translation';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/installations/site-translation/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/installations/site-translation/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC"}
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./bitbucket"), exports);
5
- tslib_1.__exportStar(require("./cloudid-products"), exports);
5
+ tslib_1.__exportStar(require("./sited-products"), exports);
6
6
  tslib_1.__exportStar(require("./site-translation"), exports);
@@ -1,10 +1,9 @@
1
1
  /// <reference types="node" />
2
2
  import { URL } from 'url';
3
- import { Ari } from '@forge/util/packages/ari';
4
- import { EnrichedAri } from '@forge/cli-shared';
3
+ import { AnyAri, Ari } from '@forge/util/packages/ari';
5
4
  export interface SiteTranslator {
6
5
  buildInstallationContext: (product: string, site: URL) => Promise<Ari>;
7
- getSitesForResourceAris: (ari: EnrichedAri[]) => Promise<Record<string, string>>;
8
- ariBelongsToProduct: (ari: EnrichedAri) => boolean;
6
+ getSitesForResourceAris: (ari: AnyAri[]) => Promise<Record<string, string>>;
7
+ ariBelongsToProduct: (ari: AnyAri) => boolean;
9
8
  }
10
9
  //# sourceMappingURL=site-translation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"site-translation.d.ts","sourceRoot":"","sources":["../../../src/installations/site-translation/site-translation.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,wBAAwB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAEvE,uBAAuB,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjF,mBAAmB,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC;CACpD"}
1
+ {"version":3,"file":"site-translation.d.ts","sourceRoot":"","sources":["../../../src/installations/site-translation/site-translation.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,wBAAwB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAEvE,uBAAuB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E,mBAAmB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CAC/C"}
@@ -0,0 +1,29 @@
1
+ /// <reference types="node" />
2
+ import { SiteTranslator } from './site-translation';
3
+ import { URL } from 'url';
4
+ import { AnyAri, Ari } from '@forge/util/packages/ari';
5
+ import { GraphQLClient, UserError } from '@forge/cli-shared';
6
+ export declare const GRAPH_PRODUCT_ID_IN_TCS = "devops";
7
+ export declare class InvalidAtlassianSiteError extends UserError {
8
+ constructor(url: URL);
9
+ }
10
+ declare type CloudIdAndActivationId = {
11
+ cloudId: string;
12
+ activationId: string;
13
+ };
14
+ export declare class ActivationIdMissingError extends Error {
15
+ constructor(url: string, product: string);
16
+ }
17
+ export declare class SitedProductTranslator implements SiteTranslator {
18
+ private graphqlClient;
19
+ constructor(graphqlClient: GraphQLClient);
20
+ ariBelongsToProduct(ari: AnyAri): boolean;
21
+ buildInstallationContext(product: string, site: URL): Promise<Ari>;
22
+ getSitesForResourceAris(aris: AnyAri[]): Promise<Record<string, string>>;
23
+ private queryHostnamesByCloudIds;
24
+ private queryHostnamesByActivationIds;
25
+ private bulkQuerySiteHostnames;
26
+ getCloudIdAndActivationId(site: URL, productResourceOwner: string): Promise<CloudIdAndActivationId>;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=sited-products.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sited-products.d.ts","sourceRoot":"","sources":["../../../src/installations/site-translation/sited-products.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAIL,aAAa,EAOb,SAAS,EAEV,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAShD,qBAAa,yBAA0B,SAAQ,SAAS;gBAC1C,GAAG,EAAE,GAAG;CAGrB;AAED,aAAK,sBAAsB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;AACxE,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAGzC;AAmCD,qBAAa,sBAAuB,YAAW,cAAc;IAC/C,OAAO,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAEzC,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAQnC,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAQlE,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAkCrF,OAAO,CAAC,wBAAwB,CAqB9B;IAEF,OAAO,CAAC,6BAA6B,CAiBnC;YAEY,sBAAsB;IAmBvB,yBAAyB,CAAC,IAAI,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;CAqBjH"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SitedProductTranslator = exports.ActivationIdMissingError = exports.InvalidAtlassianSiteError = exports.GRAPH_PRODUCT_ID_IN_TCS = void 0;
4
+ const cli_shared_1 = require("@forge/cli-shared");
5
+ exports.GRAPH_PRODUCT_ID_IN_TCS = 'devops';
6
+ const PRODUCT_RESOURCE_OWNER_TO_TCS_PRODUCT_ID = {
7
+ graph: exports.GRAPH_PRODUCT_ID_IN_TCS
8
+ };
9
+ const NON_SITED_PRODUCTS_USING_WORKSPACE_ARI = [cli_shared_1.TRELLO_RESOURCE_OWNER, cli_shared_1.BITBUCKET_RESOURCE_OWNER];
10
+ class InvalidAtlassianSiteError extends cli_shared_1.UserError {
11
+ constructor(url) {
12
+ super(cli_shared_1.Text.install.error.invalidAtlassianSite(url));
13
+ }
14
+ }
15
+ exports.InvalidAtlassianSiteError = InvalidAtlassianSiteError;
16
+ class ActivationIdMissingError extends Error {
17
+ constructor(url, product) {
18
+ super(cli_shared_1.Text.install.error.activationIdMissing(url, product));
19
+ }
20
+ }
21
+ exports.ActivationIdMissingError = ActivationIdMissingError;
22
+ function removeDuplicatedAris(aris) {
23
+ return Array.from(new Map(aris.map((ari) => [ari.toString(), ari])).values());
24
+ }
25
+ const tenantContextsToCloudIdAndActivationId = (url, contexts, productResourceOwner) => {
26
+ if (!contexts.length) {
27
+ throw new InvalidAtlassianSiteError(url);
28
+ }
29
+ const context = contexts[0];
30
+ if (!context || !context.cloudId) {
31
+ throw new InvalidAtlassianSiteError(url);
32
+ }
33
+ const activationId = context.activationIdByProduct?.active;
34
+ if (!activationId) {
35
+ throw new ActivationIdMissingError(url.toString(), (0, cli_shared_1.productDisplayName)(productResourceOwner));
36
+ }
37
+ return { cloudId: context.cloudId, activationId: activationId };
38
+ };
39
+ function splitArrayToChunks(array, chunkSize) {
40
+ const chunks = [];
41
+ for (let i = 0; i < array.length; i += chunkSize) {
42
+ chunks.push(array.slice(i, i + chunkSize));
43
+ }
44
+ return chunks;
45
+ }
46
+ class SitedProductTranslator {
47
+ graphqlClient;
48
+ constructor(graphqlClient) {
49
+ this.graphqlClient = graphqlClient;
50
+ }
51
+ ariBelongsToProduct(ari) {
52
+ return (ari.resourceType === cli_shared_1.SITE_RESOURCE_TYPE ||
53
+ (ari.resourceType === cli_shared_1.WORKSPACE_RESOURCE_TYPE &&
54
+ !NON_SITED_PRODUCTS_USING_WORKSPACE_ARI.includes(ari.resourceOwner)));
55
+ }
56
+ async buildInstallationContext(product, site) {
57
+ const productResourceOwner = (0, cli_shared_1.ariResourceOwner)(product);
58
+ const { cloudId, activationId } = await this.getCloudIdAndActivationId(site, productResourceOwner);
59
+ const workspaceAriCreator = cli_shared_1.createWorkspaceAriByProduct[productResourceOwner];
60
+ return workspaceAriCreator(cloudId, activationId);
61
+ }
62
+ async getSitesForResourceAris(aris) {
63
+ const uniqueAris = removeDuplicatedAris(aris);
64
+ const arisWithCloudId = uniqueAris.filter((ari) => ari.resourceType == cli_shared_1.SITE_RESOURCE_TYPE || !!ari.cloudId);
65
+ const arisWithOnlyActivationId = uniqueAris.filter((ari) => ari.resourceType == cli_shared_1.WORKSPACE_RESOURCE_TYPE && !ari.cloudId);
66
+ const [cloudIdArisToHostname, activationIdArisToHostname] = await Promise.all([
67
+ this.bulkQuerySiteHostnames(arisWithCloudId, (ari) => ari.cloudId || ari.resourceId, this.queryHostnamesByCloudIds),
68
+ this.bulkQuerySiteHostnames(arisWithOnlyActivationId, (ari) => ari.resourceId, this.queryHostnamesByActivationIds)
69
+ ]);
70
+ return {
71
+ ...cloudIdArisToHostname,
72
+ ...activationIdArisToHostname
73
+ };
74
+ }
75
+ queryHostnamesByCloudIds = async (cloudIds) => {
76
+ const query = `
77
+ query forge_cli_getHostnameForTenantContexts($cloudIds: [ID!]!) {
78
+ tenantContexts(cloudIds: $cloudIds) {
79
+ hostName
80
+ }
81
+ }
82
+ `;
83
+ const response = await this.graphqlClient.query(query, {
84
+ cloudIds: cloudIds
85
+ });
86
+ return Object.fromEntries(cloudIds.map((id, index) => [
87
+ id,
88
+ response?.tenantContexts?.[index]?.hostName || id
89
+ ]));
90
+ };
91
+ queryHostnamesByActivationIds = async (activationIds) => {
92
+ const query = `
93
+ query forge_cli_getHostnameForTenantContexts($activationIds: [ID!]!) {
94
+ tenantContexts(activationIds: $activationIds) {
95
+ hostName
96
+ }
97
+ }
98
+ `;
99
+ const response = await this.graphqlClient.query(query, {
100
+ activationIds: activationIds
101
+ });
102
+ return Object.fromEntries(activationIds.map((id, index) => [id, response?.tenantContexts?.[index]?.hostName]));
103
+ };
104
+ async bulkQuerySiteHostnames(aris, idExtractor, querySiteHostnameFunction) {
105
+ if (aris.length === 0) {
106
+ return {};
107
+ }
108
+ const idsToQuery = [...new Set(aris.map(idExtractor))];
109
+ const idsChunks = splitArrayToChunks(idsToQuery, 20);
110
+ const chunkedMapping = await Promise.all(idsChunks.map(querySiteHostnameFunction));
111
+ const fullMapping = Object.assign({}, ...chunkedMapping);
112
+ return Object.fromEntries(aris.map((ari) => [ari.toString(), fullMapping[idExtractor(ari)]]));
113
+ }
114
+ async getCloudIdAndActivationId(site, productResourceOwner) {
115
+ const query = `
116
+ query getTenantContextDetails($hostNames: [String!], $product: String!) {
117
+ tenantContexts(hostNames: $hostNames) {
118
+ cloudId
119
+ activationIdByProduct(product: $product) {
120
+ active
121
+ }
122
+ }
123
+ }
124
+ `;
125
+ const result = await this.graphqlClient.query(query, {
126
+ hostNames: [site.hostname],
127
+ product: PRODUCT_RESOURCE_OWNER_TO_TCS_PRODUCT_ID[productResourceOwner] || productResourceOwner
128
+ });
129
+ const tenantContexts = result.tenantContexts || [];
130
+ return tenantContextsToCloudIdAndActivationId(site, tenantContexts, productResourceOwner);
131
+ }
132
+ }
133
+ exports.SitedProductTranslator = SitedProductTranslator;
@@ -1,14 +1,16 @@
1
1
  /// <reference types="node" />
2
- import { AppConfigProvider, AppEnvironmentType, AppEnvironmentVersion, Maybe } from '@forge/cli-shared';
2
+ import { AppConfigProvider, AppEnvironmentType, AppEnvironmentVersion, Maybe, SupportedProduct, BaseError } from '@forge/cli-shared';
3
3
  import { URL } from 'url';
4
4
  import { AppInstallSiteDetails } from '../installations/install-app-site';
5
5
  export interface Installation {
6
6
  id: string;
7
7
  product: string;
8
+ secondaryProducts?: string[];
8
9
  site: string;
9
10
  environmentKey: string;
10
11
  environmentType: AppEnvironmentType;
11
12
  context: string;
13
+ secondaryContexts?: string[];
12
14
  version: {
13
15
  isLatest: boolean;
14
16
  version: string;
@@ -20,6 +22,7 @@ export interface AppInstallation {
20
22
  export interface AppEnvironmentVersionPermissions {
21
23
  scopes: string[];
22
24
  egressAddresses: string[];
25
+ primaryProduct?: string;
23
26
  }
24
27
  export interface AppEnvironmentPermissions extends AppEnvironmentVersionPermissions {
25
28
  addedScopes: string[];
@@ -27,8 +30,8 @@ export interface AppEnvironmentPermissions extends AppEnvironmentVersionPermissi
27
30
  hasDeployments: boolean;
28
31
  }
29
32
  interface InstallationFilterOptions {
30
- site?: string;
31
- product?: 'Jira' | 'Confluence';
33
+ site?: URL;
34
+ product?: SupportedProduct;
32
35
  environment?: string;
33
36
  }
34
37
  export interface AppEnvironmentVersionData {
@@ -42,14 +45,25 @@ export interface ListAppInstallationsClient {
42
45
  export interface UpgradeAppInstallationsClient {
43
46
  upgradeInstallation({ site, product, environmentKey, appId }: AppInstallSiteDetails): Promise<void>;
44
47
  }
48
+ export interface HasNoAppInstallationsForEnvClient {
49
+ hasNoAppInstallationsForEnv(appId: string, appEnv: AppEnvironmentType): Promise<boolean>;
50
+ }
51
+ export declare class MultipleMatchingInstallationsError extends BaseError {
52
+ constructor();
53
+ }
45
54
  export declare class InstallationService {
46
55
  private readonly getAppConfig;
47
56
  private readonly listInstallationsClient;
48
57
  private readonly upgradeAppInstallationsClient;
49
- constructor(getAppConfig: AppConfigProvider, listInstallationsClient: ListAppInstallationsClient, upgradeAppInstallationsClient: UpgradeAppInstallationsClient);
58
+ private readonly hasNoAppInstallationsForEnvClient;
59
+ constructor(getAppConfig: AppConfigProvider, listInstallationsClient: ListAppInstallationsClient, upgradeAppInstallationsClient: UpgradeAppInstallationsClient, hasNoAppInstallationsForEnvClient: HasNoAppInstallationsForEnvClient);
60
+ private comparePossibleInstallations;
61
+ private matchSiteForProduct;
50
62
  private filterInstallations;
51
63
  listAppInstallations(filter?: InstallationFilterOptions): Promise<AppInstallation>;
64
+ hasNoAppInstallationsForEnv(appEnv: AppEnvironmentType): Promise<boolean>;
52
65
  listNonTechnicalAppInstallations(filter?: InstallationFilterOptions): Promise<AppInstallation>;
66
+ findOnlyMatchingInstallation(filter: InstallationFilterOptions): Promise<Installation>;
53
67
  hasOutdatedProductInstallation(environment: string): Promise<boolean>;
54
68
  upgradeInstallation(site: URL, product: string, environmentKey: string, appId: string): Promise<boolean>;
55
69
  private getPermissionsFromAppEnvironmentVersion;
@@ -1 +1 @@
1
- {"version":3,"file":"installation-service.d.ts","sourceRoot":"","sources":["../../src/service/installation-service.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EAKrB,KAAK,EAEN,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,kBAAkB,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,QAAQ,EAAE,OAAO,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,yBAA0B,SAAQ,gCAAgC;IACjF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,kBAAkB,CAAC;IACpC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,yBAAyB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,GAAG,IAAI,CAAC;IACnD,eAAe,EAAE,kBAAkB,CAAC;CACrC;AAED,MAAM,WAAW,0BAA0B;IACzC,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC1D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;CACxG;AAED,MAAM,WAAW,6BAA6B;IAC5C,mBAAmB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrG;AAKD,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,6BAA6B;gBAF7B,YAAY,EAAE,iBAAiB,EAC/B,uBAAuB,EAAE,0BAA0B,EACnD,6BAA6B,EAAE,6BAA6B;IAG/E,OAAO,CAAC,mBAAmB;IAiBd,oBAAoB,CAAC,MAAM,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,eAAe,CAAC;IAOlF,gCAAgC,CAAC,MAAM,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,eAAe,CAAC;IAU9F,8BAA8B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOrE,mBAAmB,CAC9B,IAAI,EAAE,GAAG,EACT,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC;IAkBnB,OAAO,CAAC,uCAAuC;IAgBlC,4BAA4B,CACvC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC;CAiClD"}
1
+ {"version":3,"file":"installation-service.d.ts","sourceRoot":"","sources":["../../src/service/installation-service.ts"],"names":[],"mappings":"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"}
@@ -1,29 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InstallationService = void 0;
3
+ exports.InstallationService = exports.MultipleMatchingInstallationsError = void 0;
4
4
  const cli_shared_1 = require("@forge/cli-shared");
5
5
  const egress_1 = require("@forge/egress");
6
6
  const lodash_1 = require("lodash");
7
7
  const graphql_client_1 = require("../installations/graphql-client");
8
8
  const IDENTITY_PRODUCT_NAME = 'identity';
9
+ const BITBUCKET_PRODUCT_NAME = 'bitbucket';
9
10
  const JIRA_SERVICE_DESK_PRODUCT_NAME = 'jira-servicedesk';
11
+ class MultipleMatchingInstallationsError extends cli_shared_1.BaseError {
12
+ constructor() {
13
+ super(cli_shared_1.Text.error.multipleMatchingInstallations);
14
+ }
15
+ }
16
+ exports.MultipleMatchingInstallationsError = MultipleMatchingInstallationsError;
10
17
  class InstallationService {
11
18
  getAppConfig;
12
19
  listInstallationsClient;
13
20
  upgradeAppInstallationsClient;
14
- constructor(getAppConfig, listInstallationsClient, upgradeAppInstallationsClient) {
21
+ hasNoAppInstallationsForEnvClient;
22
+ constructor(getAppConfig, listInstallationsClient, upgradeAppInstallationsClient, hasNoAppInstallationsForEnvClient) {
15
23
  this.getAppConfig = getAppConfig;
16
24
  this.listInstallationsClient = listInstallationsClient;
17
25
  this.upgradeAppInstallationsClient = upgradeAppInstallationsClient;
26
+ this.hasNoAppInstallationsForEnvClient = hasNoAppInstallationsForEnvClient;
27
+ }
28
+ comparePossibleInstallations(url1, url2) {
29
+ const trimmedUrl1 = url1.replace(/\/+$/, '');
30
+ const trimmedUrl2 = url2.replace(/\/+$/, '');
31
+ return trimmedUrl1 === trimmedUrl2;
32
+ }
33
+ matchSiteForProduct(filterSite, installationSite, installationProduct) {
34
+ if (installationProduct === BITBUCKET_PRODUCT_NAME) {
35
+ return this.comparePossibleInstallations(filterSite.href, installationSite);
36
+ }
37
+ return this.comparePossibleInstallations(filterSite.host, installationSite);
18
38
  }
19
39
  filterInstallations(installations, { site: filterSite, product: filterProduct, environment: filterEnvironment }) {
20
- const isDefaultEnvironment = (env) => env === (0, cli_shared_1.optionToEnvironment)(cli_shared_1.DEFAULT_ENVIRONMENT_OPTION);
21
40
  return installations.filter(({ product, site, environmentKey }) => {
22
41
  const matchProduct = !filterProduct || filterProduct === (0, cli_shared_1.productDisplayName)(product);
23
- const matchSite = !filterSite || filterSite === site;
24
- const matchEnvironment = filterEnvironment
25
- ? isDefaultEnvironment(filterEnvironment) || filterEnvironment === (0, cli_shared_1.environmentToOption)(environmentKey)
26
- : true;
42
+ const matchSite = !filterSite || this.matchSiteForProduct(filterSite, site, product);
43
+ const matchEnvironment = !filterEnvironment || filterEnvironment === (0, cli_shared_1.optionToEnvironment)(environmentKey);
27
44
  return matchProduct && matchSite && matchEnvironment;
28
45
  });
29
46
  }
@@ -32,12 +49,26 @@ class InstallationService {
32
49
  const installations = await this.listInstallationsClient.listInstallations(appId);
33
50
  return { installations: this.filterInstallations(installations, { ...filter }) };
34
51
  }
52
+ async hasNoAppInstallationsForEnv(appEnv) {
53
+ const { id: appId } = await this.getAppConfig();
54
+ return this.hasNoAppInstallationsForEnvClient.hasNoAppInstallationsForEnv(appId, appEnv);
55
+ }
35
56
  async listNonTechnicalAppInstallations(filter) {
36
57
  const { installations } = await this.listAppInstallations(filter);
37
58
  return {
38
59
  installations: installations.filter(({ product }) => product !== IDENTITY_PRODUCT_NAME && product !== JIRA_SERVICE_DESK_PRODUCT_NAME)
39
60
  };
40
61
  }
62
+ async findOnlyMatchingInstallation(filter) {
63
+ const filterInstalls = await this.listNonTechnicalAppInstallations(filter);
64
+ if (!filterInstalls.installations.length) {
65
+ throw new cli_shared_1.UserError(cli_shared_1.Text.error.invalidInstallationContext);
66
+ }
67
+ if (filterInstalls.installations.length !== 1) {
68
+ throw new MultipleMatchingInstallationsError();
69
+ }
70
+ return filterInstalls.installations[0];
71
+ }
41
72
  async hasOutdatedProductInstallation(environment) {
42
73
  const { installations } = await this.listNonTechnicalAppInstallations({
43
74
  environment
@@ -65,23 +96,25 @@ class InstallationService {
65
96
  }
66
97
  getPermissionsFromAppEnvironmentVersion(appEnvironmentVersion) {
67
98
  const permissions = appEnvironmentVersion?.permissions[0];
99
+ const primaryProduct = appEnvironmentVersion?.primaryProduct ?? undefined;
68
100
  if (!permissions) {
69
- return { scopes: [], egressAddresses: [] };
101
+ return { scopes: [], egressAddresses: [], primaryProduct };
70
102
  }
71
103
  const scopes = permissions.scopes.map((s) => s.key);
72
104
  const egressAddresses = permissions?.egress ? (0, cli_shared_1.flatMap)(permissions.egress, ({ addresses }) => addresses ?? []) : [];
73
- return { scopes, egressAddresses };
105
+ return { scopes, egressAddresses, primaryProduct };
74
106
  }
75
107
  async getAppEnvironmentPermissions(appId, environmentKey) {
76
108
  const versionDetails = await this.listInstallationsClient.getVersions(appId, environmentKey, 2);
77
109
  const versions = versionDetails?.nodes;
78
110
  if (!versions || versions.length === 0)
79
111
  return;
80
- const [{ scopes, egressAddresses }, oldVersion] = versions.map((appEnvironmentVersion) => this.getPermissionsFromAppEnvironmentVersion(appEnvironmentVersion));
112
+ const [{ scopes, egressAddresses, primaryProduct }, oldVersion] = versions.map((appEnvironmentVersion) => this.getPermissionsFromAppEnvironmentVersion(appEnvironmentVersion));
81
113
  const groupedEgressAddresses = (0, egress_1.sortAndGroupEgressPermissionsByDomain)(egressAddresses);
82
114
  if (!oldVersion) {
83
115
  return {
84
116
  scopes,
117
+ primaryProduct,
85
118
  hasDeployments: false,
86
119
  egressAddresses: groupedEgressAddresses,
87
120
  addedScopes: scopes,
@@ -92,6 +125,7 @@ class InstallationService {
92
125
  const addedScopes = (0, lodash_1.difference)(scopes, oldScopes);
93
126
  return {
94
127
  scopes,
128
+ primaryProduct,
95
129
  hasDeployments: true,
96
130
  egressAddresses: groupedEgressAddresses,
97
131
  addedScopes,
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel-service.d.ts","sourceRoot":"","sources":["../../src/service/tunnel-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tunnel-service.d.ts","sourceRoot":"","sources":["../../src/service/tunnel-service.ts"],"names":[],"mappings":"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"}
@@ -240,7 +240,7 @@ class DockerTunnelService extends SandboxTunnelServiceBase {
240
240
  if (process.env.FORGE_DEV_DOCKER_TUNNEL) {
241
241
  const monorepoRoot = (0, path_1.join)(__dirname, '../../../..');
242
242
  options.push(`-v=${monorepoRoot}:/monorepo:cached`);
243
- options.push(`-v=${monorepoRoot}/node_modules/@koterpillar/cloudflared/docker-bin:/monorepo/node_modules/@koterpillar/cloudflared/bin`);
243
+ options.push(`-v=${monorepoRoot}/node_modules/cloudflared/docker-bin:/monorepo/node_modules/cloudflared/bin`);
244
244
  }
245
245
  if (process.env.FORGE_TUNNEL_MOUNT_DIRECTORIES) {
246
246
  const mounts = process.env.FORGE_TUNNEL_MOUNT_DIRECTORIES.split(',');