@appsemble/cli 0.36.10 → 0.37.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
- # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.36.10/config/assets/logo.svg) Appsemble CLI
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.37.1/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.36.10/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.36.10)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.37.1/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.37.1)
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.36.10/LICENSE.md) ©
345
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.37.1/LICENSE.md) ©
346
346
  [Appsemble](https://appsemble.com)
package/commands/start.js CHANGED
@@ -159,6 +159,11 @@ export function builder(yargs) {
159
159
  desc: 'Use TLS when connecting to the Valkey server.',
160
160
  type: 'boolean',
161
161
  default: false,
162
+ })
163
+ .option('app-serving-cache-ttl', {
164
+ desc: 'The TTL in seconds for cached app-serving metadata. Set to 0 to disable the cache.',
165
+ type: 'number',
166
+ default: 300,
162
167
  });
163
168
  }
164
169
  export async function handler(argv) {
package/lib/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { readFile, stat } from 'node:fs/promises';
3
- import { dirname, join, relative } from 'node:path';
3
+ import { dirname, isAbsolute, join, relative } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
4
5
  import { inspect } from 'node:util';
5
6
  import { prefixBlockURL } from '@appsemble/lang-sdk';
6
7
  import { AppsembleError, getWorkspaces, logger, readData } from '@appsemble/node-utils';
@@ -396,7 +397,8 @@ export async function getProjectWebpackConfig(buildConfig, mode, outputPath) {
396
397
  }
397
398
  logger.info(`Using webpack config from ${configPath}`);
398
399
  const publicPath = prefixBlockURL({ type: buildConfig.name, version: buildConfig.version }, '');
399
- let config = await import(String(configPath));
400
+ const configSpecifier = isAbsolute(configPath) ? pathToFileURL(configPath).href : configPath;
401
+ let config = await import(configSpecifier);
400
402
  config = await (config.default || config);
401
403
  config = config instanceof Function ? await config(buildConfig, { mode, publicPath }) : config;
402
404
  // Koa-webpack serves assets on the `output.path` path. Normally this field describes where to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appsemble/cli",
3
- "version": "0.36.10",
3
+ "version": "0.37.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.36.10",
48
- "@appsemble/types": "0.36.10",
49
- "@appsemble/lang-sdk": "0.36.10",
50
- "@appsemble/utils": "0.36.10",
47
+ "@appsemble/node-utils": "0.37.1",
48
+ "@appsemble/types": "0.37.1",
49
+ "@appsemble/lang-sdk": "0.37.1",
50
+ "@appsemble/utils": "0.37.1",
51
51
  "@fortawesome/fontawesome-common-types": "^6.0.0",
52
52
  "@inquirer/prompts": "^8.0.0",
53
53
  "@koa/cors": "^5.0.0",
@@ -89,8 +89,8 @@
89
89
  "yargs": "^17.0.0"
90
90
  },
