@appsemble/cli 0.24.10 → 0.24.13
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/resource/publish.js +1 -1
- package/lib/app.js +31 -7
- package/lib/resource.d.ts +32 -2
- package/lib/resource.js +58 -6
- package/package.json +5 -5
- 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.24.13)
|
|
7
7
|
[](https://prettier.io)
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
@@ -304,5 +304,5 @@ appsemble run-cronjobs --interval 30
|
|
|
304
304
|
|
|
305
305
|
## License
|
|
306
306
|
|
|
307
|
-
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.24.
|
|
307
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.24.13/LICENSE.md) ©
|
|
308
308
|
[Appsemble](https://appsemble.com)
|
package/lib/app.js
CHANGED
|
@@ -8,6 +8,7 @@ import axios from 'axios';
|
|
|
8
8
|
import fg from 'fast-glob';
|
|
9
9
|
import FormData from 'form-data';
|
|
10
10
|
import normalizePath from 'normalize-path';
|
|
11
|
+
import { parse as parseYaml } from 'yaml';
|
|
11
12
|
import { publishAsset } from './asset.js';
|
|
12
13
|
import { traverseBlockThemes } from './block.js';
|
|
13
14
|
import { coerceRemote } from './coercers.js';
|
|
@@ -15,7 +16,7 @@ import { getProjectBuildConfig } from './config.js';
|
|
|
15
16
|
import { printAxiosError } from './output.js';
|
|
16
17
|
import { processCss } from './processCss.js';
|
|
17
18
|
import { buildProject, makeProjectPayload } from './project.js';
|
|
18
|
-
import {
|
|
19
|
+
import { publishResourcesRecursively } from './resource.js';
|
|
19
20
|
/**
|
|
20
21
|
* Traverses an app directory and appends the files it finds to the given FormData object.
|
|
21
22
|
*
|
|
@@ -352,6 +353,7 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
|
|
|
352
353
|
const sentryDsn = (_l = appsembleContext.sentryDsn) !== null && _l !== void 0 ? _l : options.sentryDsn;
|
|
353
354
|
const sentryEnvironment = (_m = appsembleContext.sentryEnvironment) !== null && _m !== void 0 ? _m : options.sentryEnvironment;
|
|
354
355
|
const googleAnalyticsId = (_o = appsembleContext.googleAnalyticsId) !== null && _o !== void 0 ? _o : options.googleAnalyticsId;
|
|
356
|
+
const { appLock } = appsembleContext;
|
|
355
357
|
logger.info(`App id: ${id}`);
|
|
356
358
|
logger.verbose(`App remote: ${remote}`);
|
|
357
359
|
logger.verbose(`App is template: ${inspect(template, { colors: true })}`);
|
|
@@ -388,6 +390,18 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
|
|
|
388
390
|
formData.append('googleAnalyticsID', googleAnalyticsId);
|
|
389
391
|
}
|
|
390
392
|
await authenticate(remote, 'apps:write', clientCredentials);
|
|
393
|
+
if (appLock) {
|
|
394
|
+
logger.info(`Setting AppLock to ${appLock}`);
|
|
395
|
+
try {
|
|
396
|
+
await axios.post(`/api/apps/${id}/lock`, {
|
|
397
|
+
locked: appLock,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
logger.error(error);
|
|
402
|
+
process.exit(1);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
391
405
|
let data;
|
|
392
406
|
try {
|
|
393
407
|
data = await axios
|
|
@@ -448,6 +462,7 @@ export async function publishApp({ assets, assetsClonable, clientCredentials, co
|
|
|
448
462
|
const sentryDsn = (_l = appsembleContext.sentryDsn) !== null && _l !== void 0 ? _l : options.sentryDsn;
|
|
449
463
|
const sentryEnvironment = (_m = appsembleContext.sentryEnvironment) !== null && _m !== void 0 ? _m : options.sentryEnvironment;
|
|
450
464
|
const googleAnalyticsId = (_o = appsembleContext.googleAnalyticsId) !== null && _o !== void 0 ? _o : options.googleAnalyticsId;
|
|
465
|
+
const appLock = appsembleContext.appLock || 'unlocked';
|
|
451
466
|
logger.verbose(`App remote: ${remote}`);
|
|
452
467
|
logger.verbose(`App organization: ${organizationId}`);
|
|
453
468
|
logger.verbose(`App is template: ${inspect(template, { colors: true })}`);
|
|
@@ -461,6 +476,7 @@ export async function publishApp({ assets, assetsClonable, clientCredentials, co
|
|
|
461
476
|
formData.append('demoMode', String(demoMode));
|
|
462
477
|
formData.append('visibility', visibility);
|
|
463
478
|
formData.append('iconBackground', iconBackground);
|
|
479
|
+
formData.append('locked', appLock);
|
|
464
480
|
if (icon) {
|
|
465
481
|
const realIcon = typeof icon === 'string' ? createReadStream(icon) : icon;
|
|
466
482
|
logger.info(`Using icon from ${(_p = realIcon.path) !== null && _p !== void 0 ? _p : 'stdin'}`);
|
|
@@ -535,17 +551,20 @@ export async function publishApp({ assets, assetsClonable, clientCredentials, co
|
|
|
535
551
|
}
|
|
536
552
|
}
|
|
537
553
|
if (resources && existsSync(join(path, 'resources'))) {
|
|
554
|
+
const appDefinition = parseYaml(yaml, { maxAliasCount: 10000 });
|
|
538
555
|
const resourcePath = join(path, 'resources');
|
|
539
556
|
try {
|
|
540
557
|
const resourceFiles = await readdir(resourcePath, { withFileTypes: true });
|
|
558
|
+
const resourcesToPublish = [];
|
|
559
|
+
const publishedResourcesIds = {};
|
|
541
560
|
for (const resource of resourceFiles) {
|
|
542
561
|
if (resource.isFile()) {
|
|
543
562
|
const { name } = parse(resource.name);
|
|
544
|
-
|
|
563
|
+
resourcesToPublish.push({
|
|
545
564
|
appId: data.id,
|
|
546
565
|
path: join(resourcePath, resource.name),
|
|
547
|
-
|
|
548
|
-
|
|
566
|
+
definition: appDefinition.resources[name],
|
|
567
|
+
type: name,
|
|
549
568
|
});
|
|
550
569
|
}
|
|
551
570
|
else if (resource.isDirectory()) {
|
|
@@ -553,15 +572,20 @@ export async function publishApp({ assets, assetsClonable, clientCredentials, co
|
|
|
553
572
|
withFileTypes: true,
|
|
554
573
|
});
|
|
555
574
|
for (const subResource of subDirectoryResources.filter((s) => s.isFile())) {
|
|
556
|
-
|
|
575
|
+
resourcesToPublish.push({
|
|
557
576
|
appId: data.id,
|
|
558
577
|
path: join(resourcePath, resource.name, subResource.name),
|
|
559
|
-
|
|
560
|
-
|
|
578
|
+
definition: appDefinition.resources[resource.name],
|
|
579
|
+
type: resource.name,
|
|
561
580
|
});
|
|
562
581
|
}
|
|
563
582
|
}
|
|
564
583
|
}
|
|
584
|
+
await publishResourcesRecursively({
|
|
585
|
+
remote,
|
|
586
|
+
resourcesToPublish,
|
|
587
|
+
publishedResourcesIds,
|
|
588
|
+
});
|
|
565
589
|
}
|
|
566
590
|
catch (error) {
|
|
567
591
|
logger.error('Something went wrong when creating resources:');
|
package/lib/resource.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ResourceDefinition } from '@appsemble/types';
|
|
1
2
|
interface UpdateResourceParams {
|
|
2
3
|
/**
|
|
3
4
|
* The name of the resource that a new entry is being created of.
|
|
@@ -20,7 +21,7 @@ interface PublishResourceParams {
|
|
|
20
21
|
/**
|
|
21
22
|
* The name of the resource that a new entry is being created of.
|
|
22
23
|
*/
|
|
23
|
-
|
|
24
|
+
type: string;
|
|
24
25
|
/**
|
|
25
26
|
* The path in which the resource JSON is located.
|
|
26
27
|
*/
|
|
@@ -33,7 +34,36 @@ interface PublishResourceParams {
|
|
|
33
34
|
* The remote server to publish the resource on.
|
|
34
35
|
*/
|
|
35
36
|
remote: string;
|
|
37
|
+
/**
|
|
38
|
+
* The definition of the resource.
|
|
39
|
+
*/
|
|
40
|
+
definition?: ResourceDefinition;
|
|
41
|
+
/**
|
|
42
|
+
* An array of property name to value maps of referenced resources.
|
|
43
|
+
*/
|
|
44
|
+
publishedResourcesIds?: Record<string, number[]>;
|
|
45
|
+
}
|
|
46
|
+
export interface ResourceToPublish {
|
|
47
|
+
appId: number;
|
|
48
|
+
path: string;
|
|
49
|
+
type: string;
|
|
50
|
+
definition: ResourceDefinition;
|
|
51
|
+
}
|
|
52
|
+
interface PublishResourcesRecursivelyParams {
|
|
53
|
+
/**
|
|
54
|
+
* The remote server to publish the resource on.
|
|
55
|
+
*/
|
|
56
|
+
remote: string;
|
|
57
|
+
/**
|
|
58
|
+
* All resources that need to be published.
|
|
59
|
+
*/
|
|
60
|
+
resourcesToPublish: ResourceToPublish[];
|
|
61
|
+
/**
|
|
62
|
+
* Already published resources.
|
|
63
|
+
*/
|
|
64
|
+
publishedResourcesIds: Record<string, number[]>;
|
|
36
65
|
}
|
|
37
|
-
export declare function publishResource({ appId, path, remote,
|
|
66
|
+
export declare function publishResource({ appId, definition, path, publishedResourcesIds, remote, type, }: PublishResourceParams): Promise<number[]>;
|
|
67
|
+
export declare function publishResourcesRecursively({ publishedResourcesIds, remote, resourcesToPublish, }: PublishResourcesRecursivelyParams): Promise<Record<string, number[]>>;
|
|
38
68
|
export declare function updateResource({ appId, path, remote, resourceName, }: UpdateResourceParams): Promise<void>;
|
|
39
69
|
export {};
|
package/lib/resource.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { AppsembleError, logger, readData } from '@appsemble/node-utils';
|
|
3
3
|
import axios from 'axios';
|
|
4
|
-
export async function publishResource({ appId, path, remote,
|
|
4
|
+
export async function publishResource({ appId, definition, path, publishedResourcesIds = {}, remote, type, }) {
|
|
5
5
|
const csv = path.endsWith('.csv');
|
|
6
6
|
let resources;
|
|
7
7
|
if (csv) {
|
|
@@ -15,15 +15,67 @@ export async function publishResource({ appId, path, remote, resourceName, }) {
|
|
|
15
15
|
resources = [].concat(file);
|
|
16
16
|
}
|
|
17
17
|
logger.info(`Publishing resource(s) from ${path}`);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
let data;
|
|
19
|
+
if (csv) {
|
|
20
|
+
const response = await axios.post(`/api/apps/${appId}/resources/${type}`, resources, {
|
|
21
|
+
baseURL: remote,
|
|
22
|
+
headers: { 'content-type': 'text/csv' },
|
|
23
|
+
});
|
|
24
|
+
data = response.data;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const response = await axios.post(`/api/apps/${appId}/resources/${type}`, resources.map((resource) => {
|
|
28
|
+
var _a, _b, _c;
|
|
29
|
+
const resourceWithReferences = { ...resource };
|
|
30
|
+
for (const [referencedProperty, resourceReference] of Object.entries((_a = definition === null || definition === void 0 ? void 0 : definition.references) !== null && _a !== void 0 ? _a : {})) {
|
|
31
|
+
resourceWithReferences[referencedProperty] =
|
|
32
|
+
(_b = publishedResourcesIds[resourceReference.resource]) === null || _b === void 0 ? void 0 : _b[Number((_c = resource[`$${resourceReference.resource}`]) !== null && _c !== void 0 ? _c : -1)];
|
|
33
|
+
}
|
|
34
|
+
return resourceWithReferences;
|
|
35
|
+
}), {
|
|
36
|
+
baseURL: remote,
|
|
37
|
+
headers: { 'content-type': 'application/json' },
|
|
38
|
+
});
|
|
39
|
+
data = response.data;
|
|
40
|
+
}
|
|
22
41
|
const ids = [].concat(data).map((d) => d.id);
|
|
23
|
-
const url = new URL(`/apps/${appId}/resources/${
|
|
42
|
+
const url = new URL(`/apps/${appId}/resources/${type}/`, remote);
|
|
24
43
|
logger.info(`Successfully published ${ids.length} resource${resources.length === 1 ? '' : 's'} at: \n${ids
|
|
25
44
|
.map((id) => `${url}${id}`)
|
|
26
45
|
.join('\n')}`);
|
|
46
|
+
return ids;
|
|
47
|
+
}
|
|
48
|
+
export async function publishResourcesRecursively({ publishedResourcesIds, remote, resourcesToPublish, }) {
|
|
49
|
+
let updatedPublishedResourcesIds = { ...publishedResourcesIds };
|
|
50
|
+
for (const resourceToPublish of resourcesToPublish) {
|
|
51
|
+
const resourceReferences = resourceToPublish.definition.references;
|
|
52
|
+
if (resourceReferences) {
|
|
53
|
+
for (const resourceReference of Object.values(resourceReferences)) {
|
|
54
|
+
const referencedResourceType = resourceReference.resource;
|
|
55
|
+
const referencedResourcesToPublish = resourcesToPublish.filter((referencedResourceToPublish) => referencedResourceToPublish.type === referencedResourceType);
|
|
56
|
+
if (referencedResourcesToPublish.length &&
|
|
57
|
+
!updatedPublishedResourcesIds[referencedResourceType]) {
|
|
58
|
+
const referencedPublishedResourcesIds = await publishResourcesRecursively({
|
|
59
|
+
remote,
|
|
60
|
+
resourcesToPublish: referencedResourcesToPublish,
|
|
61
|
+
publishedResourcesIds: updatedPublishedResourcesIds,
|
|
62
|
+
});
|
|
63
|
+
updatedPublishedResourcesIds = {
|
|
64
|
+
...updatedPublishedResourcesIds,
|
|
65
|
+
...referencedPublishedResourcesIds,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!updatedPublishedResourcesIds[resourceToPublish.type]) {
|
|
71
|
+
updatedPublishedResourcesIds[resourceToPublish.type] = await publishResource({
|
|
72
|
+
...resourceToPublish,
|
|
73
|
+
publishedResourcesIds: updatedPublishedResourcesIds,
|
|
74
|
+
remote,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return updatedPublishedResourcesIds;
|
|
27
79
|
}
|
|
28
80
|
export async function updateResource({ appId, path, remote, resourceName, }) {
|
|
29
81
|
const [file] = await readData(path);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/cli",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.13",
|
|
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.24.
|
|
46
|
-
"@appsemble/types": "0.24.
|
|
47
|
-
"@appsemble/utils": "0.24.
|
|
45
|
+
"@appsemble/node-utils": "0.24.13",
|
|
46
|
+
"@appsemble/types": "0.24.13",
|
|
47
|
+
"@appsemble/utils": "0.24.13",
|
|
48
48
|
"@fortawesome/fontawesome-common-types": "^6.0.0",
|
|
49
49
|
"@koa/cors": "^4.0.0",
|
|
50
50
|
"@odata/parser": "^0.2.0",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"yargs": "^17.0.0"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@appsemble/types": "0.24.
|
|
89
|
+
"@appsemble/types": "0.24.13",
|
|
90
90
|
"@types/concat-stream": "^2.0.0",
|
|
91
91
|
"@types/inquirer": "^9.0.0",
|
|
92
92
|
"@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.24.
|
|
9
|
+
version: 0.24.13
|
|
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.24.
|
|
20
|
+
version: 0.24.13
|
|
21
21
|
parameters:
|
|
22
22
|
icon: arrow-left
|
|
23
23
|
actions:
|