@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 CHANGED
@@ -1,9 +1,9 @@
1
- # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.24.10/config/assets/logo.svg) Appsemble CLI
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.24.13/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.24.10/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.24.10)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.24.13/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.24.13)
7
7
  [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](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.10/LICENSE.md) ©
307
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.24.13/LICENSE.md) ©
308
308
  [Appsemble](https://appsemble.com)
@@ -41,7 +41,7 @@ export async function handler({ app, appId, clientCredentials, context, paths, r
41
41
  for (const path of files) {
42
42
  logger.info('');
43
43
  await publishResource({
44
- resourceName,
44
+ type: resourceName,
45
45
  appId: resolvedAppId,
46
46
  path,
47
47
  remote: resolvedRemote,
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 { publishResource } from './resource.js';
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
- await publishResource({
563
+ resourcesToPublish.push({
545
564
  appId: data.id,
546
565
  path: join(resourcePath, resource.name),
547
- remote,
548
- resourceName: name,
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
- await publishResource({
575
+ resourcesToPublish.push({
557
576
  appId: data.id,
558
577
  path: join(resourcePath, resource.name, subResource.name),
559
- remote,
560
- resourceName: resource.name,
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
- resourceName: string;
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, resourceName, }: PublishResourceParams): Promise<void>;
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, resourceName, }) {
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
- const { data } = await axios.post(`/api/apps/${appId}/resources/${resourceName}`, resources, {
19
- baseURL: remote,
20
- headers: { 'content-type': csv ? 'text/csv' : 'application/json' },
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/${resourceName}/`, remote);
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.10",
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.10",
46
- "@appsemble/types": "0.24.10",
47
- "@appsemble/utils": "0.24.10",
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.10",
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.10
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.10
20
+ version: 0.24.13
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.24.10",
5
+ "@appsemble/sdk": "0.24.13",
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.24.10",
6
- "@appsemble/sdk": "0.24.10",
5
+ "@appsemble/preact": "0.24.13",
6
+ "@appsemble/sdk": "0.24.13",
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.24.10"
5
+ "@appsemble/sdk": "0.24.13"
6
6
  }
7
7
  }