@appsemble/cli 0.27.10 → 0.27.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/app.js CHANGED
@@ -20,12 +20,16 @@ import { publishResourcesRecursively } from './resource.js';
20
20
  * Traverses an app directory and appends the files it finds to the given FormData object.
21
21
  *
22
22
  * @param path The path of the app directory to traverse.
23
+ * @param context The Context to use from `.appsemblerc.yaml`.
23
24
  * @param formData The FormData object to append the results into..
24
25
  * @returns The context from `.appsemblerc.yaml` if a match was found.
25
26
  */
26
- export async function traverseAppDirectory(path, formData) {
27
+ export async function traverseAppDirectory(path, context, formData) {
27
28
  let rc;
29
+ let discoveredContext;
28
30
  let yaml;
31
+ let iconPath;
32
+ let maskableIconPath;
29
33
  let controllerPath;
30
34
  let controllerBuildConfig;
31
35
  let controllerBuildResult;
@@ -60,6 +64,10 @@ export async function traverseAppDirectory(path, formData) {
60
64
  formData.append('iconBackground', rc.iconBackground);
61
65
  gatheredData.iconBackground = rc.iconBackground;
62
66
  }
67
+ if (context && has(rc === null || rc === void 0 ? void 0 : rc.context, context)) {
68
+ discoveredContext = rc.context[context];
69
+ logger.verbose(`Using context: ${inspect(discoveredContext, { colors: true })}`);
70
+ }
63
71
  break;
64
72
  case 'app-definition.yaml': {
65
73
  logger.info(`Using app definition from ${filepath}`);
@@ -74,10 +82,12 @@ export async function traverseAppDirectory(path, formData) {
74
82
  }
75
83
  case 'icon.png':
76
84
  case 'icon.svg':
85
+ iconPath = filepath;
77
86
  gatheredData.iconUrl = filepath;
78
87
  return;
79
88
  case 'maskable-icon.png':
80
- return;
89
+ maskableIconPath = filepath;
90
+ break;
81
91
  case 'screenshots':
82
92
  return opendirSafe(filepath, (screenshotPath, screenshotStat) => {
83
93
  if (screenshotStat.isDirectory() &&
@@ -133,7 +143,14 @@ export async function traverseAppDirectory(path, formData) {
133
143
  if (yaml === undefined) {
134
144
  throw new AppsembleError('No app definition found');
135
145
  }
136
- return [rc, yaml, gatheredData];
146
+ discoveredContext || (discoveredContext = {});
147
+ discoveredContext.icon = discoveredContext.icon
148
+ ? resolve(path, discoveredContext.icon)
149
+ : iconPath;
150
+ discoveredContext.maskableIcon = discoveredContext.maskableIcon
151
+ ? resolve(path, discoveredContext.maskableIcon)
152
+ : maskableIconPath;
153
+ return [discoveredContext, rc, yaml, gatheredData];
137
154
  }
138
155
  async function retrieveContext(path, context) {
139
156
  let rc;
@@ -452,15 +469,45 @@ This block version is not used in the app`);
452
469
  }
453
470
  }
454
471
  /**
455
- * Update an existing app.
472
+ * Resolve the app’s ID and remote based on the app context.
456
473
  *
457
- * @param argv The command line options used for updating the app.
474
+ * @param appPath The path to the app.
475
+ * @param name Which context to use in the AppsembleRC file.
476
+ * @param defaultRemote The remote to fall back to.
477
+ * @param defaultAppId The app ID to fall back to.
478
+ * @returns The resolved app ID and remote.
458
479
  */
459
- export async function updateApp({ clientCredentials, context, force, path, ...options }) {
460
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
480
+ export async function resolveAppIdAndRemote(appPath, name, defaultRemote, defaultAppId) {
481
+ var _a;
482
+ let id = defaultAppId;
483
+ let resolvedRemote = defaultRemote;
484
+ if (appPath) {
485
+ const rcPath = join(appPath, '.appsemblerc.yaml');
486
+ const [rc] = await readData(rcPath);
487
+ const context = (_a = rc.context) === null || _a === void 0 ? void 0 : _a[name];
488
+ if (!defaultAppId) {
489
+ id = context === null || context === void 0 ? void 0 : context.id;
490
+ }
491
+ if (context.remote) {
492
+ resolvedRemote = context.remote;
493
+ }
494
+ }
495
+ if (id == null) {
496
+ throw new AppsembleError(`App ID was not found in context.${name}.id nor in --app-id`);
497
+ }
498
+ return [id, coerceRemote(resolvedRemote)];
499
+ }
500
+ /**
501
+ * Publish a new app.
502
+ *
503
+ * @param options The options to use for publishing an app.
504
+ */
505
+ export async function publishApp({ clientCredentials, context, dryRun, modifyContext, path, ...options }) {
506
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
461
507
  const file = await stat(path);
462
508
  const formData = new FormData();
463
509
  const appsembleContext = await retrieveContext(path, context);
510
+ let rc;
464
511
  let yaml;
465
512
  let filename = relative(process.cwd(), path);
466
513
  const variant = (_b = (_a = appsembleContext.variant) !== null && _a !== void 0 ? _a : options.variant) !== null && _b !== void 0 ? _b : context;
@@ -473,16 +520,24 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
473
520
  logger.warn(`App variant ${variant} is not defined in ${join(path, 'variants')}. Using default app.`);
474
521
  }
475
522
  if (file.isFile()) {
523
+ // Assuming file is App YAML
476
524
  const [, data] = await readData(appVariantPath);
477
525
  yaml = data;
478
526
  formData.append('yaml', data);
479
527
  }
480
528
  else {
481
- [, yaml] = await traverseAppDirectory(appVariantPath, formData);
529
+ let appsembleVariantContext;
530
+ [appsembleVariantContext, rc, yaml] = await traverseAppDirectory(appVariantPath, context, formData);
531
+ if (appsembleVariantContext.icon) {
532
+ appsembleContext.icon = appsembleVariantContext.icon;
533
+ }
534
+ if (appsembleVariantContext.maskableIcon) {
535
+ appsembleContext.maskableIcon = appsembleVariantContext.maskableIcon;
536
+ }
482
537
  filename = join(filename, 'app-definition.yaml');
483
538
  }
484
539
  const remote = (_c = appsembleContext.remote) !== null && _c !== void 0 ? _c : options.remote;
485
- const id = (_d = appsembleContext.id) !== null && _d !== void 0 ? _d : options.id;
540
+ const organizationId = (_d = appsembleContext.organization) !== null && _d !== void 0 ? _d : options.organization;
486
541
  const template = (_f = (_e = appsembleContext.template) !== null && _e !== void 0 ? _e : options.template) !== null && _f !== void 0 ? _f : false;
487
542
  const assetsClonable = (_h = (_g = appsembleContext.assetsClonable) !== null && _g !== void 0 ? _g : options.assetsClonable) !== null && _h !== void 0 ? _h : false;
488
543
  const demoMode = (_k = (_j = appsembleContext.demoMode) !== null && _j !== void 0 ? _j : options.demoMode) !== null && _k !== void 0 ? _k : false;
@@ -493,23 +548,23 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
493
548
  const sentryDsn = (_q = appsembleContext.sentryDsn) !== null && _q !== void 0 ? _q : options.sentryDsn;
494
549
  const sentryEnvironment = (_r = appsembleContext.sentryEnvironment) !== null && _r !== void 0 ? _r : options.sentryEnvironment;
495
550
  const googleAnalyticsId = (_s = appsembleContext.googleAnalyticsId) !== null && _s !== void 0 ? _s : options.googleAnalyticsId;
496
- const resources = (_t = appsembleContext.resources) !== null && _t !== void 0 ? _t : options.resources;
497
- const assets = (_u = appsembleContext.assets) !== null && _u !== void 0 ? _u : options.assets;
498
- const { appLock } = appsembleContext;
499
- logger.info(`App id: ${id}`);
551
+ const assets = (_t = appsembleContext.assets) !== null && _t !== void 0 ? _t : options.assets;
552
+ const resources = (_u = appsembleContext.resources) !== null && _u !== void 0 ? _u : options.resources;
553
+ const appLock = appsembleContext.appLock || 'unlocked';
500
554
  logger.verbose(`App remote: ${remote}`);
555
+ logger.verbose(`App organization: ${organizationId}`);
501
556
  logger.verbose(`App is template: ${inspect(template, { colors: true })}`);
502
557
  logger.verbose(`App visibility: ${visibility}`);
503
558
  logger.verbose(`Icon background: ${iconBackground}`);
504
- logger.verbose(`Force update: ${inspect(force, { colors: true })}`);
505
- if (!id) {
506
- throw new AppsembleError('The app id must be passed as a command line flag or in the context');
559
+ if (!organizationId) {
560
+ throw new AppsembleError('An organization id must be passed as a command line flag or in the context');
507
561
  }
508
- formData.append('force', String(force));
562
+ formData.append('OrganizationId', organizationId);
509
563
  formData.append('template', String(template));
510
564
  formData.append('demoMode', String(demoMode));
511
565
  formData.append('visibility', visibility);
512
566
  formData.append('iconBackground', iconBackground);
567
+ formData.append('locked', appLock);
513
568
  if (icon) {
514
569
  const realIcon = typeof icon === 'string' ? createReadStream(icon) : icon;
515
570
  logger.info(`Using icon from ${(_v = realIcon.path) !== null && _v !== void 0 ? _v : 'stdin'}`);
@@ -536,21 +591,12 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
536
591
  authScope += ' resources:write';
537
592
  }
538
593
  await authenticate(remote, authScope, clientCredentials);
539
- if (appLock) {
540
- logger.info(`Setting AppLock to ${appLock}`);
541
- try {
542
- await axios.post(`/api/apps/${id}/lock`, {
543
- locked: appLock,
544
- });
545
- }
546
- catch (error) {
547
- logger.error(error);
548
- process.exit(1);
549
- }
550
- }
551
594
  let data;
552
595
  try {
553
- ({ data } = await axios.patch(`/api/apps/${id}`, formData, { baseURL: remote }));
596
+ ({ data } = await axios.post('/api/apps', formData, {
597
+ baseURL: remote,
598
+ params: { dryRun: dryRun || undefined },
599
+ }));
554
600
  }
555
601
  catch (error) {
556
602
  if (!axios.isAxiosError(error)) {
@@ -561,38 +607,64 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
561
607
  }
562
608
  throw new AppsembleError(printAxiosError(filename, yaml, error.response.data.data.errors));
563
609
  }
564
- if (file.isDirectory()) {
565
- // After uploading the app, upload block styles and messages if they are available
566
- await traverseBlockThemes(appVariantPath, data.id, remote, force);
567
- await uploadMessages(appVariantPath, data.id, remote, force);
568
- // After updating the app, publish seed resources and assets if they are available
569
- if (assets && (data.locked !== 'fullLock' || force)) {
610
+ if (dryRun) {
611
+ logger.info('Skipped uploading block themes and app messages.');
612
+ logger.info('Successfully ran dry run. The app should be valid when creating it.');
613
+ return;
614
+ }
615
+ if (file.isDirectory() && !dryRun) {
616
+ // After uploading the app, upload block styles, messages if they are available
617
+ await traverseBlockThemes(appVariantPath, data.id, remote, false);
618
+ await uploadMessages(appVariantPath, data.id, remote, false);
619
+ // After uploading the app, publish seed resources and assets if they are available
620
+ if (assets) {
570
621
  await publishSeedAssets(appVariantPath, data, remote, assetsClonable);
571
622
  }
572
- if (resources && (data.locked !== 'fullLock' || force)) {
623
+ if (resources) {
573
624
  await publishSeedResources(appVariantPath, data, remote);
574
625
  }
575
626
  }
627
+ if (modifyContext && appsembleContext && context && !dryRun) {
628
+ rc.context[context].id = data.id;
629
+ await writeData(join(appVariantPath, '.appsemblerc.yaml'), rc, { sort: false });
630
+ logger.info(`Updated .appsemblerc: Set context.${context}.id to ${data.id}`);
631
+ }
576
632
  const { host, protocol } = new URL(remote);
577
- logger.info(`Successfully updated app ${data.definition.name}! 🙌`);
633
+ logger.info(`Successfully published app ${data.definition.name}! 🙌`);
578
634
  logger.info(`App URL: ${protocol}//${data.path}.${data.OrganizationId}.${host}`);
579
635
  logger.info(`App store page: ${new URL(`/apps/${data.id}`, remote)}`);
580
- if (appVariantPath !== path) {
636
+ const rcCollections = (_0 = (_z = rc === null || rc === void 0 ? void 0 : rc.context) === null || _z === void 0 ? void 0 : _z[context]) === null || _0 === void 0 ? void 0 : _0.collections;
637
+ if (Array.isArray(rcCollections)) {
638
+ for (const collectionId of rcCollections) {
639
+ try {
640
+ await axios.post(`/api/appCollections/${collectionId}/apps`, { AppId: data.id }, {
641
+ baseURL: remote,
642
+ });
643
+ logger.info(`Successfully added app to collection ${collectionId}`);
644
+ }
645
+ catch (error) {
646
+ logger.error(error);
647
+ }
648
+ }
649
+ }
650
+ if (appVariantPath !== path && modifyContext && !dryRun) {
651
+ const [defaultAppRc] = await readData(join(path, '.appsemblerc.yaml'));
652
+ defaultAppRc.context[context] = rc.context[context];
653
+ await writeData(join(path, '.appsemblerc.yaml'), defaultAppRc, { sort: false });
581
654
  await rm(appVariantPath, { recursive: true });
582
655
  logger.info(`Removed ${appVariantPath}`);
583
656
  }
584
657
  }
585
658
  /**
586
- * Publish a new app.
659
+ * Update an existing app.
587
660
  *
588
- * @param options The options to use for publishing an app.
661
+ * @param argv The command line options used for updating the app.
589
662
  */
590
- export async function publishApp({ clientCredentials, context, dryRun, modifyContext, path, ...options }) {
591
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
663
+ export async function updateApp({ clientCredentials, context, force, path, ...options }) {
664
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
592
665
  const file = await stat(path);
593
666
  const formData = new FormData();
594
667
  const appsembleContext = await retrieveContext(path, context);
595
- let rc;
596
668
  let yaml;
597
669
  let filename = relative(process.cwd(), path);
598
670
  const variant = (_b = (_a = appsembleContext.variant) !== null && _a !== void 0 ? _a : options.variant) !== null && _b !== void 0 ? _b : context;
@@ -605,17 +677,23 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
605
677
  logger.warn(`App variant ${variant} is not defined in ${join(path, 'variants')}. Using default app.`);
606
678
  }
607
679
  if (file.isFile()) {
608
- // Assuming file is App YAML
609
680
  const [, data] = await readData(appVariantPath);
610
681
  yaml = data;
611
682
  formData.append('yaml', data);
612
683
  }
613
684
  else {
614
- [rc, yaml] = await traverseAppDirectory(appVariantPath, formData);
685
+ let appsembleVariantContext;
686
+ [appsembleVariantContext, , yaml] = await traverseAppDirectory(appVariantPath, context, formData);
687
+ if (appsembleVariantContext.icon) {
688
+ appsembleContext.icon = appsembleVariantContext.icon;
689
+ }
690
+ if (appsembleVariantContext.maskableIcon) {
691
+ appsembleContext.maskableIcon = appsembleVariantContext.maskableIcon;
692
+ }
615
693
  filename = join(filename, 'app-definition.yaml');
616
694
  }
617
695
  const remote = (_c = appsembleContext.remote) !== null && _c !== void 0 ? _c : options.remote;
618
- const organizationId = (_d = appsembleContext.organization) !== null && _d !== void 0 ? _d : options.organization;
696
+ const id = (_d = appsembleContext.id) !== null && _d !== void 0 ? _d : options.id;
619
697
  const template = (_f = (_e = appsembleContext.template) !== null && _e !== void 0 ? _e : options.template) !== null && _f !== void 0 ? _f : false;
620
698
  const assetsClonable = (_h = (_g = appsembleContext.assetsClonable) !== null && _g !== void 0 ? _g : options.assetsClonable) !== null && _h !== void 0 ? _h : false;
621
699
  const demoMode = (_k = (_j = appsembleContext.demoMode) !== null && _j !== void 0 ? _j : options.demoMode) !== null && _k !== void 0 ? _k : false;
@@ -626,23 +704,23 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
626
704
  const sentryDsn = (_q = appsembleContext.sentryDsn) !== null && _q !== void 0 ? _q : options.sentryDsn;
627
705
  const sentryEnvironment = (_r = appsembleContext.sentryEnvironment) !== null && _r !== void 0 ? _r : options.sentryEnvironment;
628
706
  const googleAnalyticsId = (_s = appsembleContext.googleAnalyticsId) !== null && _s !== void 0 ? _s : options.googleAnalyticsId;
629
- const assets = (_t = appsembleContext.assets) !== null && _t !== void 0 ? _t : options.assets;
630
- const resources = (_u = appsembleContext.resources) !== null && _u !== void 0 ? _u : options.resources;
631
- const appLock = appsembleContext.appLock || 'unlocked';
707
+ const resources = (_t = appsembleContext.resources) !== null && _t !== void 0 ? _t : options.resources;
708
+ const assets = (_u = appsembleContext.assets) !== null && _u !== void 0 ? _u : options.assets;
709
+ const { appLock } = appsembleContext;
710
+ logger.info(`App id: ${id}`);
632
711
  logger.verbose(`App remote: ${remote}`);
633
- logger.verbose(`App organization: ${organizationId}`);
634
712
  logger.verbose(`App is template: ${inspect(template, { colors: true })}`);
635
713
  logger.verbose(`App visibility: ${visibility}`);
636
714
  logger.verbose(`Icon background: ${iconBackground}`);
637
- if (!organizationId) {
638
- throw new AppsembleError('An organization id must be passed as a command line flag or in the context');
715
+ logger.verbose(`Force update: ${inspect(force, { colors: true })}`);
716
+ if (!id) {
717
+ throw new AppsembleError('The app id must be passed as a command line flag or in the context');
639
718
  }
640
- formData.append('OrganizationId', organizationId);
719
+ formData.append('force', String(force));
641
720
  formData.append('template', String(template));
642
721
  formData.append('demoMode', String(demoMode));
643
722
  formData.append('visibility', visibility);
644
723
  formData.append('iconBackground', iconBackground);
645
- formData.append('locked', appLock);
646
724
  if (icon) {
647
725
  const realIcon = typeof icon === 'string' ? createReadStream(icon) : icon;
648
726
  logger.info(`Using icon from ${(_v = realIcon.path) !== null && _v !== void 0 ? _v : 'stdin'}`);
@@ -669,12 +747,21 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
669
747
  authScope += ' resources:write';
670
748
  }
671
749
  await authenticate(remote, authScope, clientCredentials);
750
+ if (appLock) {
751
+ logger.info(`Setting AppLock to ${appLock}`);
752
+ try {
753
+ await axios.post(`/api/apps/${id}/lock`, {
754
+ locked: appLock,
755
+ });
756
+ }
757
+ catch (error) {
758
+ logger.error(error);
759
+ process.exit(1);
760
+ }
761
+ }
672
762
  let data;
673
763
  try {
674
- ({ data } = await axios.post('/api/apps', formData, {
675
- baseURL: remote,
676
- params: { dryRun: dryRun || undefined },
677
- }));
764
+ ({ data } = await axios.patch(`/api/apps/${id}`, formData, { baseURL: remote }));
678
765
  }
679
766
  catch (error) {
680
767
  if (!axios.isAxiosError(error)) {
@@ -685,83 +772,27 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
685
772
  }
686
773
  throw new AppsembleError(printAxiosError(filename, yaml, error.response.data.data.errors));
687
774
  }
688
- if (dryRun) {
689
- logger.info('Skipped uploading block themes and app messages.');
690
- logger.info('Successfully ran dry run. The app should be valid when creating it.');
691
- return;
692
- }
693
- if (file.isDirectory() && !dryRun) {
694
- // After uploading the app, upload block styles, messages if they are available
695
- await traverseBlockThemes(appVariantPath, data.id, remote, false);
696
- await uploadMessages(appVariantPath, data.id, remote, false);
697
- // After uploading the app, publish seed resources and assets if they are available
698
- if (assets) {
775
+ if (file.isDirectory()) {
776
+ // After uploading the app, upload block styles and messages if they are available
777
+ await traverseBlockThemes(appVariantPath, data.id, remote, force);
778
+ await uploadMessages(appVariantPath, data.id, remote, force);
779
+ // After updating the app, publish seed resources and assets if they are available
780
+ if (assets && (data.locked !== 'fullLock' || force)) {
699
781
  await publishSeedAssets(appVariantPath, data, remote, assetsClonable);
700
782
  }
701
- if (resources) {
783
+ if (resources && (data.locked !== 'fullLock' || force)) {
702
784
  await publishSeedResources(appVariantPath, data, remote);
703
785
  }
704
786
  }
705
- if (modifyContext && appsembleContext && context && !dryRun) {
706
- rc.context[context].id = data.id;
707
- await writeData(join(appVariantPath, '.appsemblerc.yaml'), rc, { sort: false });
708
- logger.info(`Updated .appsemblerc: Set context.${context}.id to ${data.id}`);
709
- }
710
787
  const { host, protocol } = new URL(remote);
711
- logger.info(`Successfully published app ${data.definition.name}! 🙌`);
788
+ logger.info(`Successfully updated app ${data.definition.name}! 🙌`);
712
789
  logger.info(`App URL: ${protocol}//${data.path}.${data.OrganizationId}.${host}`);
713
790
  logger.info(`App store page: ${new URL(`/apps/${data.id}`, remote)}`);
714
- const rcCollections = (_z = rc.context[context]) === null || _z === void 0 ? void 0 : _z.collections;
715
- if (Array.isArray(rcCollections)) {
716
- for (const collectionId of rcCollections) {
717
- try {
718
- await axios.post(`/api/appCollections/${collectionId}/apps`, { AppId: data.id }, {
719
- baseURL: remote,
720
- });
721
- logger.info(`Successfully added app to collection ${collectionId}`);
722
- }
723
- catch (error) {
724
- logger.error(error);
725
- }
726
- }
727
- }
728
- if (appVariantPath !== path && modifyContext && !dryRun) {
729
- const [defaultAppRc] = await readData(join(path, '.appsemblerc.yaml'));
730
- defaultAppRc.context[context] = rc.context[context];
731
- await writeData(join(path, '.appsemblerc.yaml'), defaultAppRc, { sort: false });
791
+ if (appVariantPath !== path) {
732
792
  await rm(appVariantPath, { recursive: true });
733
793
  logger.info(`Removed ${appVariantPath}`);
734
794
  }
735
795
  }
736
- /**
737
- * Resolve the app’s ID and remote based on the app context.
738
- *
739
- * @param appPath The path to the app.
740
- * @param name Which context to use in the AppsembleRC file.
741
- * @param defaultRemote The remote to fall back to.
742
- * @param defaultAppId The app ID to fall back to.
743
- * @returns The resolved app ID and remote.
744
- */
745
- export async function resolveAppIdAndRemote(appPath, name, defaultRemote, defaultAppId) {
746
- var _a;
747
- let id = defaultAppId;
748
- let resolvedRemote = defaultRemote;
749
- if (appPath) {
750
- const rcPath = join(appPath, '.appsemblerc.yaml');
751
- const [rc] = await readData(rcPath);
752
- const context = (_a = rc.context) === null || _a === void 0 ? void 0 : _a[name];
753
- if (!defaultAppId) {
754
- id = context === null || context === void 0 ? void 0 : context.id;
755
- }
756
- if (context.remote) {
757
- resolvedRemote = context.remote;
758
- }
759
- }
760
- if (id == null) {
761
- throw new AppsembleError(`App ID was not found in context.${name}.id nor in --app-id`);
762
- }
763
- return [id, coerceRemote(resolvedRemote)];
764
- }
765
796
  export async function patchApp({ id, remote, ...options }) {
766
797
  const formData = new FormData();
767
798
  if (options.path !== undefined) {