@appsemble/cli 0.21.2 → 0.22.0
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 +46 -11
- package/commands/app/create.d.ts +11 -24
- package/commands/app/create.js +98 -62
- package/commands/app/index.js +2 -0
- package/commands/app/publish.d.ts +27 -0
- package/commands/app/publish.js +75 -0
- package/commands/asset/index.js +2 -2
- package/commands/asset/{create.d.ts → publish.d.ts} +4 -4
- package/commands/asset/{create.js → publish.js} +8 -8
- package/commands/block/create.d.ts +12 -0
- package/commands/block/create.js +66 -0
- package/commands/block/delete.d.ts +11 -0
- package/commands/block/delete.js +22 -0
- package/commands/block/index.js +4 -0
- package/commands/migrate.js +2 -2
- package/commands/resource/index.js +2 -2
- package/commands/resource/{create.d.ts → publish.d.ts} +4 -4
- package/commands/resource/{create.js → publish.js} +8 -8
- package/commands/serve.js +20 -14
- package/index.js +2 -3
- package/lib/app.d.ts +8 -9
- package/lib/app.js +8 -8
- package/lib/asset.d.ts +4 -4
- package/lib/asset.js +2 -2
- package/lib/block.d.ts +8 -0
- package/lib/block.js +6 -6
- package/lib/createServers.js +13 -9
- package/lib/getBlockConfigFromTypeScript.test.js +3 -1
- package/lib/initAxios.js +2 -3
- package/lib/resource.d.ts +5 -5
- package/lib/resource.js +3 -3
- package/package.json +14 -7
- package/server/db/methods.js +5 -1
- package/server/options/getAppBlockStyles.js +17 -17
- package/server/options/parseQuery.js +13 -9
- package/templates/apps/empty/.appsemblerc.yaml +15 -0
- package/templates/apps/empty/app-definition.yaml +26 -0
- package/templates/apps/empty/assets/.gitkeep +0 -0
- package/templates/apps/empty/i18n/en.json +0 -0
- package/templates/apps/empty/resources/.gitkeep +0 -0
- package/templates/apps/empty/themes/@appsemble/.gitkeep +0 -0
- package/templates/apps/empty/themes/core/index.css +3 -0
- package/templates/apps/empty/themes/shared/index.css +3 -0
- package/templates/blocks/mini-jsx/.appsemblerc.yaml +1 -0
- package/templates/blocks/mini-jsx/README.md +11 -0
- package/templates/blocks/mini-jsx/block.ts +48 -0
- package/templates/blocks/mini-jsx/i18n/en.json +3 -0
- package/templates/blocks/mini-jsx/package.json +8 -0
- package/templates/blocks/mini-jsx/src/index.module.css +19 -0
- package/templates/blocks/mini-jsx/src/index.tsx +61 -0
- package/templates/blocks/mini-jsx/tsconfig.json +9 -0
- package/templates/blocks/preact/.appsemblerc.yaml +1 -0
- package/templates/blocks/preact/README.md +11 -0
- package/templates/blocks/preact/block.ts +37 -0
- package/templates/blocks/preact/i18n/en.json +5 -0
- package/templates/blocks/preact/package.json +9 -0
- package/templates/blocks/preact/src/index.tsx +99 -0
- package/templates/blocks/preact/tsconfig.json +9 -0
- package/templates/blocks/vanilla/.appsemblerc.yaml +1 -0
- package/templates/blocks/vanilla/README.md +10 -0
- package/templates/blocks/vanilla/block.ts +20 -0
- package/templates/blocks/vanilla/i18n/en.json +3 -0
- package/templates/blocks/vanilla/package.json +7 -0
- package/templates/blocks/vanilla/src/index.ts +25 -0
- package/templates/blocks/vanilla/tsconfig.json +7 -0
- package/types.d.ts +0 -46
- package/vitest.config.d.ts +0 -2
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.22.0)
|
|
7
7
|
[](https://prettier.io)
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
@@ -85,8 +85,8 @@ App assets will be served from the local file system.
|
|
|
85
85
|
|
|
86
86
|
The development server will automatically fetch all blocks that are needed for the served app but
|
|
87
87
|
are missing from the local workspaces. These are typically third-party or proprietary blocks. The
|
|
88
|
-
development server will use `
|
|
89
|
-
from. The following option allows you to specify a different remote
|
|
88
|
+
development server will use `http://localhost:9999` as the default remote server to fetch blocks
|
|
89
|
+
from. The following option allows you to specify a different remote (e.g. `https://appsemble.app`):
|
|
90
90
|
|
|
91
91
|
```sh
|
|
92
92
|
appsemble serve <path-to-app-directory> --remote <remote>
|
|
@@ -136,11 +136,19 @@ appsemble organization create my-organization --name 'My Organization' --icon ic
|
|
|
136
136
|
|
|
137
137
|
### Apps
|
|
138
138
|
|
|
139
|
+
The Appsemble CLI allows you to bootstrap an Appsemble app into a standard Appsemble project layout.
|
|
140
|
+
The command is followed by a series of interactive questions. You can also pass the values as
|
|
141
|
+
arguments.
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
appsemble app create
|
|
145
|
+
```
|
|
146
|
+
|
|
139
147
|
The Appsemble CLI can be used to create and update apps. For example, to create an app in the
|
|
140
148
|
`apps/my-app` directory, run:
|
|
141
149
|
|
|
142
150
|
```sh
|
|
143
|
-
appsemble app
|
|
151
|
+
appsemble app publish apps/my-app
|
|
144
152
|
```
|
|
145
153
|
|
|
146
154
|
Similarly, to update an app using an app directory, run the following command:
|
|
@@ -154,13 +162,40 @@ For a more in depth explanation of how to build apps, use our
|
|
|
154
162
|
|
|
155
163
|
### Blocks
|
|
156
164
|
|
|
157
|
-
The Appsemble CLI
|
|
158
|
-
|
|
165
|
+
The Appsemble CLI allows you to bootstrap an Appsemble block into a standard Appsemble project
|
|
166
|
+
layout. The command is followed by a series of interactive questions.
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
appsemble block create
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The Appsemble CLI can also be used to publish and delete (although we don’t recommend doing it in
|
|
173
|
+
production) Appsemble blocks. For example, to publish all blocks in the `blocks` directory, run:
|
|
159
174
|
|
|
160
175
|
```sh
|
|
161
176
|
appsemble block publish blocks/*
|
|
162
177
|
```
|
|
163
178
|
|
|
179
|
+
or to publish a single block located in some other directory, run
|
|
180
|
+
|
|
181
|
+
```sh
|
|
182
|
+
appsemble block publish path/to/block/directory
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Blocks can be deleted if they are not in use by any apps. To delete a block, run
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
appsemble block delete <block-name:block-version>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Organization id can be passed as an argument(default for which is “appsemble”).
|
|
192
|
+
|
|
193
|
+
To know more about the block related commands, run
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
appsemble block --help
|
|
197
|
+
```
|
|
198
|
+
|
|
164
199
|
Building blocks uses
|
|
165
200
|
[ Webpack](https://webpack.js.org). To use
|
|
166
201
|
this, install the additional dependencies
|
|
@@ -189,7 +224,7 @@ The Appsemble CLI can be used to upload assets from disk. For example, the follo
|
|
|
189
224
|
an asset named `example-asset`:
|
|
190
225
|
|
|
191
226
|
```sh
|
|
192
|
-
appsemble asset
|
|
227
|
+
appsemble asset publish --app-id 1 path/to/example-asset.png
|
|
193
228
|
```
|
|
194
229
|
|
|
195
230
|
### Resources
|
|
@@ -206,11 +241,11 @@ The Appsemble CLI can be used to create a resource from a JSON file or directory
|
|
|
206
241
|
```
|
|
207
242
|
|
|
208
243
|
```sh
|
|
209
|
-
appsemble resource
|
|
244
|
+
appsemble resource publish --app-id 1 --context development --app path/to/my-app my-resource path/to/resources/my-resource.json
|
|
210
245
|
```
|
|
211
246
|
|
|
212
247
|
```sh
|
|
213
|
-
appsemble resource
|
|
248
|
+
appsemble resource publish --app-id 1 --context development --app path/to/my-app my-resource path/to/resources/*
|
|
214
249
|
```
|
|
215
250
|
|
|
216
251
|
And resources can also be updated when they contain an id in the JSON file.
|
|
@@ -247,5 +282,5 @@ appsemble run-cronjobs --interval 30
|
|
|
247
282
|
|
|
248
283
|
## License
|
|
249
284
|
|
|
250
|
-
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.
|
|
285
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.22.0/LICENSE.md) ©
|
|
251
286
|
[Appsemble](https://appsemble.com)
|
package/commands/app/create.d.ts
CHANGED
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
-
/// <reference types="node" resolution-mode="require"/>
|
|
3
|
-
import { type ReadStream } from 'node:fs';
|
|
4
|
-
import { type AppVisibility } from '@appsemble/types';
|
|
5
1
|
import { type Argv } from 'yargs';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
dryRun: boolean;
|
|
16
|
-
resources: boolean;
|
|
17
|
-
modifyContext: boolean;
|
|
18
|
-
visibility: AppVisibility;
|
|
19
|
-
sentryDsn: string;
|
|
20
|
-
sentryEnvironment: string;
|
|
21
|
-
googleAnalyticsId: string;
|
|
2
|
+
export declare const command = "create";
|
|
3
|
+
export declare const description = "Scaffold a new app with a basic app-definition and styling.";
|
|
4
|
+
interface AppArgs {
|
|
5
|
+
path?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
organization?: string;
|
|
8
|
+
template?: string;
|
|
9
|
+
languages?: string[];
|
|
10
|
+
description?: string;
|
|
22
11
|
}
|
|
23
|
-
export declare
|
|
24
|
-
export declare
|
|
25
|
-
export declare function builder(yargs: Argv): Argv<any>;
|
|
26
|
-
export declare function handler({ paths, ...args }: CreateAppArguments): Promise<void>;
|
|
12
|
+
export declare function builder(yargs: Argv): Promise<Argv<any>>;
|
|
13
|
+
export declare function handler(args: AppArgs): Promise<void>;
|
|
27
14
|
export {};
|
package/commands/app/create.js
CHANGED
|
@@ -1,75 +1,111 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export const
|
|
8
|
-
export
|
|
1
|
+
import { cp, readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { logger, readData, writeData } from '@appsemble/node-utils';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import { parse, stringify } from 'yaml';
|
|
6
|
+
const templatesDir = new URL('../../templates/apps/', import.meta.url);
|
|
7
|
+
export const command = 'create';
|
|
8
|
+
export const description = 'Scaffold a new app with a basic app-definition and styling.';
|
|
9
|
+
export async function builder(yargs) {
|
|
10
|
+
const templateChoices = await readdir(templatesDir);
|
|
11
|
+
const languageChoices = ['en', 'nl', 'ru', 'fr', 'de', 'da', 'id', 'hr'];
|
|
9
12
|
return yargs
|
|
10
|
-
.
|
|
11
|
-
describe: '
|
|
13
|
+
.option('path', {
|
|
14
|
+
describe: 'Path of the folder where you want to put your app.',
|
|
12
15
|
})
|
|
13
|
-
.option('
|
|
14
|
-
describe: '
|
|
16
|
+
.option('name', {
|
|
17
|
+
describe: 'The name of the app.',
|
|
15
18
|
})
|
|
16
19
|
.option('organization', {
|
|
17
|
-
describe: 'The ID
|
|
20
|
+
describe: 'The Organization ID app should be created for.',
|
|
18
21
|
})
|
|
19
|
-
.option('
|
|
20
|
-
describe: 'The
|
|
21
|
-
coerce: coerceFile,
|
|
22
|
-
})
|
|
23
|
-
.option('icon-background', {
|
|
24
|
-
describe: 'The background color to use for the icon in opaque contexts.',
|
|
25
|
-
default: '#ffffff',
|
|
26
|
-
})
|
|
27
|
-
.option('maskable-icon', {
|
|
28
|
-
describe: 'The maskable icon to upload. By default "maskable-icon.png" in the app directory is used.',
|
|
29
|
-
coerce: coerceFile,
|
|
30
|
-
})
|
|
31
|
-
.option('visibility', {
|
|
32
|
-
describe: 'Visibility of the app in the public app store.',
|
|
33
|
-
default: 'unlisted',
|
|
34
|
-
choices: ['public', 'unlisted', 'private'],
|
|
22
|
+
.option('description', {
|
|
23
|
+
describe: 'The description of the app.',
|
|
35
24
|
})
|
|
36
25
|
.option('template', {
|
|
37
|
-
describe: '
|
|
38
|
-
|
|
39
|
-
})
|
|
40
|
-
.option('dry-run', {
|
|
41
|
-
describe: 'Whether the API should be called to run without actually creating the app.',
|
|
42
|
-
type: 'boolean',
|
|
43
|
-
})
|
|
44
|
-
.option('resources', {
|
|
45
|
-
describe: 'Whether the resources from the `resources` directory should be created after creating the app. The names of subdirectories are used as the name of the resource, otherwise the names of top level resource .json files are used instead.',
|
|
46
|
-
type: 'boolean',
|
|
47
|
-
})
|
|
48
|
-
.option('modify-context', {
|
|
49
|
-
describe: 'If the app context is specified, modify it for the current context to include the id of the created app.',
|
|
50
|
-
type: 'boolean',
|
|
51
|
-
})
|
|
52
|
-
.option('google-analytics-id', {
|
|
53
|
-
describe: 'The ID for Google Analytics for the app.',
|
|
26
|
+
describe: 'The template to use.',
|
|
27
|
+
choices: templateChoices,
|
|
54
28
|
})
|
|
55
|
-
.option('
|
|
56
|
-
describe: '
|
|
57
|
-
|
|
58
|
-
.option('sentry-environment', {
|
|
59
|
-
describe: 'The environment for the custom Sentry DSN for the app.',
|
|
60
|
-
implies: ['sentry-dsn'],
|
|
29
|
+
.option('languages', {
|
|
30
|
+
describe: 'Languages in which the app will be translated.',
|
|
31
|
+
choices: languageChoices,
|
|
61
32
|
});
|
|
62
33
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
34
|
+
function validateAppName(input) {
|
|
35
|
+
if (input.length > 30 || input.length === 0) {
|
|
36
|
+
logger.error('Please input a valid app name. Name must be between 1 and 30 characters long.');
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
export async function handler(args) {
|
|
42
|
+
const templateChoices = await readdir(templatesDir);
|
|
43
|
+
const languageChoices = ['en', 'nl', 'ru', 'fr', 'de', 'da', 'id', 'hr'];
|
|
44
|
+
const answers = await inquirer.prompt([
|
|
45
|
+
!args.organization && {
|
|
46
|
+
name: 'organization',
|
|
47
|
+
message: 'For which organisation is this app? (default "appsemble")',
|
|
48
|
+
},
|
|
49
|
+
!args.name && {
|
|
50
|
+
name: 'name',
|
|
51
|
+
message: 'What will be the name of the app.',
|
|
52
|
+
validate: validateAppName,
|
|
53
|
+
},
|
|
54
|
+
!args.description && {
|
|
55
|
+
name: 'description',
|
|
56
|
+
message: 'Please describe your app.',
|
|
57
|
+
},
|
|
58
|
+
!args.template && {
|
|
59
|
+
name: 'template',
|
|
60
|
+
type: 'list',
|
|
61
|
+
choices: templateChoices,
|
|
62
|
+
message: 'Please choose a template to continue.',
|
|
63
|
+
},
|
|
64
|
+
!args.languages && {
|
|
65
|
+
name: 'languages',
|
|
66
|
+
type: 'checkbox',
|
|
67
|
+
choices: languageChoices,
|
|
68
|
+
message: 'Please select the languages for your app.',
|
|
69
|
+
},
|
|
70
|
+
!args.path && {
|
|
71
|
+
name: 'path',
|
|
72
|
+
message: 'Please enter the path for where you want the app folder to go (default "apps").',
|
|
73
|
+
},
|
|
74
|
+
].filter(Boolean));
|
|
75
|
+
const path = args.path || answers.path || join(process.cwd(), 'apps');
|
|
76
|
+
const organization = answers.organization || args.organization || 'appsemble';
|
|
77
|
+
const name = answers.name || args.name;
|
|
78
|
+
const appDescription = answers.description || args.description || '';
|
|
79
|
+
const template = answers.template || args.template;
|
|
80
|
+
const languages = answers.languages || args.languages;
|
|
81
|
+
const outputDirectory = join(path, name);
|
|
82
|
+
const inputDirectory = new URL(`${template}/`, templatesDir);
|
|
83
|
+
const appsembleRcPath = new URL('.appsemblerc.yaml', inputDirectory);
|
|
84
|
+
const [appsembleRc] = await readData(appsembleRcPath);
|
|
85
|
+
const outputAppsembleRcObject = { ...appsembleRc };
|
|
86
|
+
for (const key of Object.keys(appsembleRc.context)) {
|
|
87
|
+
outputAppsembleRcObject.context[key].organization = organization;
|
|
73
88
|
}
|
|
89
|
+
const outputAppsembleRc = parse(stringify(outputAppsembleRcObject));
|
|
90
|
+
const appDefinitionPath = new URL('app-definition.yaml', inputDirectory);
|
|
91
|
+
const [appDefinition] = await readData(appDefinitionPath);
|
|
92
|
+
const outputAppDefinitionObject = { ...appDefinition };
|
|
93
|
+
outputAppDefinitionObject.name = name;
|
|
94
|
+
outputAppDefinitionObject.description = appDescription;
|
|
95
|
+
const outputAppDefinition = parse(stringify(outputAppDefinitionObject));
|
|
96
|
+
await cp(inputDirectory, outputDirectory, {
|
|
97
|
+
errorOnExist: true,
|
|
98
|
+
filter: (src) => !src.endsWith('.appsemblerc.yaml') || !src.endsWith('app-definition.yaml'),
|
|
99
|
+
force: false,
|
|
100
|
+
recursive: true,
|
|
101
|
+
});
|
|
102
|
+
for (const language of languages) {
|
|
103
|
+
await writeData(join(outputDirectory, 'i18n', `${language}.json`), {});
|
|
104
|
+
}
|
|
105
|
+
await writeData(join(outputDirectory, '.appsemblerc.yaml'), outputAppsembleRc);
|
|
106
|
+
await writeData(join(outputDirectory, 'app-definition.yaml'), outputAppDefinition, {
|
|
107
|
+
sort: false,
|
|
108
|
+
});
|
|
109
|
+
logger.info(`Successfully created ${name} at ${outputDirectory}`);
|
|
74
110
|
}
|
|
75
111
|
//# sourceMappingURL=create.js.map
|
package/commands/app/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as create from './create.js';
|
|
2
2
|
import * as extractMessages from './extract-messages.js';
|
|
3
|
+
import * as publish from './publish.js';
|
|
3
4
|
import * as update from './update.js';
|
|
4
5
|
export { noop as handler } from '@appsemble/utils';
|
|
5
6
|
export const command = 'app';
|
|
6
7
|
export const description = 'Commands related to apps.';
|
|
7
8
|
export function builder(yargs) {
|
|
8
9
|
return yargs
|
|
10
|
+
.command(publish)
|
|
9
11
|
.command(create)
|
|
10
12
|
.command(extractMessages)
|
|
11
13
|
.command(update)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
3
|
+
import { type ReadStream } from 'node:fs';
|
|
4
|
+
import { type AppVisibility } from '@appsemble/types';
|
|
5
|
+
import { type Argv } from 'yargs';
|
|
6
|
+
import { type BaseArguments } from '../../types.js';
|
|
7
|
+
interface PublishAppArguments extends BaseArguments {
|
|
8
|
+
context: string;
|
|
9
|
+
icon: NodeJS.ReadStream | ReadStream;
|
|
10
|
+
iconBackground: string;
|
|
11
|
+
maskableIcon: NodeJS.ReadStream | ReadStream;
|
|
12
|
+
paths: string[];
|
|
13
|
+
organization: string;
|
|
14
|
+
template: boolean;
|
|
15
|
+
dryRun: boolean;
|
|
16
|
+
resources: boolean;
|
|
17
|
+
modifyContext: boolean;
|
|
18
|
+
visibility: AppVisibility;
|
|
19
|
+
sentryDsn: string;
|
|
20
|
+
sentryEnvironment: string;
|
|
21
|
+
googleAnalyticsId: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const command = "publish <paths...>";
|
|
24
|
+
export declare const description = "Publish a new App to a remote based on a specified YAML file or directory.";
|
|
25
|
+
export declare function builder(yargs: Argv): Argv<any>;
|
|
26
|
+
export declare function handler({ paths, ...args }: PublishAppArguments): Promise<void>;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { logger } from '@appsemble/node-utils';
|
|
2
|
+
import fg from 'fast-glob';
|
|
3
|
+
import normalizePath from 'normalize-path';
|
|
4
|
+
import { publishApp } from '../../lib/app.js';
|
|
5
|
+
import { coerceFile } from '../../lib/coercers.js';
|
|
6
|
+
export const command = 'publish <paths...>';
|
|
7
|
+
export const description = 'Publish a new App to a remote based on a specified YAML file or directory.';
|
|
8
|
+
export function builder(yargs) {
|
|
9
|
+
return yargs
|
|
10
|
+
.positional('paths', {
|
|
11
|
+
describe: 'The paths to the apps to publish.',
|
|
12
|
+
})
|
|
13
|
+
.option('context', {
|
|
14
|
+
describe: 'If specified, use the specified context from .appsemblerc.yaml',
|
|
15
|
+
})
|
|
16
|
+
.option('organization', {
|
|
17
|
+
describe: 'The organization ID the app should be published for.',
|
|
18
|
+
})
|
|
19
|
+
.option('icon', {
|
|
20
|
+
describe: 'The icon to upload. By default "icon.png" in the app directory is used.',
|
|
21
|
+
coerce: coerceFile,
|
|
22
|
+
})
|
|
23
|
+
.option('icon-background', {
|
|
24
|
+
describe: 'The background color to use for the icon in opaque contexts.',
|
|
25
|
+
default: '#ffffff',
|
|
26
|
+
})
|
|
27
|
+
.option('maskable-icon', {
|
|
28
|
+
describe: 'The maskable icon to upload. By default "maskable-icon.png" in the app directory is used.',
|
|
29
|
+
coerce: coerceFile,
|
|
30
|
+
})
|
|
31
|
+
.option('visibility', {
|
|
32
|
+
describe: 'Visibility of the app in the public app store.',
|
|
33
|
+
default: 'unlisted',
|
|
34
|
+
choices: ['public', 'unlisted', 'private'],
|
|
35
|
+
})
|
|
36
|
+
.option('template', {
|
|
37
|
+
describe: 'Whether the app should be marked as a template.',
|
|
38
|
+
type: 'boolean',
|
|
39
|
+
})
|
|
40
|
+
.option('dry-run', {
|
|
41
|
+
describe: 'Whether the API should be called to run without actually creating the app.',
|
|
42
|
+
type: 'boolean',
|
|
43
|
+
})
|
|
44
|
+
.option('resources', {
|
|
45
|
+
describe: 'Whether the resources from the `resources` directory should be created after publishing the app. The names of subdirectories are used as the name of the resource, otherwise the names of top level resource .json files are used instead.',
|
|
46
|
+
type: 'boolean',
|
|
47
|
+
})
|
|
48
|
+
.option('modify-context', {
|
|
49
|
+
describe: 'If the app context is specified, modify it for the current context to include the id of the published app.',
|
|
50
|
+
type: 'boolean',
|
|
51
|
+
})
|
|
52
|
+
.option('google-analytics-id', {
|
|
53
|
+
describe: 'The ID for Google Analytics for the app.',
|
|
54
|
+
})
|
|
55
|
+
.option('sentry-dsn', {
|
|
56
|
+
describe: 'The custom Sentry DSN for the app.',
|
|
57
|
+
})
|
|
58
|
+
.option('sentry-environment', {
|
|
59
|
+
describe: 'The environment for the custom Sentry DSN for the app.',
|
|
60
|
+
implies: ['sentry-dsn'],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export async function handler({ paths, ...args }) {
|
|
64
|
+
const normalizedPaths = paths.map((path) => normalizePath(path));
|
|
65
|
+
const directories = await fg(normalizedPaths, { absolute: true, onlyDirectories: true });
|
|
66
|
+
logger.info(`Publishing ${directories.length} apps`);
|
|
67
|
+
for (const dir of directories) {
|
|
68
|
+
logger.info('');
|
|
69
|
+
await publishApp({
|
|
70
|
+
...args,
|
|
71
|
+
path: dir,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=publish.js.map
|
package/commands/asset/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as publish from './publish.js';
|
|
2
2
|
export { noop as handler } from '@appsemble/utils';
|
|
3
3
|
export const command = 'asset';
|
|
4
4
|
export const description = 'Commands related to app assets.';
|
|
5
5
|
export function builder(yargs) {
|
|
6
|
-
return yargs.command(
|
|
6
|
+
return yargs.command(publish).demandCommand(1);
|
|
7
7
|
}
|
|
8
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Argv } from 'yargs';
|
|
2
2
|
import { type BaseArguments } from '../../types.js';
|
|
3
|
-
interface
|
|
3
|
+
interface PublishAssetArguments extends BaseArguments {
|
|
4
4
|
name: string;
|
|
5
5
|
useFileName: boolean;
|
|
6
6
|
paths: string[];
|
|
@@ -8,8 +8,8 @@ interface CreateAssetArguments extends BaseArguments {
|
|
|
8
8
|
context: string;
|
|
9
9
|
app: string;
|
|
10
10
|
}
|
|
11
|
-
export declare const command = "
|
|
12
|
-
export declare const description = "
|
|
11
|
+
export declare const command = "publish <paths...>";
|
|
12
|
+
export declare const description = "Publish assets for an existing app.";
|
|
13
13
|
export declare function builder(yargs: Argv): Argv<any>;
|
|
14
|
-
export declare function handler({ app, appId, clientCredentials, context, name, paths, remote, useFileName, }:
|
|
14
|
+
export declare function handler({ app, appId, clientCredentials, context, name, paths, remote, useFileName, }: PublishAssetArguments): Promise<void>;
|
|
15
15
|
export {};
|
|
@@ -3,14 +3,14 @@ import { AppsembleError, logger } from '@appsemble/node-utils';
|
|
|
3
3
|
import fg from 'fast-glob';
|
|
4
4
|
import normalizePath from 'normalize-path';
|
|
5
5
|
import { resolveAppIdAndRemote } from '../../lib/app.js';
|
|
6
|
-
import {
|
|
6
|
+
import { publishAsset } from '../../lib/asset.js';
|
|
7
7
|
import { authenticate } from '../../lib/authentication.js';
|
|
8
|
-
export const command = '
|
|
9
|
-
export const description = '
|
|
8
|
+
export const command = 'publish <paths...>';
|
|
9
|
+
export const description = 'Publish assets for an existing app.';
|
|
10
10
|
export function builder(yargs) {
|
|
11
11
|
return yargs
|
|
12
12
|
.positional('paths', {
|
|
13
|
-
describe: 'The path to the resources to
|
|
13
|
+
describe: 'The path to the resources to publish',
|
|
14
14
|
normalize: true,
|
|
15
15
|
demandOption: true,
|
|
16
16
|
})
|
|
@@ -23,7 +23,7 @@ export function builder(yargs) {
|
|
|
23
23
|
default: true,
|
|
24
24
|
})
|
|
25
25
|
.option('app-id', {
|
|
26
|
-
describe: 'The ID of the app to
|
|
26
|
+
describe: 'The ID of the app to publish the resources for.',
|
|
27
27
|
type: 'number',
|
|
28
28
|
})
|
|
29
29
|
.option('app', {
|
|
@@ -41,10 +41,10 @@ export async function handler({ app, appId, clientCredentials, context, name, pa
|
|
|
41
41
|
if (name && files.length > 1) {
|
|
42
42
|
throw new AppsembleError('--name was specified but multiple files were found.');
|
|
43
43
|
}
|
|
44
|
-
logger.info(`
|
|
44
|
+
logger.info(`Publishing ${files.length} asset(s)`);
|
|
45
45
|
for (const path of files) {
|
|
46
46
|
logger.info('');
|
|
47
|
-
await
|
|
47
|
+
await publishAsset({
|
|
48
48
|
name: name || (useFileName ? parse(path).name : null),
|
|
49
49
|
appId: resolvedAppId,
|
|
50
50
|
path,
|
|
@@ -52,4 +52,4 @@ export async function handler({ app, appId, clientCredentials, context, name, pa
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
//# sourceMappingURL=
|
|
55
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Argv } from 'yargs';
|
|
2
|
+
export declare const command = "create";
|
|
3
|
+
export declare const description = "Bootstrap a new Appsemble block.";
|
|
4
|
+
interface BlockArgs {
|
|
5
|
+
organization?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
path?: string;
|
|
8
|
+
template?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function builder(yargs: Argv): Promise<Argv<any>>;
|
|
11
|
+
export declare function handler(args: BlockArgs): Promise<void>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { cp, readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { logger, readData, version, writeData } from '@appsemble/node-utils';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
const templateDir = new URL('../../templates/blocks/', import.meta.url);
|
|
6
|
+
export const command = 'create';
|
|
7
|
+
export const description = 'Bootstrap a new Appsemble block.';
|
|
8
|
+
export async function builder(yargs) {
|
|
9
|
+
const choices = await readdir(templateDir);
|
|
10
|
+
return yargs
|
|
11
|
+
.option('organization', {
|
|
12
|
+
describe: 'The ID of the organization block should be created for.',
|
|
13
|
+
})
|
|
14
|
+
.option('name', {
|
|
15
|
+
describe: 'The name of the block',
|
|
16
|
+
})
|
|
17
|
+
.option('path', {
|
|
18
|
+
describe: 'Path of the folder where you want to put your block.',
|
|
19
|
+
})
|
|
20
|
+
.option('template', {
|
|
21
|
+
describe: 'The template to use.',
|
|
22
|
+
choices,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export async function handler(args) {
|
|
26
|
+
const choices = await readdir(templateDir);
|
|
27
|
+
const answers = await inquirer.prompt([
|
|
28
|
+
!args.organization && {
|
|
29
|
+
name: 'organization',
|
|
30
|
+
message: 'For which organization is the block? (default "appsemble")',
|
|
31
|
+
},
|
|
32
|
+
!args.name && { name: 'name', message: 'What should be the name of the block?' },
|
|
33
|
+
!args.path && {
|
|
34
|
+
name: 'path',
|
|
35
|
+
message: 'Please enter the path for where you want the block folder to go (default "blocks").',
|
|
36
|
+
},
|
|
37
|
+
!args.template && {
|
|
38
|
+
name: 'template',
|
|
39
|
+
type: 'list',
|
|
40
|
+
choices,
|
|
41
|
+
message: 'What kind of block project should be bootstrapped?',
|
|
42
|
+
},
|
|
43
|
+
].filter(Boolean));
|
|
44
|
+
const organization = answers.organization || args.organization || 'appsemble';
|
|
45
|
+
const name = answers.name || args.name;
|
|
46
|
+
const template = answers.template || args.template;
|
|
47
|
+
const path = answers.path || args.path || join(process.cwd(), 'blocks');
|
|
48
|
+
const outputPath = join(path, name);
|
|
49
|
+
const inputPath = new URL(`${template}/`, templateDir);
|
|
50
|
+
const pkgPath = new URL('package.json', inputPath);
|
|
51
|
+
const [inputPkg] = await readData(pkgPath);
|
|
52
|
+
const outputPkg = {
|
|
53
|
+
name: `@${organization}/${name}`,
|
|
54
|
+
version,
|
|
55
|
+
...inputPkg,
|
|
56
|
+
};
|
|
57
|
+
await cp(inputPath, outputPath, {
|
|
58
|
+
errorOnExist: true,
|
|
59
|
+
filter: (src) => !src.endsWith('package.json'),
|
|
60
|
+
force: false,
|
|
61
|
+
recursive: true,
|
|
62
|
+
});
|
|
63
|
+
await writeData(join(outputPath, 'package.json'), outputPkg);
|
|
64
|
+
logger.info(`Successfully created @${organization}/${name}/${version} at ${outputPath}`);
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Argv } from 'yargs';
|
|
2
|
+
import { type BaseArguments } from '../../types.js';
|
|
3
|
+
interface DeleteBlockArguments extends BaseArguments {
|
|
4
|
+
block: string;
|
|
5
|
+
organization: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const command = "delete <block>";
|
|
8
|
+
export declare const description = "Delete a specific block version. Using this outside local development is discouraged.";
|
|
9
|
+
export declare function builder(yargs: Argv): Argv<any>;
|
|
10
|
+
export declare function handler({ block, clientCredentials, organization, remote, }: DeleteBlockArguments): Promise<void>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { logger } from '@appsemble/node-utils';
|
|
2
|
+
import { authenticate } from '../../lib/authentication.js';
|
|
3
|
+
import { deleteBlock } from '../../lib/block.js';
|
|
4
|
+
export const command = 'delete <block>';
|
|
5
|
+
export const description = 'Delete a specific block version. Using this outside local development is discouraged.';
|
|
6
|
+
export function builder(yargs) {
|
|
7
|
+
return yargs
|
|
8
|
+
.positional('block', {
|
|
9
|
+
describe: 'Blockname and version to be deleted',
|
|
10
|
+
})
|
|
11
|
+
.option('organization', {
|
|
12
|
+
describe: 'Organization to which the block belongs.',
|
|
13
|
+
default: 'appsemble',
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export async function handler({ block, clientCredentials, organization, remote, }) {
|
|
17
|
+
await authenticate(remote, 'blocks:delete', clientCredentials);
|
|
18
|
+
const [blockName, blockVersion] = block.split(':');
|
|
19
|
+
logger.info(`Deleting Block ${block}`);
|
|
20
|
+
await deleteBlock({ organization, blockName, blockVersion, remote });
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=delete.js.map
|