@appsemble/cli 0.37.4 → 0.37.5
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/serve.js +18 -10
- package/commands/start.js +3 -0
- package/lib/config.js +1 -1
- package/lib/createServers.js +3 -1
- package/lib/processCss.js +22 -2
- package/package.json +8 -7
- package/server/options/getAppBlockStyles.js +4 -3
- package/server/options/getAppStyles.js +5 -2
- 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.37.5)
|
|
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.37.
|
|
345
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.37.5/LICENSE.md) ©
|
|
346
346
|
[Appsemble](https://appsemble.com)
|
package/commands/serve.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { createWriteStream, existsSync } from 'node:fs';
|
|
2
2
|
import { mkdir, readFile } from 'node:fs/promises';
|
|
3
3
|
import http from 'node:http';
|
|
4
|
-
import { basename, extname, join, parse } from 'node:path';
|
|
4
|
+
import { basename, dirname, extname, join, parse } from 'node:path';
|
|
5
5
|
import { Readable } from 'node:stream';
|
|
6
|
+
import { pipeline } from 'node:stream/promises';
|
|
6
7
|
import { getAppBlocks, getAppRoles, normalize, parseBlockName, } from '@appsemble/lang-sdk';
|
|
7
|
-
import { AppsembleError, logger, opendirSafe, readData, writeData, } from '@appsemble/node-utils';
|
|
8
|
+
import { AppsembleError, getBlockAssetDownloadUrl, isValidBlockAssetFilename, logger, opendirSafe, readData, writeData, } from '@appsemble/node-utils';
|
|
8
9
|
import { asciiLogo } from '@appsemble/utils';
|
|
9
10
|
import axios from 'axios';
|
|
10
11
|
import csvToJson from 'csvtojson';
|
|
@@ -132,29 +133,36 @@ export async function handler(argv) {
|
|
|
132
133
|
const cachedBlockManifest = join(blockCacheDir, 'manifest.json');
|
|
133
134
|
const cacheExists = existsSync(cachedBlockManifest);
|
|
134
135
|
if (!cacheExists || (cacheExists && argv['overwrite-block-cache'])) {
|
|
135
|
-
const blockUrl = `/api/blocks/@${organization}/${blockName}/versions/${identifiableBlock.version}
|
|
136
|
+
const blockUrl = String(new URL(`/api/blocks/@${organization}/${blockName}/versions/${identifiableBlock.version}`, argv.remote));
|
|
136
137
|
try {
|
|
137
|
-
const { data: blockManifest } = await axios.get(
|
|
138
|
-
await writeData(cachedBlockManifest, blockManifest);
|
|
138
|
+
const { data: blockManifest } = await axios.get(blockUrl);
|
|
139
139
|
const assetsDir = join(blockCacheDir, 'assets');
|
|
140
140
|
if (!existsSync(assetsDir)) {
|
|
141
141
|
await mkdir(assetsDir);
|
|
142
142
|
}
|
|
143
143
|
const blockFilesPromises = blockManifest.files.map(async (filename) => {
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
if (!isValidBlockAssetFilename(filename)) {
|
|
145
|
+
throw new AppsembleError(`Invalid block asset filename: ${filename}`);
|
|
146
|
+
}
|
|
147
|
+
const target = join(assetsDir, filename);
|
|
148
|
+
await mkdir(dirname(target), { recursive: true });
|
|
149
|
+
const { data: content } = await axios.get(getBlockAssetDownloadUrl(blockUrl, blockManifest.fileUrls, filename), {
|
|
146
150
|
responseType: 'stream',
|
|
147
151
|
});
|
|
148
|
-
content
|
|
152
|
+
await pipeline(content, createWriteStream(target));
|
|
149
153
|
});
|
|
150
154
|
await Promise.all(blockFilesPromises);
|
|
151
|
-
|
|
155
|
+
const localBlockManifest = { ...blockManifest };
|
|
156
|
+
delete localBlockManifest.fileUrls;
|
|
157
|
+
await writeData(cachedBlockManifest, localBlockManifest);
|
|
158
|
+
return localBlockManifest;
|
|
152
159
|
}
|
|
153
160
|
catch {
|
|
154
161
|
throw new AppsembleError(`The server was unable to fetch the "${blockName}" block\nThis could be due to a misconfigured remote\nMake sure the passed remote supports fetching blocks such as https://appsemble.app`);
|
|
155
162
|
}
|
|
156
163
|
}
|
|
157
|
-
const [blockManifest] = await readData(cachedBlockManifest);
|
|
164
|
+
const [blockManifest] = (await readData(cachedBlockManifest));
|
|
165
|
+
delete blockManifest.fileUrls;
|
|
158
166
|
return blockManifest;
|
|
159
167
|
});
|
|
160
168
|
const localBlocks = await Promise.all(localBlocksPromises);
|
package/commands/start.js
CHANGED
|
@@ -139,6 +139,9 @@ export function builder(yargs) {
|
|
|
139
139
|
})
|
|
140
140
|
.option('s3-secret-key', {
|
|
141
141
|
desc: 'The secret key of the Amazon S3 compatible object storage server',
|
|
142
|
+
})
|
|
143
|
+
.option('block-assets-base-url', {
|
|
144
|
+
desc: 'The base URL for block assets stored in S3 compatible object storage',
|
|
142
145
|
})
|
|
143
146
|
.option('valkey-host', {
|
|
144
147
|
desc: 'The host of the Valkey server to connect to.',
|
package/lib/config.js
CHANGED
|
@@ -407,7 +407,7 @@ export async function getProjectWebpackConfig(buildConfig, mode, outputPath) {
|
|
|
407
407
|
config.output = config.output || {};
|
|
408
408
|
config.output.path = outputPath || publicPath;
|
|
409
409
|
logger.verbose(`Patched webpack config output.path to ${config.output.path}`);
|
|
410
|
-
config.output.publicPath = publicPath;
|
|
410
|
+
config.output.publicPath = mode === 'production' ? 'auto' : publicPath;
|
|
411
411
|
logger.verbose(`Patched webpack config output.publicPath to ${config.output.publicPath}`);
|
|
412
412
|
return config;
|
|
413
413
|
}
|
package/lib/createServers.js
CHANGED
|
@@ -40,7 +40,9 @@ export function createApiServer({ context }) {
|
|
|
40
40
|
app.use(compose([
|
|
41
41
|
conditional((ctx) => ctx.path.startsWith('/api') ||
|
|
42
42
|
ctx.path === '/auth/oauth2/token' ||
|
|
43
|
-
/\/apps\/\d+\/auth\/oauth2\/token/.test(ctx.path),
|
|
43
|
+
/\/apps\/\d+\/auth\/oauth2\/token/.test(ctx.path),
|
|
44
|
+
// Reflect the origin instead of '*', so credentialed app requests pass CORS.
|
|
45
|
+
cors({ origin: (ctx) => ctx.get('Origin') || '*', credentials: true })),
|
|
44
46
|
koas(api(version, argv), [
|
|
45
47
|
parameters(),
|
|
46
48
|
bodyParser(),
|
package/lib/processCss.js
CHANGED
|
@@ -2,7 +2,28 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import postcss from 'postcss';
|
|
3
3
|
import postcssImport from 'postcss-import';
|
|
4
4
|
import postcssrc from 'postcss-load-config';
|
|
5
|
+
import postcssPresetEnv from 'postcss-preset-env';
|
|
5
6
|
import postcssUrl from 'postcss-url';
|
|
7
|
+
/**
|
|
8
|
+
* Load the PostCSS plugins to process app CSS with.
|
|
9
|
+
*
|
|
10
|
+
* The PostCSS config of the project is used if it has one. Otherwise the CSS is processed with the
|
|
11
|
+
* Appsemble CLI's default PostCSS preset.
|
|
12
|
+
*
|
|
13
|
+
* @returns The PostCSS plugins to use.
|
|
14
|
+
*/
|
|
15
|
+
async function loadPlugins() {
|
|
16
|
+
try {
|
|
17
|
+
const { plugins } = await postcssrc();
|
|
18
|
+
return plugins;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (!error.message?.startsWith('No PostCSS Config found')) {
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
return [postcssPresetEnv({ stage: 0 })];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
6
27
|
/**
|
|
7
28
|
* Verifies and processes a CSS file using PostCSS.
|
|
8
29
|
*
|
|
@@ -11,8 +32,7 @@ import postcssUrl from 'postcss-url';
|
|
|
11
32
|
*/
|
|
12
33
|
export async function processCss(path) {
|
|
13
34
|
const data = await readFile(path, 'utf8');
|
|
14
|
-
const
|
|
15
|
-
const postCss = postcss(postcssConfig.plugins);
|
|
35
|
+
const postCss = postcss(await loadPlugins());
|
|
16
36
|
postCss.use(postcssUrl({ url: 'inline' }));
|
|
17
37
|
postCss.use(postcssImport({ plugins: postCss.plugins }));
|
|
18
38
|
const { css } = await postCss.process(data, { from: path, to: undefined });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/cli",
|
|
3
|
-
"version": "0.37.
|
|
3
|
+
"version": "0.37.5",
|
|
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.37.
|
|
48
|
-
"@appsemble/types": "0.37.
|
|
49
|
-
"@appsemble/lang-sdk": "0.37.
|
|
50
|
-
"@appsemble/utils": "0.37.
|
|
47
|
+
"@appsemble/node-utils": "0.37.5",
|
|
48
|
+
"@appsemble/types": "0.37.5",
|
|
49
|
+
"@appsemble/lang-sdk": "0.37.5",
|
|
50
|
+
"@appsemble/utils": "0.37.5",
|
|
51
51
|
"@fortawesome/fontawesome-common-types": "^6.0.0",
|
|
52
52
|
"@inquirer/prompts": "^8.0.0",
|
|
53
53
|
"@koa/cors": "^5.0.0",
|
|
@@ -76,6 +76,7 @@
|
|
|
76
76
|
"postcss": "^8.0.0",
|
|
77
77
|
"postcss-import": "^15.0.0",
|
|
78
78
|
"postcss-load-config": "^4.0.0",
|
|
79
|
+
"postcss-preset-env": "^9.0.0",
|
|
79
80
|
"postcss-url": "^10.0.0",
|
|
80
81
|
"prettier": "^3.0.0",
|
|
81
82
|
"raw-body": "^2.0.0",
|
|
@@ -89,8 +90,8 @@
|
|
|
89
90
|
"yargs": "^17.0.0"
|
|
90
91
|
},
|
|
91
92
|
"devDependencies": {
|
|
92
|
-
"@appsemble/types": "0.37.
|
|
93
|
-
"@appsemble/server": "0.37.
|
|
93
|
+
"@appsemble/types": "0.37.5",
|
|
94
|
+
"@appsemble/server": "0.37.5",
|
|
94
95
|
"@types/concat-stream": "2.0.3",
|
|
95
96
|
"@types/koa__cors": "5.0.1",
|
|
96
97
|
"@types/koa-compress": "4.0.7",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { parseBlockName } from '@appsemble/lang-sdk';
|
|
4
|
-
import { opendirSafe, } from '@appsemble/node-utils';
|
|
4
|
+
import { opendirSafe, replaceAssetFunctions, } from '@appsemble/node-utils';
|
|
5
5
|
import { processCss } from '../../lib/processCss.js';
|
|
6
6
|
export async function getAppBlockStyles({ context, name, }) {
|
|
7
|
-
const { appPath } = context;
|
|
7
|
+
const { apiUrl, appPath, appsembleApp } = context;
|
|
8
8
|
const [, blockName] = parseBlockName(name);
|
|
9
9
|
let style = '';
|
|
10
10
|
const themeDirPath = join(appPath, 'theme');
|
|
@@ -16,7 +16,8 @@ export async function getAppBlockStyles({ context, name, }) {
|
|
|
16
16
|
if (themeStat.name.startsWith('@') && existsSync(blockDir)) {
|
|
17
17
|
await opendirSafe(blockDir, async (file) => {
|
|
18
18
|
if (file.endsWith('.css')) {
|
|
19
|
-
|
|
19
|
+
const css = await processCss(join(file));
|
|
20
|
+
style = replaceAssetFunctions(css, appsembleApp.id, apiUrl);
|
|
20
21
|
}
|
|
21
22
|
});
|
|
22
23
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { replaceAssetFunctions, } from '@appsemble/node-utils';
|
|
1
2
|
export function getAppStyles({ context }) {
|
|
3
|
+
const { apiUrl, appsembleApp } = context;
|
|
4
|
+
const { coreStyle = '', id, sharedStyle = '' } = appsembleApp;
|
|
2
5
|
return Promise.resolve({
|
|
3
|
-
coreStyle:
|
|
4
|
-
sharedStyle:
|
|
6
|
+
coreStyle: replaceAssetFunctions(coreStyle, id, apiUrl),
|
|
7
|
+
sharedStyle: replaceAssetFunctions(sharedStyle, id, apiUrl),
|
|
5
8
|
});
|
|
6
9
|
}
|
|
7
10
|
//# sourceMappingURL=getAppStyles.js.map
|
|
@@ -6,7 +6,7 @@ pages:
|
|
|
6
6
|
- name: Example Page A
|
|
7
7
|
blocks:
|
|
8
8
|
- type: action-button
|
|
9
|
-
version: 0.37.
|
|
9
|
+
version: 0.37.5
|
|
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.37.
|
|
20
|
+
version: 0.37.5
|
|
21
21
|
parameters:
|
|
22
22
|
icon: arrow-left
|
|
23
23
|
actions:
|