91
91
  "devDependencies": {
92
- "@appsemble/types": "0.36.10",
93
- "@appsemble/server": "0.36.10",
92
+ "@appsemble/types": "0.37.1",
93
+ "@appsemble/server": "0.37.1",
94
94
  "@types/concat-stream": "2.0.3",
95
95
  "@types/koa__cors": "5.0.1",
96
96
  "@types/koa-compress": "4.0.7",
@@ -1,2 +1,2 @@
1
1
  import { type DeleteAppResourceParams } from '@appsemble/node-utils';
2
- export declare function deleteAppResource({ id, type }: DeleteAppResourceParams): Promise<void>;
2
+ export declare function deleteAppResource({ context, id, ifMatch, type, }: DeleteAppResourceParams): Promise<void>;
@@ -1,5 +1,16 @@
1
+ import { createResourceEtag, matchesResourceIfMatch, throwResourcePreconditionFailedKoaError, } from '@appsemble/node-utils';
1
2
  import { Resource } from '../models/Resource.js';
2
- export function deleteAppResource({ id, type }) {
3
- return Resource.deleteOne(id, type);
3
+ import { withResourceLock } from '../utils/resourceLock.js';
4
+ export function deleteAppResource({ context, id, ifMatch, type, }) {
5
+ return withResourceLock(type, id, async () => {
6
+ if (ifMatch) {
7
+ const existing = await Resource.findById(id, type);
8
+ if (!existing ||
9
+ !matchesResourceIfMatch(ifMatch, createResourceEtag(existing))) {
10
+ throwResourcePreconditionFailedKoaError(context, type, id);
11
+ }
12
+ }
13
+ return Resource.deleteOne(id, type);
14
+ });
4
15
  }
5
16
  //# sourceMappingURL=deleteAppResource.js.map
@@ -1,2 +1,2 @@
1
1
  import { type GetThemeParams, type Theme as ThemeInterface } from '@appsemble/node-utils';
2
- export declare function getTheme({ theme }: GetThemeParams): Promise<ThemeInterface>;
2
+ export declare function getTheme({ theme }: GetThemeParams): Promise<ThemeInterface | null>;
@@ -1,9 +1,6 @@
1
1
  import { Theme } from '../models/Theme.js';
2
2
  export async function getTheme({ theme }) {
3
3
  const persistedTheme = await Theme.findOne({ where: theme });
4
- return {
5
- // @ts-expect-error 2322 null is not assignable to type (strictNullChecks)
6
- css: persistedTheme ? persistedTheme.css : null,
7
- };
4
+ return persistedTheme && { css: persistedTheme.css };
8
5
  }
9
6
  //# sourceMappingURL=getTheme.js.map
@@ -1,3 +1,3 @@
1
1
  import { type UpdateAppResourceParams } from '@appsemble/node-utils';
2
2
  import { type Resource as ResourceInterface } from '@appsemble/types';
3
- export declare function updateAppResource({ id, resource, type, }: UpdateAppResourceParams): Promise<ResourceInterface | null>;
3
+ export declare function updateAppResource({ context, id, ifMatch, resource, type, }: UpdateAppResourceParams): Promise<ResourceInterface | null>;
@@ -1,5 +1,16 @@
1
+ import { createResourceEtag, matchesResourceIfMatch, throwResourcePreconditionFailedKoaError, } from '@appsemble/node-utils';
1
2
  import { Resource } from '../models/Resource.js';
2
- export function updateAppResource({ id, resource, type, }) {
3
- return Resource.updateOne(id, resource, type);
3
+ import { withResourceLock } from '../utils/resourceLock.js';
4
+ export function updateAppResource({ context, id, ifMatch, resource, type, }) {
5
+ return withResourceLock(type, id, async () => {
6
+ if (ifMatch) {
7
+ const existing = await Resource.findById(id, type);
8
+ if (!existing ||
9
+ !matchesResourceIfMatch(ifMatch, createResourceEtag(existing))) {
10
+ throwResourcePreconditionFailedKoaError(context, type, id);
11
+ }
12
+ }
13
+ return Resource.updateOne(id, resource, type);
14
+ });
4
15
  }
5
16
  //# sourceMappingURL=updateAppResource.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Serialize file-backed resource operations against the same (type, id) pair so
3
+ * the read-then-write pattern used by `updateAppResource`/`deleteAppResource`
4
+ * cannot interleave with a concurrent writer.
5
+ *
6
+ * @param type Resource type, used as part of the lock key.
7
+ * @param id Resource id, used as part of the lock key.
8
+ * @param fn Async operation to run while holding the lock.
9
+ * @returns The resolved value of `fn`.
10
+ */
11
+ export declare function withResourceLock<T>(type: string, id: number | string, fn: () => Promise<T>): Promise<T>;
@@ -0,0 +1,23 @@
1
+ const queues = new Map();
2
+ /**
3
+ * Serialize file-backed resource operations against the same (type, id) pair so
4
+ * the read-then-write pattern used by `updateAppResource`/`deleteAppResource`
5
+ * cannot interleave with a concurrent writer.
6
+ *
7
+ * @param type Resource type, used as part of the lock key.
8
+ * @param id Resource id, used as part of the lock key.
9
+ * @param fn Async operation to run while holding the lock.
10
+ * @returns The resolved value of `fn`.
11
+ */
12
+ export function withResourceLock(type, id, fn) {
13
+ const key = `${type}#${id}`;
14
+ const previous = queues.get(key) ?? Promise.resolve();
15
+ const next = previous.then(fn, fn);
16
+ queues.set(key, next.finally(() => {
17
+ if (queues.get(key) === next) {
18
+ queues.delete(key);
19
+ }
20
+ }));
21
+ return next;
22
+ }
23
+ //# sourceMappingURL=resourceLock.js.map
@@ -6,7 +6,7 @@ pages:
6
6
  - name: Example Page A
7
7
  blocks:
8
8
  - type: action-button
9
- version: 0.36.10
9
+ version: 0.37.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.36.10
20
+ version: 0.37.1
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.36.10",
8
+ "@appsemble/sdk": "0.37.1",
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.36.10",
9
- "@appsemble/sdk": "0.36.10",
8
+ "@appsemble/preact": "0.37.1",
9
+ "@appsemble/sdk": "0.37.1",
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.36.10"
8
+ "@appsemble/sdk": "0.37.1"
9
9
  }
10
10
  }