@appsemble/cli 0.38.0 → 0.38.1
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
|
-
#  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.38.1)
|
|
7
7
|
[](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.
|
|
345
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.38.1/LICENSE.md) ©
|
|
346
346
|
[Appsemble](https://appsemble.com)
|
package/lib/app.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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
|
-
|
|
325
|
-
|
|
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.
|
|
3
|
+
"version": "0.38.1",
|
|
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.
|
|
48
|
-
"@appsemble/types": "0.38.
|
|
49
|
-
"@appsemble/lang-sdk": "0.38.
|
|
50
|
-
"@appsemble/utils": "0.38.
|
|
47
|
+
"@appsemble/node-utils": "0.38.1",
|
|
48
|
+
"@appsemble/types": "0.38.1",
|
|
49
|
+
"@appsemble/lang-sdk": "0.38.1",
|
|
50
|
+
"@appsemble/utils": "0.38.1",
|
|
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.
|
|
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.
|
|
94
|
-
"@appsemble/server": "0.38.
|
|
93
|
+
"@appsemble/types": "0.38.1",
|
|
94
|
+
"@appsemble/server": "0.38.1",
|
|
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": "
|
|
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.
|
|
9
|
+
version: 0.38.1
|
|
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.
|
|
20
|
+
version: 0.38.1
|
|
21
21
|
parameters:
|
|
22
22
|
icon: arrow-left
|
|
23
23
|
actions:
|