@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 CHANGED
@@ -1,9 +1,9 @@
1
- # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.27.9/config/assets/logo.svg) Appsemble CLI
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.27.10/config/assets/logo.svg) Appsemble CLI
2
2
 
3
3
  > Manage apps and blocks from the command line.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@appsemble/cli)](https://www.npmjs.com/package/@appsemble/cli)
6
- [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.27.9/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.27.9)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.27.10/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.27.10)
7
7
  [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](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.9/LICENSE.md) ©
326
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.27.10/LICENSE.md) ©
327
327
  [Appsemble](https://appsemble.com)
@@ -1,6 +1,5 @@
1
1
  import { authenticate, logger } from '@appsemble/node-utils';
2
- import axios from 'axios';
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
- const formData = new FormData();
59
- if (args.path) {
60
- logger.info(`Setting app path to ${args.path}`);
61
- formData.append('path', args.path);
62
- }
63
- if (args.force) {
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, readFile, rm, stat } from 'node:fs/promises';
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
- logger.warn(`Found unused file ${filepath}`);
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 {};
@@ -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.9",
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.9",
46
- "@appsemble/types": "0.27.9",
47
- "@appsemble/utils": "0.27.9",
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.9",
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,2 @@
1
+ import { type AppReadme as AppReadmeInterface, type GetAppSubEntityParams } from '@appsemble/node-utils';
2
+ export declare function getAppReadmes({ app }: GetAppSubEntityParams): Promise<AppReadmeInterface[]>;
@@ -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
@@ -33,3 +33,4 @@ export * from './applyAppServiceSecrets.js';
33
33
  export * from './getAppMembers.js';
34
34
  export * from './getAppTeams.js';
35
35
  export * from './getAppUserInfo.js';
36
+ export * from './getAppReadmes.js';
@@ -33,4 +33,5 @@ export * from './applyAppServiceSecrets.js';
33
33
  export * from './getAppMembers.js';
34
34
  export * from './getAppTeams.js';
35
35
  export * from './getAppUserInfo.js';
36
+ export * from './getAppReadmes.js';
36
37
  //# sourceMappingURL=index.js.map
@@ -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
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.9
20
+ version: 0.27.10
21
21
  parameters:
22
22
  icon: arrow-left
23
23
  actions:
@@ -2,7 +2,7 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@appsemble/sdk": "0.27.9",
5
+ "@appsemble/sdk": "0.27.10",
6
6
  "mini-jsx": "^4.0.0"
7
7
  }
8
8
  }
@@ -2,8 +2,8 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@appsemble/preact": "0.27.9",
6
- "@appsemble/sdk": "0.27.9",
5
+ "@appsemble/preact": "0.27.10",
6
+ "@appsemble/sdk": "0.27.10",
7
7
  "preact": "^10.0.0"
8
8
  }
9
9
  }
@@ -2,6 +2,6 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@appsemble/sdk": "0.27.9"
5
+ "@appsemble/sdk": "0.27.10"
6
6
  }
7
7
  }