@appsemble/cli 0.27.9 ā 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/app/patch.js +7 -58
- package/commands/serve.js +1 -1
- package/lib/app.d.ts +127 -75
- package/lib/app.js +223 -125
- package/lib/app.test.d.ts +1 -0
- package/lib/app.test.js +1350 -0
- package/package.json +8 -5
- package/server/options/getAppReadmes.d.ts +2 -0
- package/server/options/getAppReadmes.js +11 -0
- package/server/options/index.d.ts +1 -0
- package/server/options/index.js +1 -0
- package/server/options/options.js +2 -1
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cpSync, createReadStream, createWriteStream, existsSync } from 'node:fs';
|
|
2
|
-
import { mkdir, readdir,
|
|
2
|
+
import { mkdir, readdir, rm, stat } from 'node:fs/promises';
|
|
3
3
|
import { basename, dirname, join, parse, relative, resolve } from 'node:path';
|
|
4
4
|
import { inspect } from 'node:util';
|
|
5
5
|
import { applyAppVariant, AppsembleError, authenticate, logger, opendirSafe, readData, writeData, } from '@appsemble/node-utils';
|
|
@@ -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;
|
|
@@ -44,6 +48,14 @@ export async function traverseAppDirectory(path, formData) {
|
|
|
44
48
|
};
|
|
45
49
|
logger.info(`Traversing directory for App files in ${path} šµ`);
|
|
46
50
|
await opendirSafe(path, async (filepath, filestat) => {
|
|
51
|
+
if (filestat.isFile() && filestat.name.toLowerCase().startsWith('readme')) {
|
|
52
|
+
logger.info(`Adding ${filepath}`);
|
|
53
|
+
formData.append('readmes', createReadStream(filepath));
|
|
54
|
+
if (filestat.name.toLowerCase().startsWith('readme.md')) {
|
|
55
|
+
gatheredData.readmeUrl = basename(filepath);
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
47
59
|
switch (filestat.name.toLowerCase()) {
|
|
48
60
|
case '.appsemblerc.yaml':
|
|
49
61
|
logger.info(`Reading app settings from ${filepath}`);
|
|
@@ -52,6 +64,10 @@ export async function traverseAppDirectory(path, formData) {
|
|
|
52
64
|
formData.append('iconBackground', rc.iconBackground);
|
|
53
65
|
gatheredData.iconBackground = rc.iconBackground;
|
|
54
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
|
+
}
|
|
55
71
|
break;
|
|
56
72
|
case 'app-definition.yaml': {
|
|
57
73
|
logger.info(`Using app definition from ${filepath}`);
|
|
@@ -66,15 +82,12 @@ export async function traverseAppDirectory(path, formData) {
|
|
|
66
82
|
}
|
|
67
83
|
case 'icon.png':
|
|
68
84
|
case 'icon.svg':
|
|
85
|
+
iconPath = filepath;
|
|
69
86
|
gatheredData.iconUrl = filepath;
|
|
70
87
|
return;
|
|
71
88
|
case 'maskable-icon.png':
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
logger.info(`Including longDescription from ${filepath}`);
|
|
75
|
-
formData.append('longDescription', await readFile(filepath, 'utf8'));
|
|
76
|
-
gatheredData.longDescription = await readFile(filepath, 'utf8');
|
|
77
|
-
return;
|
|
89
|
+
maskableIconPath = filepath;
|
|
90
|
+
break;
|
|
78
91
|
case 'screenshots':
|
|
79
92
|
return opendirSafe(filepath, (screenshotPath, screenshotStat) => {
|
|
80
93
|
if (screenshotStat.isDirectory() &&
|
|
@@ -124,13 +137,20 @@ export async function traverseAppDirectory(path, formData) {
|
|
|
124
137
|
gatheredData.controllerImplementations = controllerImplementations;
|
|
125
138
|
break;
|
|
126
139
|
default:
|
|
127
|
-
|
|
140
|
+
break;
|
|
128
141
|
}
|
|
129
142
|
});
|
|
130
143
|
if (yaml === undefined) {
|
|
131
144
|
throw new AppsembleError('No app definition found');
|
|
132
145
|
}
|
|
133
|
-
|
|
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];
|
|
134
154
|
}
|
|
135
155
|
async function retrieveContext(path, context) {
|
|
136
156
|
let rc;
|
|
@@ -449,15 +469,45 @@ This block version is not used in the app`);
|
|
|
449
469
|
}
|
|
450
470
|
}
|
|
451
471
|
/**
|
|
452
|
-
*
|
|
472
|
+
* Resolve the appās ID and remote based on the app context.
|
|
453
473
|
*
|
|
454
|
-
* @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.
|
|
455
479
|
*/
|
|
456
|
-
export async function
|
|
457
|
-
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;
|
|
458
507
|
const file = await stat(path);
|
|
459
508
|
const formData = new FormData();
|
|
460
509
|
const appsembleContext = await retrieveContext(path, context);
|
|
510
|
+
let rc;
|
|
461
511
|
let yaml;
|
|
462
512
|
let filename = relative(process.cwd(), path);
|
|
463
513
|
const variant = (_b = (_a = appsembleContext.variant) !== null && _a !== void 0 ? _a : options.variant) !== null && _b !== void 0 ? _b : context;
|
|
@@ -470,16 +520,24 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
|
|
|
470
520
|
logger.warn(`App variant ${variant} is not defined in ${join(path, 'variants')}. Using default app.`);
|
|
471
521
|
}
|
|
472
522
|
if (file.isFile()) {
|
|
523
|
+
// Assuming file is App YAML
|
|
473
524
|
const [, data] = await readData(appVariantPath);
|
|
474
525
|
yaml = data;
|
|
475
526
|
formData.append('yaml', data);
|
|
476
527
|
}
|
|
477
528
|
else {
|
|
478
|
-
|
|
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
|
+
}
|
|
479
537
|
filename = join(filename, 'app-definition.yaml');
|
|
480
538
|
}
|
|
481
539
|
const remote = (_c = appsembleContext.remote) !== null && _c !== void 0 ? _c : options.remote;
|
|
482
|
-
const
|
|
540
|
+
const organizationId = (_d = appsembleContext.organization) !== null && _d !== void 0 ? _d : options.organization;
|
|
483
541
|
const template = (_f = (_e = appsembleContext.template) !== null && _e !== void 0 ? _e : options.template) !== null && _f !== void 0 ? _f : false;
|
|
484
542
|
const assetsClonable = (_h = (_g = appsembleContext.assetsClonable) !== null && _g !== void 0 ? _g : options.assetsClonable) !== null && _h !== void 0 ? _h : false;
|
|
485
543
|
const demoMode = (_k = (_j = appsembleContext.demoMode) !== null && _j !== void 0 ? _j : options.demoMode) !== null && _k !== void 0 ? _k : false;
|
|
@@ -490,23 +548,23 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
|
|
|
490
548
|
const sentryDsn = (_q = appsembleContext.sentryDsn) !== null && _q !== void 0 ? _q : options.sentryDsn;
|
|
491
549
|
const sentryEnvironment = (_r = appsembleContext.sentryEnvironment) !== null && _r !== void 0 ? _r : options.sentryEnvironment;
|
|
492
550
|
const googleAnalyticsId = (_s = appsembleContext.googleAnalyticsId) !== null && _s !== void 0 ? _s : options.googleAnalyticsId;
|
|
493
|
-
const
|
|
494
|
-
const
|
|
495
|
-
const
|
|
496
|
-
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';
|
|
497
554
|
logger.verbose(`App remote: ${remote}`);
|
|
555
|
+
logger.verbose(`App organization: ${organizationId}`);
|
|
498
556
|
logger.verbose(`App is template: ${inspect(template, { colors: true })}`);
|
|
499
557
|
logger.verbose(`App visibility: ${visibility}`);
|
|
500
558
|
logger.verbose(`Icon background: ${iconBackground}`);
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
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');
|
|
504
561
|
}
|
|
505
|
-
formData.append('
|
|
562
|
+
formData.append('OrganizationId', organizationId);
|
|
506
563
|
formData.append('template', String(template));
|
|
507
564
|
formData.append('demoMode', String(demoMode));
|
|
508
565
|
formData.append('visibility', visibility);
|
|
509
566
|
formData.append('iconBackground', iconBackground);
|
|
567
|
+
formData.append('locked', appLock);
|
|
510
568
|
if (icon) {
|
|
511
569
|
const realIcon = typeof icon === 'string' ? createReadStream(icon) : icon;
|
|
512
570
|
logger.info(`Using icon from ${(_v = realIcon.path) !== null && _v !== void 0 ? _v : 'stdin'}`);
|
|
@@ -533,21 +591,12 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
|
|
|
533
591
|
authScope += ' resources:write';
|
|
534
592
|
}
|
|
535
593
|
await authenticate(remote, authScope, clientCredentials);
|
|
536
|
-
if (appLock) {
|
|
537
|
-
logger.info(`Setting AppLock to ${appLock}`);
|
|
538
|
-
try {
|
|
539
|
-
await axios.post(`/api/apps/${id}/lock`, {
|
|
540
|
-
locked: appLock,
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
catch (error) {
|
|
544
|
-
logger.error(error);
|
|
545
|
-
process.exit(1);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
594
|
let data;
|
|
549
595
|
try {
|
|
550
|
-
({ data } = await axios.
|
|
596
|
+
({ data } = await axios.post('/api/apps', formData, {
|
|
597
|
+
baseURL: remote,
|
|
598
|
+
params: { dryRun: dryRun || undefined },
|
|
599
|
+
}));
|
|
551
600
|
}
|
|
552
601
|
catch (error) {
|
|
553
602
|
if (!axios.isAxiosError(error)) {
|
|
@@ -558,38 +607,64 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
|
|
|
558
607
|
}
|
|
559
608
|
throw new AppsembleError(printAxiosError(filename, yaml, error.response.data.data.errors));
|
|
560
609
|
}
|
|
561
|
-
if (
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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) {
|
|
567
621
|
await publishSeedAssets(appVariantPath, data, remote, assetsClonable);
|
|
568
622
|
}
|
|
569
|
-
if (resources
|
|
623
|
+
if (resources) {
|
|
570
624
|
await publishSeedResources(appVariantPath, data, remote);
|
|
571
625
|
}
|
|
572
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
|
+
}
|
|
573
632
|
const { host, protocol } = new URL(remote);
|
|
574
|
-
logger.info(`Successfully
|
|
633
|
+
logger.info(`Successfully published app ${data.definition.name}! š`);
|
|
575
634
|
logger.info(`App URL: ${protocol}//${data.path}.${data.OrganizationId}.${host}`);
|
|
576
635
|
logger.info(`App store page: ${new URL(`/apps/${data.id}`, remote)}`);
|
|
577
|
-
|
|
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 });
|
|
578
654
|
await rm(appVariantPath, { recursive: true });
|
|
579
655
|
logger.info(`Removed ${appVariantPath}`);
|
|
580
656
|
}
|
|
581
657
|
}
|
|
582
658
|
/**
|
|
583
|
-
*
|
|
659
|
+
* Update an existing app.
|
|
584
660
|
*
|
|
585
|
-
* @param
|
|
661
|
+
* @param argv The command line options used for updating the app.
|
|
586
662
|
*/
|
|
587
|
-
export async function
|
|
588
|
-
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;
|
|
589
665
|
const file = await stat(path);
|
|
590
666
|
const formData = new FormData();
|
|
591
667
|
const appsembleContext = await retrieveContext(path, context);
|
|
592
|
-
let rc;
|
|
593
668
|
let yaml;
|
|
594
669
|
let filename = relative(process.cwd(), path);
|
|
595
670
|
const variant = (_b = (_a = appsembleContext.variant) !== null && _a !== void 0 ? _a : options.variant) !== null && _b !== void 0 ? _b : context;
|
|
@@ -602,17 +677,23 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
|
|
|
602
677
|
logger.warn(`App variant ${variant} is not defined in ${join(path, 'variants')}. Using default app.`);
|
|
603
678
|
}
|
|
604
679
|
if (file.isFile()) {
|
|
605
|
-
// Assuming file is App YAML
|
|
606
680
|
const [, data] = await readData(appVariantPath);
|
|
607
681
|
yaml = data;
|
|
608
682
|
formData.append('yaml', data);
|
|
609
683
|
}
|
|
610
684
|
else {
|
|
611
|
-
|
|
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
|
+
}
|
|
612
693
|
filename = join(filename, 'app-definition.yaml');
|
|
613
694
|
}
|
|
614
695
|
const remote = (_c = appsembleContext.remote) !== null && _c !== void 0 ? _c : options.remote;
|
|
615
|
-
const
|
|
696
|
+
const id = (_d = appsembleContext.id) !== null && _d !== void 0 ? _d : options.id;
|
|
616
697
|
const template = (_f = (_e = appsembleContext.template) !== null && _e !== void 0 ? _e : options.template) !== null && _f !== void 0 ? _f : false;
|
|
617
698
|
const assetsClonable = (_h = (_g = appsembleContext.assetsClonable) !== null && _g !== void 0 ? _g : options.assetsClonable) !== null && _h !== void 0 ? _h : false;
|
|
618
699
|
const demoMode = (_k = (_j = appsembleContext.demoMode) !== null && _j !== void 0 ? _j : options.demoMode) !== null && _k !== void 0 ? _k : false;
|
|
@@ -623,23 +704,23 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
|
|
|
623
704
|
const sentryDsn = (_q = appsembleContext.sentryDsn) !== null && _q !== void 0 ? _q : options.sentryDsn;
|
|
624
705
|
const sentryEnvironment = (_r = appsembleContext.sentryEnvironment) !== null && _r !== void 0 ? _r : options.sentryEnvironment;
|
|
625
706
|
const googleAnalyticsId = (_s = appsembleContext.googleAnalyticsId) !== null && _s !== void 0 ? _s : options.googleAnalyticsId;
|
|
626
|
-
const
|
|
627
|
-
const
|
|
628
|
-
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}`);
|
|
629
711
|
logger.verbose(`App remote: ${remote}`);
|
|
630
|
-
logger.verbose(`App organization: ${organizationId}`);
|
|
631
712
|
logger.verbose(`App is template: ${inspect(template, { colors: true })}`);
|
|
632
713
|
logger.verbose(`App visibility: ${visibility}`);
|
|
633
714
|
logger.verbose(`Icon background: ${iconBackground}`);
|
|
634
|
-
|
|
635
|
-
|
|
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');
|
|
636
718
|
}
|
|
637
|
-
formData.append('
|
|
719
|
+
formData.append('force', String(force));
|
|
638
720
|
formData.append('template', String(template));
|
|
639
721
|
formData.append('demoMode', String(demoMode));
|
|
640
722
|
formData.append('visibility', visibility);
|
|
641
723
|
formData.append('iconBackground', iconBackground);
|
|
642
|
-
formData.append('locked', appLock);
|
|
643
724
|
if (icon) {
|
|
644
725
|
const realIcon = typeof icon === 'string' ? createReadStream(icon) : icon;
|
|
645
726
|
logger.info(`Using icon from ${(_v = realIcon.path) !== null && _v !== void 0 ? _v : 'stdin'}`);
|
|
@@ -666,12 +747,21 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
|
|
|
666
747
|
authScope += ' resources:write';
|
|
667
748
|
}
|
|
668
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
|
+
}
|
|
669
762
|
let data;
|
|
670
763
|
try {
|
|
671
|
-
({ data } = await axios.
|
|
672
|
-
baseURL: remote,
|
|
673
|
-
params: { dryRun: dryRun || undefined },
|
|
674
|
-
}));
|
|
764
|
+
({ data } = await axios.patch(`/api/apps/${id}`, formData, { baseURL: remote }));
|
|
675
765
|
}
|
|
676
766
|
catch (error) {
|
|
677
767
|
if (!axios.isAxiosError(error)) {
|
|
@@ -682,81 +772,89 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
|
|
|
682
772
|
}
|
|
683
773
|
throw new AppsembleError(printAxiosError(filename, yaml, error.response.data.data.errors));
|
|
684
774
|
}
|
|
685
|
-
if (
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
// After uploading the app, upload block styles, messages if they are available
|
|
692
|
-
await traverseBlockThemes(appVariantPath, data.id, remote, false);
|
|
693
|
-
await uploadMessages(appVariantPath, data.id, remote, false);
|
|
694
|
-
// After uploading the app, publish seed resources and assets if they are available
|
|
695
|
-
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)) {
|
|
696
781
|
await publishSeedAssets(appVariantPath, data, remote, assetsClonable);
|
|
697
782
|
}
|
|
698
|
-
if (resources) {
|
|
783
|
+
if (resources && (data.locked !== 'fullLock' || force)) {
|
|
699
784
|
await publishSeedResources(appVariantPath, data, remote);
|
|
700
785
|
}
|
|
701
786
|
}
|
|
702
|
-
if (modifyContext && appsembleContext && context && !dryRun) {
|
|
703
|
-
rc.context[context].id = data.id;
|
|
704
|
-
await writeData(join(appVariantPath, '.appsemblerc.yaml'), rc, { sort: false });
|
|
705
|
-
logger.info(`Updated .appsemblerc: Set context.${context}.id to ${data.id}`);
|
|
706
|
-
}
|
|
707
787
|
const { host, protocol } = new URL(remote);
|
|
708
|
-
logger.info(`Successfully
|
|
788
|
+
logger.info(`Successfully updated app ${data.definition.name}! š`);
|
|
709
789
|
logger.info(`App URL: ${protocol}//${data.path}.${data.OrganizationId}.${host}`);
|
|
710
790
|
logger.info(`App store page: ${new URL(`/apps/${data.id}`, remote)}`);
|
|
711
|
-
const rcCollections = (_z = rc.context[context]) === null || _z === void 0 ? void 0 : _z.collections;
|
|
712
|
-
if (Array.isArray(rcCollections)) {
|
|
713
|
-
for (const collectionId of rcCollections) {
|
|
714
|
-
try {
|
|
715
|
-
await axios.post(`/api/appCollections/${collectionId}/apps`, { AppId: data.id }, {
|
|
716
|
-
baseURL: remote,
|
|
717
|
-
});
|
|
718
|
-
logger.info(`Successfully added app to collection ${collectionId}`);
|
|
719
|
-
}
|
|
720
|
-
catch (error) {
|
|
721
|
-
logger.error(error);
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
791
|
if (appVariantPath !== path) {
|
|
726
|
-
const [defaultAppRc] = await readData(join(path, '.appsemblerc.yaml'));
|
|
727
|
-
defaultAppRc.context[context] = rc.context[context];
|
|
728
|
-
await writeData(join(path, '.appsemblerc.yaml'), defaultAppRc, { sort: false });
|
|
729
792
|
await rm(appVariantPath, { recursive: true });
|
|
730
793
|
logger.info(`Removed ${appVariantPath}`);
|
|
731
794
|
}
|
|
732
795
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
if (
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
796
|
+
export async function patchApp({ id, remote, ...options }) {
|
|
797
|
+
const formData = new FormData();
|
|
798
|
+
if (options.path !== undefined) {
|
|
799
|
+
logger.info(`Setting app path to ${options.path}`);
|
|
800
|
+
formData.append('path', options.path);
|
|
801
|
+
}
|
|
802
|
+
if (options.force !== undefined) {
|
|
803
|
+
formData.append('force', String(options.force));
|
|
804
|
+
}
|
|
805
|
+
if (options.demoMode !== undefined) {
|
|
806
|
+
logger.info(`Setting app demo mode to ${options.demoMode}`);
|
|
807
|
+
formData.append('demoMode', String(options.demoMode));
|
|
808
|
+
}
|
|
809
|
+
if (options.template !== undefined) {
|
|
810
|
+
logger.info(`Setting template to ${options.template}`);
|
|
811
|
+
formData.append('template', String(options.template));
|
|
812
|
+
}
|
|
813
|
+
if (options.visibility !== undefined) {
|
|
814
|
+
logger.info(`Setting app visibility to ${options.visibility}`);
|
|
815
|
+
formData.append('visibility', options.visibility);
|
|
816
|
+
}
|
|
817
|
+
if (options.iconBackground !== undefined) {
|
|
818
|
+
logger.info(`Setting app icon background to ${options.iconBackground}`);
|
|
819
|
+
formData.append('iconBackground', options.iconBackground);
|
|
820
|
+
}
|
|
821
|
+
if (options.showAppDefinition !== undefined) {
|
|
822
|
+
logger.info(`Setting showAppDefinition to ${options.showAppDefinition}`);
|
|
823
|
+
formData.append('showAppDefinition', String(options.showAppDefinition));
|
|
824
|
+
}
|
|
825
|
+
if (options.showAppsembleLogin !== undefined) {
|
|
826
|
+
logger.info(`Setting showAppsembleLogin to ${options.showAppsembleLogin}`);
|
|
827
|
+
formData.append('showAppsembleLogin', String(options.showAppsembleLogin));
|
|
828
|
+
}
|
|
829
|
+
if (options.showAppsembleOAuth2Login !== undefined) {
|
|
830
|
+
logger.info(`Setting showAppsembleOAuth2Login to ${options.showAppsembleOAuth2Login}`);
|
|
831
|
+
formData.append('showAppsembleOAuth2Login', String(options.showAppsembleOAuth2Login));
|
|
832
|
+
}
|
|
833
|
+
if (options.enableSelfRegistration !== undefined) {
|
|
834
|
+
logger.info(`Setting enableSelfRegistration to ${options.enableSelfRegistration}`);
|
|
835
|
+
formData.append('enableSelfRegistration', String(options.enableSelfRegistration));
|
|
836
|
+
}
|
|
837
|
+
try {
|
|
838
|
+
if (!formData.getLengthSync() && options.locked === undefined) {
|
|
839
|
+
logger.warn('Nothing to patch. Need at least one additional argument to patch app.');
|
|
840
|
+
return;
|
|
752
841
|
}
|
|
753
|
-
if (
|
|
754
|
-
|
|
842
|
+
if (formData.getLengthSync()) {
|
|
843
|
+
const { data } = await axios.patch(`/api/apps/${id}`, formData);
|
|
844
|
+
logger.info(`Successfully updated app with id ${id}`);
|
|
845
|
+
const { host, protocol } = new URL(remote);
|
|
846
|
+
logger.info(`App URL: ${protocol}//${data.path}.${data.OrganizationId}.${host}`);
|
|
847
|
+
}
|
|
848
|
+
if (options.locked !== undefined) {
|
|
849
|
+
await axios.post(`/api/apps/${id}/lock`, {
|
|
850
|
+
locked: options.locked,
|
|
851
|
+
});
|
|
852
|
+
logger.info(`Successfully set app lock value for app with id ${id} to ${options.locked}`);
|
|
755
853
|
}
|
|
854
|
+
logger.info(`App store page: ${new URL(`/apps/${id}`, remote)}`);
|
|
756
855
|
}
|
|
757
|
-
|
|
758
|
-
|
|
856
|
+
catch (error) {
|
|
857
|
+
logger.error(error);
|
|
759
858
|
}
|
|
760
|
-
return [id, coerceRemote(resolvedRemote)];
|
|
761
859
|
}
|
|
762
860
|
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|