@appsemble/cli 0.23.3 → 0.23.4

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.23.3/config/assets/logo.svg) Appsemble CLI
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.23.4/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.23.3/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.23.3)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.23.4/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.23.4)
7
7
  [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://prettier.io)
8
8
 
9
9
  ## Table of Contents
@@ -144,8 +144,8 @@ arguments.
144
144
  appsemble app create
145
145
  ```
146
146
 
147
- The Appsemble CLI can be used to create, update and delete apps. For example, to create an app in
148
- the `apps/my-app` directory, run:
147
+ The Appsemble CLI can be used to create, export, import and update apps. For example, to create an
148
+ app in the `apps/my-app` directory, run:
149
149
 
150
150
  ```sh
151
151
  appsemble app publish apps/my-app
@@ -163,6 +163,22 @@ To delete an app using the CLI use the following command:
163
163
  appsemble app delete --id <appId>
164
164
  ```
165
165
 
166
+ To export an app as a zip file, run the following:
167
+
168
+ ```sh
169
+ appsemble app export --id <app-id>
170
+ ```
171
+
172
+ Supported arguments for this app are `resources` and `path`. Resources is used to specify whether to
173
+ include the resources in the exported file and path is the path of the folder where you want to put
174
+ your downloaded file. Path is `./apps` by default and resources is set to `false`.
175
+
176
+ To import an app from a zip file, use the following command:
177
+
178
+ ```sh
179
+ appsemble app import <path-of-zip-file> --organization <organizationId>
180
+ ```
181
+
166
182
  For a more in depth explanation of how to build apps, use our
167
183
  [app building guide](https://appsemble.app/docs/guide).
168
184
 
@@ -288,5 +304,5 @@ appsemble run-cronjobs --interval 30
288
304
 
289
305
  ## License
290
306
 
291
- [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.23.3/LICENSE.md) ©
307
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.23.4/LICENSE.md) ©
292
308
  [Appsemble](https://appsemble.com)
@@ -0,0 +1,12 @@
1
+ import { type Argv } from 'yargs';
2
+ import { type BaseArguments } from '../../types.js';
3
+ interface ExportAppArgs extends BaseArguments {
4
+ id: number;
5
+ resources: boolean;
6
+ path?: string;
7
+ }
8
+ export declare const command = "export";
9
+ export declare const description = "Export an app as a zip file using app id.\n App definition, styles and messages are exported by default, to export resources, make sure you have suitable permissions and use the '--resources' flag.";
10
+ export declare function builder(yargs: Argv): Argv<any>;
11
+ export declare function handler(args: ExportAppArgs): Promise<void>;
12
+ export {};
@@ -0,0 +1,29 @@
1
+ import { join } from 'node:path';
2
+ import { authenticate, logger } from '@appsemble/node-utils';
3
+ import { exportAppAsZip } from '../../lib/app.js';
4
+ export const command = 'export';
5
+ export const description = `Export an app as a zip file using app id.
6
+ App definition, styles and messages are exported by default, to export resources, make sure you have suitable permissions and use the '--resources' flag.`;
7
+ export function builder(yargs) {
8
+ return yargs
9
+ .option('id', {
10
+ describe: 'Id of the app to be exported as a zip file',
11
+ demandOption: true,
12
+ })
13
+ .option('resources', {
14
+ describe: 'Boolean representing whether the resources should be exported or not',
15
+ default: false,
16
+ })
17
+ .option('path', {
18
+ describe: 'Path of the folder where you want to put your exported file.',
19
+ });
20
+ }
21
+ export async function handler(args) {
22
+ const { clientCredentials, id: appId, path: outputDirectory, remote, resources } = args;
23
+ const defaultOutputDirectory = join(process.cwd(), 'apps');
24
+ await authenticate(remote, 'apps:export', clientCredentials);
25
+ logger.info(`Exporting app with id: ${appId}`);
26
+ await exportAppAsZip(appId, resources, outputDirectory || defaultOutputDirectory, remote);
27
+ logger.info('Export completed successfully');
28
+ }
29
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1,11 @@
1
+ import { type Argv } from 'yargs';
2
+ import { type BaseArguments } from '../../types.js';
3
+ interface ImportAppArgs extends BaseArguments {
4
+ organization: string;
5
+ path: string;
6
+ }
7
+ export declare const command = "import <path>";
8
+ export declare const description = "Import an app from a zip file using organization id. App definition, styles, resources and messages can be imported from the zip file.";
9
+ export declare function builder(yargs: Argv): Argv<any>;
10
+ export declare function handler(args: ImportAppArgs): Promise<void>;
11
+ export {};
@@ -0,0 +1,36 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { authenticate, logger } from '@appsemble/node-utils';
3
+ import axios from 'axios';
4
+ export const command = 'import <path>';
5
+ export const description = 'Import an app from a zip file using organization id. App definition, styles, resources and messages can be imported from the zip file.';
6
+ export function builder(yargs) {
7
+ return yargs
8
+ .positional('path', {
9
+ describe: 'Path of the zip file you want to import.',
10
+ required: true,
11
+ })
12
+ .option('organization', {
13
+ describe: 'Id of the organization to which app will be imported.',
14
+ demandOption: true,
15
+ });
16
+ }
17
+ export async function handler(args) {
18
+ const { clientCredentials, organization, path: inputFile, remote } = args;
19
+ const [, extName] = inputFile.split('.');
20
+ if (extName !== 'zip') {
21
+ logger.error('Input file must be a zip file.');
22
+ return;
23
+ }
24
+ await authenticate(remote, 'apps:write', clientCredentials);
25
+ logger.info(`Importing app to organization: ${organization}`);
26
+ const zipFile = await readFile(inputFile);
27
+ const config = {
28
+ base: remote,
29
+ headers: {
30
+ 'Content-Type': 'application/zip',
31
+ },
32
+ };
33
+ await axios.post(`/api/apps/import/organization/${organization}`, zipFile, config);
34
+ logger.info('Importing app completed successfully');
35
+ }
36
+ //# sourceMappingURL=import.js.map
@@ -1,6 +1,8 @@
1
1
  import * as create from './create.js';
2
2
  import * as remove from './delete.js';
3
+ import * as exportApp from './export.js';
3
4
  import * as extractMessages from './extract-messages.js';
5
+ import * as importApp from './import.js';
4
6
  import * as publish from './publish.js';
5
7
  import * as update from './update.js';
6
8
  export { noop as handler } from '@appsemble/utils';
@@ -11,7 +13,9 @@ export function builder(yargs) {
11
13
  .command(publish)
12
14
  .command(create)
13
15
  .command(remove)
16
+ .command(exportApp)
14
17
  .command(extractMessages)
18
+ .command(importApp)
15
19
  .command(update)
16
20
  .demandCommand(1);
17
21
  }
@@ -1,5 +1,5 @@
1
1
  import { has } from '@appsemble/utils';
2
- import { readPackageUp } from 'read-pkg-up';
2
+ import { readPackageUp } from 'read-package-up';
3
3
  export const command = 'get <key>';
4
4
  export const description = 'Get an Appsemble configuration option from package.json.';
5
5
  export function builder(yargs) {
@@ -1,7 +1,7 @@
1
1
  import { inspect } from 'node:util';
2
2
  import { logger, writeData } from '@appsemble/node-utils';
3
3
  import { has } from '@appsemble/utils';
4
- import { readPackageUp } from 'read-pkg-up';
4
+ import { readPackageUp } from 'read-package-up';
5
5
  export const command = 'set <key> <value>';
6
6
  export const description = 'Set an Appsemble configuration option in package.json.';
7
7
  export function builder(yargs) {
package/lib/app.d.ts CHANGED
@@ -145,6 +145,15 @@ interface UpdateAppParams {
145
145
  * @returns The context from `.appsemblerc.yaml` if a match was found.
146
146
  */
147
147
  export declare function traverseAppDirectory(path: string, context: string, formData: FormData): Promise<[AppsembleContext, AppsembleRC, string, App]>;
148
+ /**
149
+ * Export an app as a zip file.
150
+ *
151
+ * @param appId Id of the app to be exported.
152
+ * @param resources Boolean representing whether to include resources in the zip file.
153
+ * @param path Path of the folder where you want to put your downloaded file.
154
+ * @param remote The remote to fetch the app from.
155
+ */
156
+ export declare function exportAppAsZip(appId: number, resources: boolean, path: string, remote: string): Promise<void>;
148
157
  /**
149
158
  * Upload messages for an app.
150
159
  *
package/lib/app.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createReadStream, existsSync } from 'node:fs';
1
+ import { createReadStream, createWriteStream, existsSync } from 'node:fs';
2
2
  import { mkdir, readdir, readFile, stat } from 'node:fs/promises';
3
3
  import { basename, join, parse, relative, resolve } from 'node:path';
4
4
  import { inspect } from 'node:util';
@@ -105,6 +105,26 @@ export async function traverseAppDirectory(path, context, formData) {
105
105
  : maskableIconPath;
106
106
  return [discoveredContext, rc, yaml, gatheredData];
107
107
  }
108
+ /**
109
+ * Export an app as a zip file.
110
+ *
111
+ * @param appId Id of the app to be exported.
112
+ * @param resources Boolean representing whether to include resources in the zip file.
113
+ * @param path Path of the folder where you want to put your downloaded file.
114
+ * @param remote The remote to fetch the app from.
115
+ */
116
+ export async function exportAppAsZip(appId, resources, path, remote) {
117
+ const app = await axios.get(`/api/apps/${appId}`);
118
+ const { name } = app.data.definition;
119
+ const response = await axios.get(`/api/apps/${appId}/export?resources=${resources}`, {
120
+ baseURL: remote,
121
+ responseType: 'stream',
122
+ });
123
+ const zipFileName = join(path, `${name}_${appId}.zip`);
124
+ const writeStream = createWriteStream(zipFileName);
125
+ response.data.pipe(writeStream);
126
+ logger.info(`Successfully downloaded file: ${zipFileName}`);
127
+ }
108
128
  /**
109
129
  * Upload messages for an app.
110
130
  *
@@ -31,7 +31,7 @@ function waitForCredentials(url) {
31
31
  catch {
32
32
  throwKoaError(ctx, 400, 'Invalid JSON');
33
33
  }
34
- assertKoaError(typeof credentials === 'string' && validate(credentials), ctx, 400, 'Invalid client credentials');
34
+ assertKoaError(typeof credentials === 'string' && !validate(credentials), ctx, 400, 'Invalid client credentials');
35
35
  ctx.status = 204;
36
36
  server.close();
37
37
  resolve(credentials);
package/lib/block.d.ts CHANGED
@@ -25,7 +25,7 @@ export declare function getBlockConfig(dir: string): Promise<BlockConfig>;
25
25
  /**
26
26
  * Discover Appsemble blocks based on workspaces in a monorepo.
27
27
  *
28
- * Both Lerna and Yarn workspaces are supported.
28
+ * npm workspaces are supported.
29
29
  *
30
30
  * @param root The project root in which to find workspaces.
31
31
  * @returns Discovered Appsemble blocks.
package/lib/block.js CHANGED
@@ -78,7 +78,7 @@ export async function getBlockConfig(dir) {
78
78
  /**
79
79
  * Discover Appsemble blocks based on workspaces in a monorepo.
80
80
  *
81
- * Both Lerna and Yarn workspaces are supported.
81
+ * npm workspaces are supported.
82
82
  *
83
83
  * @param root The project root in which to find workspaces.
84
84
  * @returns Discovered Appsemble blocks.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appsemble/cli",
3
- "version": "0.23.3",
3
+ "version": "0.23.4",
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.23.3",
46
- "@appsemble/types": "0.23.3",
47
- "@appsemble/utils": "0.23.3",
45
+ "@appsemble/node-utils": "0.23.4",
46
+ "@appsemble/types": "0.23.4",
47
+ "@appsemble/utils": "0.23.4",
48
48
  "@fortawesome/fontawesome-common-types": "^6.0.0",
49
49
  "@koa/cors": "^4.0.0",
50
50
  "@odata/parser": "^0.2.0",
@@ -55,7 +55,7 @@
55
55
  "csvtojson": "^2.0.0",
56
56
  "fast-glob": "^3.0.0",
57
57
  "form-data": "^4.0.0",
58
- "global-cache-dir": "^5.0.0",
58
+ "global-cache-dir": "^6.0.0",
59
59
  "inquirer": "^9.0.0",
60
60
  "jsonschema": "^1.0.0",
61
61
  "koa": "^2.0.0",
@@ -76,7 +76,7 @@
76
76
  "postcss-load-config": "^4.0.0",
77
77
  "postcss-url": "^10.0.0",
78
78
  "raw-body": "^2.0.0",
79
- "read-pkg-up": "^10.0.0",
79
+ "read-package-up": "^11.0.0",
80
80
  "sharp": "^0.32.0",
81
81
  "ts-json-schema-generator": "^1.0.0",
82
82
  "type-fest": "^4.0.0",
@@ -85,7 +85,7 @@
85
85
  "yargs": "^17.0.0"
86
86
  },
87
87
  "devDependencies": {
88
- "@appsemble/types": "0.23.3",
88
+ "@appsemble/types": "0.23.4",
89
89
  "@types/concat-stream": "^2.0.0",
90
90
  "@types/inquirer": "^9.0.0",
91
91
  "@types/normalize-path": "^3.0.0",
@@ -6,7 +6,7 @@ pages:
6
6
  - name: Example Page A
7
7
  blocks:
8
8
  - type: action-button
9
- version: 0.23.3
9
+ version: 0.23.4
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.23.3
20
+ version: 0.23.4
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.23.3",
5
+ "@appsemble/sdk": "0.23.4",
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.23.3",
6
- "@appsemble/sdk": "0.23.3",
5
+ "@appsemble/preact": "0.23.4",
6
+ "@appsemble/sdk": "0.23.4",
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.23.3"
5
+ "@appsemble/sdk": "0.23.4"
6
6
  }
7
7
  }
package/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type AppVisibility } from '@appsemble/types';
2
- import { type PackageJson } from 'read-pkg-up';
2
+ import { type PackageJson } from 'read-package-up';
3
3
  import { type JsonObject } from 'type-fest';
4
4
  /**
5
5
  * The base arguments from the command line.