@appsemble/cli 0.27.9 → 0.27.10
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/commands/app/patch.js +7 -58
- package/lib/app.d.ts +56 -1
- package/lib/app.js +75 -8
- package/lib/app.test.d.ts +1 -0
- package/lib/app.test.js +164 -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/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#  Appsemble CLI
|
|
2
2
|
|
|
3
3
|
> Manage apps and blocks from the command line.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@appsemble/cli)
|
|
6
|
-
[](https://gitlab.com/appsemble/appsemble/-/releases/0.27.10)
|
|
7
7
|
[](https://prettier.io)
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
@@ -323,5 +323,5 @@ appsemble run-cronjobs --interval 30
|
|
|
323
323
|
|
|
324
324
|
## License
|
|
325
325
|
|
|
326
|
-
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.27.
|
|
326
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.27.10/LICENSE.md) ©
|
|
327
327
|
[Appsemble](https://appsemble.com)
|
package/commands/app/patch.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { authenticate, logger } from '@appsemble/node-utils';
|
|
2
|
-
import
|
|
3
|
-
import FormData from 'form-data';
|
|
2
|
+
import { patchApp } from '../../lib/app.js';
|
|
4
3
|
export const command = 'patch';
|
|
5
4
|
export const description = 'Change the settings of an app without having the entire source.';
|
|
6
5
|
export function builder(yargs) {
|
|
@@ -55,61 +54,11 @@ export function builder(yargs) {
|
|
|
55
54
|
}
|
|
56
55
|
export async function handler({ clientCredentials, id, remote, ...args }) {
|
|
57
56
|
await authenticate(remote, 'apps:write', clientCredentials);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
formData.append('force', String(args.force));
|
|
65
|
-
}
|
|
66
|
-
if (args.demoMode) {
|
|
67
|
-
logger.info(`Setting app demo mode to ${args.demoMode}`);
|
|
68
|
-
formData.append('demoMode', String(args.demoMode));
|
|
69
|
-
}
|
|
70
|
-
if (args.template) {
|
|
71
|
-
logger.info(`Setting template to ${args.template}`);
|
|
72
|
-
formData.append('template', String(args.template));
|
|
73
|
-
}
|
|
74
|
-
if (args.visibility) {
|
|
75
|
-
logger.info(`Setting app visibility to ${args.visibility}`);
|
|
76
|
-
formData.append('visibility', args.visibility);
|
|
77
|
-
}
|
|
78
|
-
if (args.iconBackground) {
|
|
79
|
-
logger.info(`Setting app icon background to ${args.iconBackground}`);
|
|
80
|
-
formData.append('iconBackground', args.iconBackground);
|
|
81
|
-
}
|
|
82
|
-
if (args.showAppDefinition) {
|
|
83
|
-
logger.info(`Setting showAppDefinition to ${args.showAppDefinition}`);
|
|
84
|
-
formData.append('showAppDefinition', String(args.showAppDefinition));
|
|
85
|
-
}
|
|
86
|
-
if (args.showAppsembleLogin) {
|
|
87
|
-
logger.info(`Setting showAppsembleLogin to ${args.showAppsembleLogin}`);
|
|
88
|
-
formData.append('showAppsembleLogin', String(args.showAppsembleLogin));
|
|
89
|
-
}
|
|
90
|
-
if (args.showAppsembleOAuth2Login) {
|
|
91
|
-
logger.info(`Setting showAppsembleOAuth2Login to ${args.showAppsembleOAuth2Login}`);
|
|
92
|
-
formData.append('showAppsembleOAuth2Login', String(args.showAppsembleOAuth2Login));
|
|
93
|
-
}
|
|
94
|
-
if (args.enableSelfRegistration) {
|
|
95
|
-
logger.info(`Setting enableSelfRegistration to ${args.enableSelfRegistration}`);
|
|
96
|
-
formData.append('enableSelfRegistration', String(args.enableSelfRegistration));
|
|
97
|
-
}
|
|
98
|
-
try {
|
|
99
|
-
if (args.locked) {
|
|
100
|
-
await axios.post(`api/apps/${id}/lock`, {
|
|
101
|
-
locked: args.locked,
|
|
102
|
-
});
|
|
103
|
-
logger.info(`Successfully set app lock value for app with id ${id} to ${args.locked}`);
|
|
104
|
-
if (!formData.getLengthSync()) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
await axios.patch(`/api/apps/${id}`, formData);
|
|
109
|
-
logger.info(`Successfully updated app with id ${id}`);
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
logger.error(error);
|
|
113
|
-
}
|
|
57
|
+
logger.info(`Patching app ${id}`);
|
|
58
|
+
await patchApp({
|
|
59
|
+
...args,
|
|
60
|
+
id,
|
|
61
|
+
remote,
|
|
62
|
+
});
|
|
114
63
|
}
|
|
115
64
|
//# sourceMappingURL=patch.js.map
|
package/lib/app.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
/// <reference types="node" resolution-mode="require"/>
|
|
3
3
|
import { type ReadStream } from 'node:fs';
|
|
4
|
-
import { type App, type AppsembleRC, type AppVisibility } from '@appsemble/types';
|
|
4
|
+
import { type App, type AppLock, type AppsembleRC, type AppVisibility } from '@appsemble/types';
|
|
5
5
|
import FormData from 'form-data';
|
|
6
6
|
interface PublishAppParams {
|
|
7
7
|
/**
|
|
@@ -227,4 +227,59 @@ export declare function publishApp({ clientCredentials, context, dryRun, modifyC
|
|
|
227
227
|
* @returns The resolved app ID and remote.
|
|
228
228
|
*/
|
|
229
229
|
export declare function resolveAppIdAndRemote(appPath: string, name: string, defaultRemote: string, defaultAppId: number): Promise<[number, string]>;
|
|
230
|
+
interface PatchAppParams {
|
|
231
|
+
/**
|
|
232
|
+
* The path at which the app is hosted.
|
|
233
|
+
*/
|
|
234
|
+
path?: string;
|
|
235
|
+
/**
|
|
236
|
+
* Whether the locked property should be ignored.
|
|
237
|
+
*/
|
|
238
|
+
force?: boolean;
|
|
239
|
+
/**
|
|
240
|
+
* The ID of the app to update.
|
|
241
|
+
*/
|
|
242
|
+
id?: number;
|
|
243
|
+
/**
|
|
244
|
+
* Visibility of the app in the public app store.
|
|
245
|
+
*/
|
|
246
|
+
visibility?: AppVisibility;
|
|
247
|
+
/**
|
|
248
|
+
* The remote server to create the app on.
|
|
249
|
+
*/
|
|
250
|
+
remote: string;
|
|
251
|
+
/**
|
|
252
|
+
* Whether the App should be marked as a template.
|
|
253
|
+
*/
|
|
254
|
+
template?: boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Whether the App should be used in demo mode.
|
|
257
|
+
*/
|
|
258
|
+
demoMode?: boolean;
|
|
259
|
+
/**
|
|
260
|
+
* The background color to use for the icon in opaque contexts.
|
|
261
|
+
*/
|
|
262
|
+
iconBackground?: string;
|
|
263
|
+
/**
|
|
264
|
+
* Whether or not the app definition is exposed for display in Appsemble Studio.
|
|
265
|
+
*/
|
|
266
|
+
showAppDefinition?: boolean;
|
|
267
|
+
/**
|
|
268
|
+
* Whether the Appsemble password login method should be shown.
|
|
269
|
+
*/
|
|
270
|
+
showAppsembleLogin?: boolean;
|
|
271
|
+
/**
|
|
272
|
+
* Whether the Appsemble OAuth2 login method should be shown.
|
|
273
|
+
*/
|
|
274
|
+
showAppsembleOAuth2Login?: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* Whether new users should be able to register themselves.
|
|
277
|
+
*/
|
|
278
|
+
enableSelfRegistration?: boolean;
|
|
279
|
+
/**
|
|
280
|
+
* Whether the app is currently locked.
|
|
281
|
+
*/
|
|
282
|
+
locked?: AppLock;
|
|
283
|
+
}
|
|
284
|
+
export declare function patchApp({ id, remote, ...options }: PatchAppParams): Promise<void>;
|
|
230
285
|
export {};
|
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';
|
|
@@ -44,6 +44,14 @@ export async function traverseAppDirectory(path, formData) {
|
|
|
44
44
|
};
|
|
45
45
|
logger.info(`Traversing directory for App files in ${path} 🕵`);
|
|
46
46
|
await opendirSafe(path, async (filepath, filestat) => {
|
|
47
|
+
if (filestat.isFile() && filestat.name.toLowerCase().startsWith('readme')) {
|
|
48
|
+
logger.info(`Adding ${filepath}`);
|
|
49
|
+
formData.append('readmes', createReadStream(filepath));
|
|
50
|
+
if (filestat.name.toLowerCase().startsWith('readme.md')) {
|
|
51
|
+
gatheredData.readmeUrl = basename(filepath);
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
47
55
|
switch (filestat.name.toLowerCase()) {
|
|
48
56
|
case '.appsemblerc.yaml':
|
|
49
57
|
logger.info(`Reading app settings from ${filepath}`);
|
|
@@ -70,11 +78,6 @@ export async function traverseAppDirectory(path, formData) {
|
|
|
70
78
|
return;
|
|
71
79
|
case 'maskable-icon.png':
|
|
72
80
|
return;
|
|
73
|
-
case 'readme.md':
|
|
74
|
-
logger.info(`Including longDescription from ${filepath}`);
|
|
75
|
-
formData.append('longDescription', await readFile(filepath, 'utf8'));
|
|
76
|
-
gatheredData.longDescription = await readFile(filepath, 'utf8');
|
|
77
|
-
return;
|
|
78
81
|
case 'screenshots':
|
|
79
82
|
return opendirSafe(filepath, (screenshotPath, screenshotStat) => {
|
|
80
83
|
if (screenshotStat.isDirectory() &&
|
|
@@ -124,7 +127,7 @@ export async function traverseAppDirectory(path, formData) {
|
|
|
124
127
|
gatheredData.controllerImplementations = controllerImplementations;
|
|
125
128
|
break;
|
|
126
129
|
default:
|
|
127
|
-
|
|
130
|
+
break;
|
|
128
131
|
}
|
|
129
132
|
});
|
|
130
133
|
if (yaml === undefined) {
|
|
@@ -722,7 +725,7 @@ export async function publishApp({ clientCredentials, context, dryRun, modifyCon
|
|
|
722
725
|
}
|
|
723
726
|
}
|
|
724
727
|
}
|
|
725
|
-
if (appVariantPath !== path) {
|
|
728
|
+
if (appVariantPath !== path && modifyContext && !dryRun) {
|
|
726
729
|
const [defaultAppRc] = await readData(join(path, '.appsemblerc.yaml'));
|
|
727
730
|
defaultAppRc.context[context] = rc.context[context];
|
|
728
731
|
await writeData(join(path, '.appsemblerc.yaml'), defaultAppRc, { sort: false });
|
|
@@ -759,4 +762,68 @@ export async function resolveAppIdAndRemote(appPath, name, defaultRemote, defaul
|
|
|
759
762
|
}
|
|
760
763
|
return [id, coerceRemote(resolvedRemote)];
|
|
761
764
|
}
|
|
765
|
+
export async function patchApp({ id, remote, ...options }) {
|
|
766
|
+
const formData = new FormData();
|
|
767
|
+
if (options.path !== undefined) {
|
|
768
|
+
logger.info(`Setting app path to ${options.path}`);
|
|
769
|
+
formData.append('path', options.path);
|
|
770
|
+
}
|
|
771
|
+
if (options.force !== undefined) {
|
|
772
|
+
formData.append('force', String(options.force));
|
|
773
|
+
}
|
|
774
|
+
if (options.demoMode !== undefined) {
|
|
775
|
+
logger.info(`Setting app demo mode to ${options.demoMode}`);
|
|
776
|
+
formData.append('demoMode', String(options.demoMode));
|
|
777
|
+
}
|
|
778
|
+
if (options.template !== undefined) {
|
|
779
|
+
logger.info(`Setting template to ${options.template}`);
|
|
780
|
+
formData.append('template', String(options.template));
|
|
781
|
+
}
|
|
782
|
+
if (options.visibility !== undefined) {
|
|
783
|
+
logger.info(`Setting app visibility to ${options.visibility}`);
|
|
784
|
+
formData.append('visibility', options.visibility);
|
|
785
|
+
}
|
|
786
|
+
if (options.iconBackground !== undefined) {
|
|
787
|
+
logger.info(`Setting app icon background to ${options.iconBackground}`);
|
|
788
|
+
formData.append('iconBackground', options.iconBackground);
|
|
789
|
+
}
|
|
790
|
+
if (options.showAppDefinition !== undefined) {
|
|
791
|
+
logger.info(`Setting showAppDefinition to ${options.showAppDefinition}`);
|
|
792
|
+
formData.append('showAppDefinition', String(options.showAppDefinition));
|
|
793
|
+
}
|
|
794
|
+
if (options.showAppsembleLogin !== undefined) {
|
|
795
|
+
logger.info(`Setting showAppsembleLogin to ${options.showAppsembleLogin}`);
|
|
796
|
+
formData.append('showAppsembleLogin', String(options.showAppsembleLogin));
|
|
797
|
+
}
|
|
798
|
+
if (options.showAppsembleOAuth2Login !== undefined) {
|
|
799
|
+
logger.info(`Setting showAppsembleOAuth2Login to ${options.showAppsembleOAuth2Login}`);
|
|
800
|
+
formData.append('showAppsembleOAuth2Login', String(options.showAppsembleOAuth2Login));
|
|
801
|
+
}
|
|
802
|
+
if (options.enableSelfRegistration !== undefined) {
|
|
803
|
+
logger.info(`Setting enableSelfRegistration to ${options.enableSelfRegistration}`);
|
|
804
|
+
formData.append('enableSelfRegistration', String(options.enableSelfRegistration));
|
|
805
|
+
}
|
|
806
|
+
try {
|
|
807
|
+
if (!formData.getLengthSync() && options.locked === undefined) {
|
|
808
|
+
logger.warn('Nothing to patch. Need at least one additional argument to patch app.');
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (formData.getLengthSync()) {
|
|
812
|
+
const { data } = await axios.patch(`/api/apps/${id}`, formData);
|
|
813
|
+
logger.info(`Successfully updated app with id ${id}`);
|
|
814
|
+
const { host, protocol } = new URL(remote);
|
|
815
|
+
logger.info(`App URL: ${protocol}//${data.path}.${data.OrganizationId}.${host}`);
|
|
816
|
+
}
|
|
817
|
+
if (options.locked !== undefined) {
|
|
818
|
+
await axios.post(`/api/apps/${id}/lock`, {
|
|
819
|
+
locked: options.locked,
|
|
820
|
+
});
|
|
821
|
+
logger.info(`Successfully set app lock value for app with id ${id} to ${options.locked}`);
|
|
822
|
+
}
|
|
823
|
+
logger.info(`App store page: ${new URL(`/apps/${id}`, remote)}`);
|
|
824
|
+
}
|
|
825
|
+
catch (error) {
|
|
826
|
+
logger.error(error);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
762
829
|
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/app.test.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { authenticate } from '@appsemble/node-utils';
|
|
2
|
+
import { authorizeClientCredentials, createServer, createTestUser, models, setArgv, useTestDatabase, } from '@appsemble/server';
|
|
3
|
+
import { setTestApp } from 'axios-test-instance';
|
|
4
|
+
import { hash } from 'bcrypt';
|
|
5
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { patchApp } from './app.js';
|
|
7
|
+
import { initAxios } from './initAxios.js';
|
|
8
|
+
const { App, Organization, OrganizationMember } = models;
|
|
9
|
+
const argv = { host: 'http://localhost', secret: 'test', aesSecret: 'testSecret' };
|
|
10
|
+
let user;
|
|
11
|
+
let organization;
|
|
12
|
+
let testApp;
|
|
13
|
+
async function authorizeCLI(scopes) {
|
|
14
|
+
const OAuth2AuthorizationCode = await authorizeClientCredentials(scopes);
|
|
15
|
+
const { id, secret } = OAuth2AuthorizationCode;
|
|
16
|
+
await OAuth2AuthorizationCode.update({ secret: await hash(secret, 10) });
|
|
17
|
+
await authenticate(testApp.defaults.baseURL, scopes, `${id}:${secret}`);
|
|
18
|
+
}
|
|
19
|
+
useTestDatabase(import.meta);
|
|
20
|
+
beforeAll(() => {
|
|
21
|
+
vi.useFakeTimers();
|
|
22
|
+
setArgv(argv);
|
|
23
|
+
});
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
vi.clearAllTimers();
|
|
26
|
+
vi.setSystemTime(0);
|
|
27
|
+
const server = await createServer();
|
|
28
|
+
testApp = await setTestApp(server);
|
|
29
|
+
initAxios({ remote: testApp.defaults.baseURL });
|
|
30
|
+
user = await createTestUser();
|
|
31
|
+
organization = await Organization.create({
|
|
32
|
+
id: 'testorganization',
|
|
33
|
+
name: 'Test Organization',
|
|
34
|
+
});
|
|
35
|
+
await OrganizationMember.create({
|
|
36
|
+
OrganizationId: organization.id,
|
|
37
|
+
UserId: user.id,
|
|
38
|
+
role: 'Owner',
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
afterAll(() => {
|
|
42
|
+
vi.useRealTimers();
|
|
43
|
+
});
|
|
44
|
+
describe('patchApp', () => {
|
|
45
|
+
it('should apply patches to app', async () => {
|
|
46
|
+
const patches = {
|
|
47
|
+
demoMode: true,
|
|
48
|
+
enableSelfRegistration: true,
|
|
49
|
+
iconBackground: '#FFFFFF',
|
|
50
|
+
locked: 'fullLock',
|
|
51
|
+
path: 'updated-path',
|
|
52
|
+
showAppDefinition: true,
|
|
53
|
+
showAppsembleLogin: true,
|
|
54
|
+
showAppsembleOAuth2Login: true,
|
|
55
|
+
template: true,
|
|
56
|
+
visibility: 'private',
|
|
57
|
+
};
|
|
58
|
+
const app = await App.create({
|
|
59
|
+
path: 'test-app',
|
|
60
|
+
definition: { name: 'Test App', defaultPage: 'Test Page' },
|
|
61
|
+
vapidPublicKey: 'a',
|
|
62
|
+
vapidPrivateKey: 'b',
|
|
63
|
+
visibility: 'public',
|
|
64
|
+
OrganizationId: organization.id,
|
|
65
|
+
}, { raw: true });
|
|
66
|
+
await authorizeCLI('apps:write');
|
|
67
|
+
await patchApp({
|
|
68
|
+
...patches,
|
|
69
|
+
remote: testApp.defaults.baseURL,
|
|
70
|
+
id: app.id,
|
|
71
|
+
});
|
|
72
|
+
await app.reload();
|
|
73
|
+
expect(app.dataValues).toStrictEqual(expect.objectContaining({ ...app.dataValues, ...patches }));
|
|
74
|
+
expect(app.dataValues).toMatchInlineSnapshot(`
|
|
75
|
+
{
|
|
76
|
+
"OrganizationId": "testorganization",
|
|
77
|
+
"controllerCode": null,
|
|
78
|
+
"controllerImplementations": null,
|
|
79
|
+
"coreStyle": null,
|
|
80
|
+
"created": 1970-01-01T00:00:00.000Z,
|
|
81
|
+
"definition": {
|
|
82
|
+
"defaultPage": "Test Page",
|
|
83
|
+
"name": "Test App",
|
|
84
|
+
},
|
|
85
|
+
"deleted": null,
|
|
86
|
+
"demoMode": true,
|
|
87
|
+
"domain": null,
|
|
88
|
+
"emailHost": null,
|
|
89
|
+
"emailName": null,
|
|
90
|
+
"emailPassword": null,
|
|
91
|
+
"emailPort": 587,
|
|
92
|
+
"emailSecure": true,
|
|
93
|
+
"emailUser": null,
|
|
94
|
+
"enableSelfRegistration": true,
|
|
95
|
+
"enableUnsecuredServiceSecrets": false,
|
|
96
|
+
"googleAnalyticsID": null,
|
|
97
|
+
"icon": null,
|
|
98
|
+
"iconBackground": "#FFFFFF",
|
|
99
|
+
"id": 1,
|
|
100
|
+
"locked": "fullLock",
|
|
101
|
+
"maskableIcon": null,
|
|
102
|
+
"path": "updated-path",
|
|
103
|
+
"scimEnabled": false,
|
|
104
|
+
"scimToken": null,
|
|
105
|
+
"sentryDsn": null,
|
|
106
|
+
"sentryEnvironment": null,
|
|
107
|
+
"sharedStyle": null,
|
|
108
|
+
"showAppDefinition": true,
|
|
109
|
+
"showAppsembleLogin": true,
|
|
110
|
+
"showAppsembleOAuth2Login": true,
|
|
111
|
+
"sslCertificate": null,
|
|
112
|
+
"sslKey": null,
|
|
113
|
+
"template": true,
|
|
114
|
+
"updated": 1970-01-01T00:00:00.000Z,
|
|
115
|
+
"vapidPrivateKey": "b",
|
|
116
|
+
"vapidPublicKey": "a",
|
|
117
|
+
"visibility": "private",
|
|
118
|
+
}
|
|
119
|
+
`);
|
|
120
|
+
});
|
|
121
|
+
it.each `
|
|
122
|
+
key | from | to
|
|
123
|
+
${'demoMode'} | ${false} | ${true}
|
|
124
|
+
${'demoMode'} | ${true} | ${false}
|
|
125
|
+
${'enableSelfRegistration'} | ${false} | ${true}
|
|
126
|
+
${'enableSelfRegistration'} | ${true} | ${false}
|
|
127
|
+
${'iconBackground'} | ${''} | ${'#FFFFFF'}
|
|
128
|
+
${'path'} | ${'before'} | ${'after'}
|
|
129
|
+
${'locked'} | ${'unlocked'} | ${'studioLock'}
|
|
130
|
+
${'locked'} | ${'unlocked'} | ${'fullLock'}
|
|
131
|
+
${'locked'} | ${'fullLock'} | ${'unlocked'}
|
|
132
|
+
${'showAppDefinition'} | ${false} | ${true}
|
|
133
|
+
${'showAppDefinition'} | ${true} | ${false}
|
|
134
|
+
${'showAppsembleLogin'} | ${false} | ${true}
|
|
135
|
+
${'showAppsembleLogin'} | ${true} | ${false}
|
|
136
|
+
${'showAppsembleOAuth2Login'} | ${false} | ${true}
|
|
137
|
+
${'showAppsembleOAuth2Login'} | ${true} | ${false}
|
|
138
|
+
${'template'} | ${false} | ${true}
|
|
139
|
+
${'template'} | ${true} | ${false}
|
|
140
|
+
${'visibility'} | ${'public'} | ${'unlisted'}
|
|
141
|
+
${'visibility'} | ${'public'} | ${'private'}
|
|
142
|
+
${'visibility'} | ${'private'} | ${'public'}
|
|
143
|
+
`('should patch $key from `$from` to `$to`', async ({ from, key, to }) => {
|
|
144
|
+
const app = await App.create({
|
|
145
|
+
path: 'test-app',
|
|
146
|
+
definition: { name: 'Test App', defaultPage: 'Test Page' },
|
|
147
|
+
vapidPublicKey: 'a',
|
|
148
|
+
vapidPrivateKey: 'b',
|
|
149
|
+
visibility: 'public',
|
|
150
|
+
OrganizationId: organization.id,
|
|
151
|
+
[key]: from,
|
|
152
|
+
}, { raw: true });
|
|
153
|
+
await authorizeCLI('apps:write');
|
|
154
|
+
await patchApp({
|
|
155
|
+
[key]: to,
|
|
156
|
+
remote: testApp.defaults.baseURL,
|
|
157
|
+
id: app.id,
|
|
158
|
+
});
|
|
159
|
+
expect(app.dataValues[key]).toStrictEqual(from);
|
|
160
|
+
await app.reload();
|
|
161
|
+
expect(app.dataValues[key]).toStrictEqual(to);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
//# sourceMappingURL=app.test.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/cli",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.10",
|
|
4
4
|
"description": "The CLI for developing with Appsemble apps and blocks",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"test": "vitest"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@appsemble/node-utils": "0.27.
|
|
46
|
-
"@appsemble/types": "0.27.
|
|
47
|
-
"@appsemble/utils": "0.27.
|
|
45
|
+
"@appsemble/node-utils": "0.27.10",
|
|
46
|
+
"@appsemble/types": "0.27.10",
|
|
47
|
+
"@appsemble/utils": "0.27.10",
|
|
48
48
|
"@fortawesome/fontawesome-common-types": "^6.0.0",
|
|
49
49
|
"@koa/cors": "^4.0.0",
|
|
50
50
|
"@odata/parser": "^0.2.0",
|
|
@@ -87,7 +87,10 @@
|
|
|
87
87
|
"yargs": "^17.0.0"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@appsemble/types": "0.27.
|
|
90
|
+
"@appsemble/types": "0.27.10",
|
|
91
|
+
"@appsemble/server": "0.27.10",
|
|
92
|
+
"bcrypt": "^5.0.0",
|
|
93
|
+
"axios-test-instance": "^7.0.0",
|
|
91
94
|
"@types/concat-stream": "^2.0.0",
|
|
92
95
|
"@types/inquirer": "^9.0.0",
|
|
93
96
|
"@types/normalize-path": "^3.0.0",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
export async function getAppReadmes({ app }) {
|
|
3
|
+
const readme = await readFile(`${app.path}/readmes/${app.readmeUrl}`);
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
id: 0,
|
|
7
|
+
file: readme,
|
|
8
|
+
},
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=getAppReadmes.js.map
|
package/server/options/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyAppServiceSecrets, checkRole, createAppAsset, createAppResourcesWithAssets, createSettings, createTheme, deleteAppAsset, deleteAppResource, email, getApp, getAppAssets, getAppBlockStyles, getAppDetails, getAppIcon, getAppMembers, getAppMessages, getAppResource, getAppResources, getAppScreenshots, getAppStyles, getAppTeams, getAppUrl, getAppUserInfo, getBlockAsset, getBlockMessages, getBlocksAssetsPaths, getCsp, getDbUpdated, getHost, getTheme, parseQuery, reloadUser, sendNotifications, updateAppResource, verifyResourceActionPermission, } from './index.js';
|
|
1
|
+
import { applyAppServiceSecrets, checkRole, createAppAsset, createAppResourcesWithAssets, createSettings, createTheme, deleteAppAsset, deleteAppResource, email, getApp, getAppAssets, getAppBlockStyles, getAppDetails, getAppIcon, getAppMembers, getAppMessages, getAppReadmes, getAppResource, getAppResources, getAppScreenshots, getAppStyles, getAppTeams, getAppUrl, getAppUserInfo, getBlockAsset, getBlockMessages, getBlocksAssetsPaths, getCsp, getDbUpdated, getHost, getTheme, parseQuery, reloadUser, sendNotifications, updateAppResource, verifyResourceActionPermission, } from './index.js';
|
|
2
2
|
export const options = {
|
|
3
3
|
applyAppServiceSecrets,
|
|
4
4
|
checkRole,
|
|
@@ -16,6 +16,7 @@ export const options = {
|
|
|
16
16
|
getAppIcon,
|
|
17
17
|
getAppMembers,
|
|
18
18
|
getAppMessages,
|
|
19
|
+
getAppReadmes,
|
|
19
20
|
getAppResource,
|
|
20
21
|
getAppResources,
|
|
21
22
|
getAppScreenshots,
|
|
@@ -6,7 +6,7 @@ pages:
|
|
|
6
6
|
- name: Example Page A
|
|
7
7
|
blocks:
|
|
8
8
|
- type: action-button
|
|
9
|
-
version: 0.27.
|
|
9
|
+
version: 0.27.10
|
|
10
10
|
parameters:
|
|
11
11
|
icon: arrow-right
|
|
12
12
|
actions:
|
|
@@ -17,7 +17,7 @@ pages:
|
|
|
17
17
|
- name: Example Page B
|
|
18
18
|
blocks:
|
|
19
19
|
- type: action-button
|
|
20
|
-
version: 0.27.
|
|
20
|
+
version: 0.27.10
|
|
21
21
|
parameters:
|
|
22
22
|
icon: arrow-left
|
|
23
23
|
actions:
|