@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/README.md +3 -3
- package/__fixtures__/apps/test/README.md +1 -0
- package/commands/serve.js +1 -1
- package/lib/app.d.ts +72 -75
- package/lib/app.js +155 -124
- package/lib/app.test.js +1189 -3
- package/package.json +6 -6
- package/templates/apps/empty/app-definition.yaml +2 -2
- package/templates/blocks/mini-jsx/package.json +1 -1
- package/templates/blocks/preact/package.json +2 -2
- package/templates/blocks/vanilla/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
472
|
+
* Resolve the app’s ID and remote based on the app context.
|
|
456
473
|
*
|
|
457
|
-
* @param
|
|
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
|
|
460
|
-
var _a
|
|
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
|
-
|
|
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
|
|
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
|
|
497
|
-
const
|
|
498
|
-
const
|
|
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
|
-
|
|
505
|
-
|
|
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('
|
|
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.
|
|
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 (
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
659
|
+
* Update an existing app.
|
|
587
660
|
*
|
|
588
|
-
* @param
|
|
661
|
+
* @param argv The command line options used for updating the app.
|
|
589
662
|
*/
|
|
590
|
-
export async function
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
630
|
-
const
|
|
631
|
-
const appLock = appsembleContext
|
|
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
|
-
|
|
638
|
-
|
|
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('
|
|
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.
|
|
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 (
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
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
|
|
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
|
-
|
|
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) {
|