@appsemble/cli 0.38.0 → 0.38.2-test.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 CHANGED
@@ -1,9 +1,9 @@
1
- # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.38.0/config/assets/logo.svg) Appsemble CLI
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.38.2-test.0/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.38.0/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.38.0)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.38.2-test.0/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.38.2-test.0)
7
7
  [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://prettier.io)
8
8
 
9
9
  ## Table of Contents
@@ -342,5 +342,5 @@ appsemble run-cronjobs --interval 30
342
342
 
343
343
  ## License
344
344
 
345
- [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.38.0/LICENSE.md) ©
345
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.38.2-test.0/LICENSE.md) ©
346
346
  [Appsemble](https://appsemble.com)
package/lib/app.js CHANGED
@@ -1,13 +1,15 @@
1
- import { cpSync, createReadStream, createWriteStream, existsSync } from 'node:fs';
1
+ import { createReadStream, createWriteStream, existsSync } from 'node:fs';
2
2
  import { mkdir, readdir, readFile, 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 { normalizeBlockName } from '@appsemble/lang-sdk';
6
- import { applyAppVariant, AppsembleError, authenticate, logger, opendirSafe, readData, writeData, } from '@appsemble/node-utils';
6
+ import { applyAppVariant, AppsembleError, authenticate, logger, opendirSafe, preProcessCSV, readData, writeData, } from '@appsemble/node-utils';
7
7
  import { extractAppMessages, has } from '@appsemble/utils';
8
8
  import axios from 'axios';
9
+ import csv from 'csvtojson';
9
10
  import fg from 'fast-glob';
10
11
  import FormData from 'form-data';
12
+ import { Validator } from 'jsonschema';
11
13
  import normalizePath from 'normalize-path';
12
14
  import { publishAsset } from './asset.js';
13
15
  import { traverseBlockThemes } from './block.js';
@@ -16,7 +18,6 @@ import { getProjectBuildConfig } from './config.js';
16
18
  import { printAxiosError } from './output.js';
17
19
  import { processCss } from './processCss.js';
18
20
  import { buildProject, makeProjectPayload } from './project.js';
19
- import { publishResourcesRecursively } from './resource.js';
20
21
  /**
21
22
  * Traverses an app directory and appends the files it finds to the given FormData object.
22
23
  *
@@ -105,12 +106,11 @@ export async function traverseAppDirectory(path, context, formData) {
105
106
  const language = supportedLanguages.has(screenshotDirectoryName)
106
107
  ? screenshotDirectoryName
107
108
  : 'unspecified';
108
- const tmpFilePath = join(screenshotDirectoryPath, `${language}-${screenshotName}`);
109
- cpSync(screenshotPath, tmpFilePath);
110
- logger.info(`Adding screenshot ${tmpFilePath} 🖼️`);
111
- formData.append('screenshots', createReadStream(tmpFilePath));
109
+ logger.info(`Adding screenshot ${screenshotPath} 🖼️`);
110
+ formData.append('screenshots', createReadStream(screenshotPath), {
111
+ filename: `${language}-${screenshotName}`,
112
+ });
112
113
  gatheredData.screenshotUrls.push(basename(screenshotPath));
113
- rm(tmpFilePath);
114
114
  }
115
115
  }, { allowMissing: true, recursive: true });
116
116
  case 'theme':
@@ -274,55 +274,53 @@ export async function deleteApp({ clientCredentials, id, remote }) {
274
274
  export async function publishSeedResources(path, app, remote) {
275
275
  const resourcesPath = join(path, 'resources');
276
276
  logger.info(`Publishing seed resources from ${resourcesPath}`);
277
- if (existsSync(resourcesPath)) {
278
- logger.info(`Deleting existing seed resources from app ${app.id}`);
279
- try {
280
- await axios.delete(`/api/apps/${app.id}/resources`, { baseURL: remote });
281
- const resourceFiles = await readdir(resourcesPath, { withFileTypes: true });
282
- const resourcesToPublish = [];
283
- const publishedResourcesIds = {};
284
- for (const resource of resourceFiles) {
285
- if (resource.isFile()) {
286
- const { name } = parse(resource.name);
287
- resourcesToPublish.push({
288
- // @ts-expect-error 2322 null is not assignable to type (strictNullChecks)
289
- appId: app.id,
290
- path: join(resourcesPath, resource.name),
291
- // @ts-expect-error 2322 null is not assignable to type (strictNullChecks)
292
- definition: app.definition.resources?.[name],
293
- type: name,
294
- });
295
- }
296
- else if (resource.isDirectory()) {
297
- const subDirectoryResources = await readdir(join(resourcesPath, resource.name), {
298
- withFileTypes: true,
299
- });
300
- for (const subResource of subDirectoryResources.filter((s) => s.isFile())) {
301
- resourcesToPublish.push({
302
- // @ts-expect-error 2322 null is not assignable to type (strictNullChecks)
303
- appId: app.id,
304
- path: join(resourcesPath, resource.name, subResource.name),
305
- // @ts-expect-error 2322 null is not assignable to type (strictNullChecks)
306
- definition: app.definition.resources?.[resource.name],
307
- type: resource.name,
308
- });
309
- }
310
- }
311
- }
312
- await publishResourcesRecursively({
313
- seed: true,
314
- remote,
315
- resourcesToPublish,
316
- publishedResourcesIds,
317
- });
277
+ if (!existsSync(resourcesPath)) {
278
+ logger.warn(`Missing resources directory in ${path}. Skipping...`);
279
+ return;
280
+ }
281
+ const batch = {};
282
+ const resourceFiles = await readdir(resourcesPath, { withFileTypes: true });
283
+ for (const resource of resourceFiles) {
284
+ const type = resource.isDirectory() ? resource.name : parse(resource.name).name;
285
+ const definition = app.definition.resources?.[type];
286
+ if (!definition) {
287
+ throw new AppsembleError(`Unknown resource type: ${type}`);
318
288
  }
319
- catch (error) {
320
- logger.error('Something went wrong when publishing seed resources:');
321
- logger.error(error);
289
+ const paths = resource.isDirectory()
290
+ ? (await readdir(join(resourcesPath, resource.name), { withFileTypes: true }))
291
+ .filter((entry) => entry.isFile())
292
+ .map((entry) => join(resourcesPath, resource.name, entry.name))
293
+ : [join(resourcesPath, resource.name)];
294
+ batch[type] ?? (batch[type] = []);
295
+ for (const resourcePath of paths) {
296
+ const [file] = resourcePath.endsWith('.csv')
297
+ ? [await csv({ checkType: false }).fromFile(resourcePath)]
298
+ : await readData(resourcePath);
299
+ const resources = Array.isArray(file) ? file : [file];
300
+ if (resources.some((value) => !value || typeof value !== 'object' || Array.isArray(value))) {
301
+ throw new AppsembleError(`File at ${resourcePath} does not contain an object or array of objects`);
302
+ }
303
+ if (resourcePath.endsWith('.csv')) {
304
+ new Validator().validate(resources, {
305
+ type: 'array',
306
+ items: {
307
+ ...definition.schema,
308
+ properties: {
309
+ ...definition.schema.properties,
310
+ ...Object.fromEntries(Object.values(definition.references ?? {}).map(({ resource: referencedType }) => [
311
+ `$${referencedType}`,
312
+ { type: 'integer' },
313
+ ])),
314
+ },
315
+ },
316
+ }, { preValidateProperty: preProcessCSV });
317
+ }
318
+ batch[type].push(...resources);
322
319
  }
323
320
  }
324
- else {
325
- logger.warn(`Missing resources directory in ${path}. Skipping...`);
321
+ const { data } = await axios.put(`/api/apps/${app.id}/resources`, batch, { baseURL: remote });
322
+ for (const [type, ids] of Object.entries(data)) {
323
+ logger.info(`Successfully published ${ids.length} ${type} seed resource(s)`);
326
324
  }
327
325
  }
328
326
  function normalizeSeedAppMemberRoles(roles, role) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appsemble/cli",
3
- "version": "0.38.0",
3
+ "version": "0.38.2-test.0",
4
4
  "description": "The CLI for developing with Appsemble apps and blocks",
5
5
  "keywords": [
6
6
  "app",
@@ -44,10 +44,10 @@
44
44
  "test": "vitest"
45
45
  },
46
46
  "dependencies": {
47
- "@appsemble/node-utils": "0.38.0",
48
- "@appsemble/types": "0.38.0",
49
- "@appsemble/lang-sdk": "0.38.0",
50
- "@appsemble/utils": "0.38.0",
47
+ "@appsemble/node-utils": "0.38.2-test.0",
48
+ "@appsemble/types": "0.38.2-test.0",
49
+ "@appsemble/lang-sdk": "0.38.2-test.0",
50
+ "@appsemble/utils": "0.38.2-test.0",
51
51
  "@fortawesome/fontawesome-common-types": "^6.0.0",
52
52
  "@inquirer/prompts": "^8.0.0",
53
53
  "@koa/cors": "^5.0.0",
@@ -81,7 +81,7 @@
81
81
  "prettier": "^3.0.0",
82
82
  "raw-body": "^2.0.0",
83
83
  "read-package-up": "^11.0.0",
84
- "sharp": "0.35.3",
84
+ "sharp": "0.35.4",
85
85
  "ts-json-schema-generator": "^1.0.0",
86
86
  "type-fest": "^4.0.0",
87
87
  "url": "0.11.4",
@@ -90,8 +90,8 @@
90
90
  "yargs": "^17.0.0"
91
91
  },
92
92
  "devDependencies": {
93
- "@appsemble/types": "0.38.0",
94
- "@appsemble/server": "0.38.0",
93
+ "@appsemble/types": "0.38.2-test.0",
94
+ "@appsemble/server": "0.38.2-test.0",
95
95
  "@types/concat-stream": "2.0.3",
96
96
  "@types/koa__cors": "5.0.1",
97
97
  "@types/koa-compress": "4.0.7",
@@ -100,7 +100,7 @@
100
100
  "@types/postcss-import": "14.0.3",
101
101
  "@types/postcss-url": "10.0.4",
102
102
  "axios-test-instance": "8.0.0",
103
- "bcrypt": "5.1.1",
103
+ "bcrypt": "6.0.0",
104
104
  "big-integer": "1.6.52",
105
105
  "concat-stream": "2.0.0",
106
106
  "default-browser": "5.5.1",
@@ -6,7 +6,7 @@ pages:
6
6
  - name: Example Page A
7
7
  blocks:
8
8
  - type: action-button
9
- version: 0.38.0
9
+ version: 0.38.2-test.0
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.38.0
20
+ version: 0.38.2-test.0
21
21
  parameters:
22
22
  icon: arrow-left
23
23
  actions:
@@ -5,7 +5,7 @@
5
5
  "*.css"
6
6
  ],
7
7
  "dependencies": {
8
- "@appsemble/sdk": "0.38.0",
8
+ "@appsemble/sdk": "0.38.2-test.0",
9
9
  "mini-jsx": "^4.0.0"
10
10
  }
11
11
  }
@@ -5,8 +5,8 @@
5
5
  "*.css"
6
6
  ],
7
7
  "dependencies": {
8
- "@appsemble/preact": "0.38.0",
9
- "@appsemble/sdk": "0.38.0",
8
+ "@appsemble/preact": "0.38.2-test.0",
9
+ "@appsemble/sdk": "0.38.2-test.0",
10
10
  "preact": "^10.0.0"
11
11
  }
12
12
  }
@@ -5,6 +5,6 @@
5
5
  "*.css"
6
6
  ],
7
7
  "dependencies": {
8
- "@appsemble/sdk": "0.38.0"
8
+ "@appsemble/sdk": "0.38.2-test.0"
9
9
  }
10
10
  }