@appsemble/cli 0.21.2 → 0.22.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.
Files changed (67) hide show
  1. package/README.md +46 -11
  2. package/commands/app/create.d.ts +11 -24
  3. package/commands/app/create.js +98 -62
  4. package/commands/app/index.js +2 -0
  5. package/commands/app/publish.d.ts +27 -0
  6. package/commands/app/publish.js +75 -0
  7. package/commands/asset/index.js +2 -2
  8. package/commands/asset/{create.d.ts → publish.d.ts} +4 -4
  9. package/commands/asset/{create.js → publish.js} +8 -8
  10. package/commands/block/create.d.ts +12 -0
  11. package/commands/block/create.js +66 -0
  12. package/commands/block/delete.d.ts +11 -0
  13. package/commands/block/delete.js +22 -0
  14. package/commands/block/index.js +4 -0
  15. package/commands/migrate.js +2 -2
  16. package/commands/resource/index.js +2 -2
  17. package/commands/resource/{create.d.ts → publish.d.ts} +4 -4
  18. package/commands/resource/{create.js → publish.js} +8 -8
  19. package/commands/serve.js +20 -14
  20. package/index.js +2 -3
  21. package/lib/app.d.ts +8 -9
  22. package/lib/app.js +8 -8
  23. package/lib/asset.d.ts +4 -4
  24. package/lib/asset.js +2 -2
  25. package/lib/block.d.ts +8 -0
  26. package/lib/block.js +6 -6
  27. package/lib/createServers.js +13 -9
  28. package/lib/getBlockConfigFromTypeScript.test.js +3 -1
  29. package/lib/initAxios.js +2 -3
  30. package/lib/resource.d.ts +5 -5
  31. package/lib/resource.js +3 -3
  32. package/package.json +14 -7
  33. package/server/db/methods.js +5 -1
  34. package/server/options/getAppBlockStyles.js +17 -17
  35. package/server/options/parseQuery.js +13 -9
  36. package/templates/apps/empty/.appsemblerc.yaml +15 -0
  37. package/templates/apps/empty/app-definition.yaml +26 -0
  38. package/templates/apps/empty/assets/.gitkeep +0 -0
  39. package/templates/apps/empty/i18n/en.json +0 -0
  40. package/templates/apps/empty/resources/.gitkeep +0 -0
  41. package/templates/apps/empty/themes/@appsemble/.gitkeep +0 -0
  42. package/templates/apps/empty/themes/core/index.css +3 -0
  43. package/templates/apps/empty/themes/shared/index.css +3 -0
  44. package/templates/blocks/mini-jsx/.appsemblerc.yaml +1 -0
  45. package/templates/blocks/mini-jsx/README.md +11 -0
  46. package/templates/blocks/mini-jsx/block.ts +48 -0
  47. package/templates/blocks/mini-jsx/i18n/en.json +3 -0
  48. package/templates/blocks/mini-jsx/package.json +8 -0
  49. package/templates/blocks/mini-jsx/src/index.module.css +19 -0
  50. package/templates/blocks/mini-jsx/src/index.tsx +61 -0
  51. package/templates/blocks/mini-jsx/tsconfig.json +9 -0
  52. package/templates/blocks/preact/.appsemblerc.yaml +1 -0
  53. package/templates/blocks/preact/README.md +11 -0
  54. package/templates/blocks/preact/block.ts +37 -0
  55. package/templates/blocks/preact/i18n/en.json +5 -0
  56. package/templates/blocks/preact/package.json +9 -0
  57. package/templates/blocks/preact/src/index.tsx +99 -0
  58. package/templates/blocks/preact/tsconfig.json +9 -0
  59. package/templates/blocks/vanilla/.appsemblerc.yaml +1 -0
  60. package/templates/blocks/vanilla/README.md +10 -0
  61. package/templates/blocks/vanilla/block.ts +20 -0
  62. package/templates/blocks/vanilla/i18n/en.json +3 -0
  63. package/templates/blocks/vanilla/package.json +7 -0
  64. package/templates/blocks/vanilla/src/index.ts +25 -0
  65. package/templates/blocks/vanilla/tsconfig.json +7 -0
  66. package/types.d.ts +0 -46
  67. package/vitest.config.d.ts +0 -2
@@ -1,4 +1,6 @@
1
1
  import * as build from './build.js';
2
+ import * as create from './create.js';
3
+ import * as remove from './delete.js';
2
4
  import * as extractMessages from './extract-messages.js';
3
5
  import * as publish from './publish.js';
4
6
  export { noop as handler } from '@appsemble/utils';
@@ -7,8 +9,10 @@ export const description = 'Commands related to blocks.';
7
9
  export function builder(yargs) {
8
10
  return yargs
9
11
  .command(build)
12
+ .command(create)
10
13
  .command(extractMessages)
11
14
  .command(publish)
15
+ .command(remove)
12
16
  .demandCommand(1);
13
17
  }
14
18
  //# sourceMappingURL=index.js.map
@@ -1,12 +1,12 @@
1
+ import { version } from '@appsemble/node-utils';
1
2
  import { serverImport } from '../lib/serverImport.js';
2
- import pkg from '../package.json' assert { type: 'json' };
3
3
  export const command = 'migrate [migrate-to]';
4
4
  export const description = 'Migrate the Appsemble database';
5
5
  export function builder(yargs) {
6
6
  return yargs
7
7
  .positional('migrate-to', {
8
8
  desc: 'The database version to migrate to.',
9
- default: pkg.version,
9
+ default: version,
10
10
  })
11
11
  .option('database-host', {
12
12
  desc: 'The host of the database to connect to. This defaults to the connected database container.',
@@ -1,11 +1,11 @@
1
- import * as create from './create.js';
1
+ import * as publish from './publish.js';
2
2
  import * as update from './update.js';
3
3
  export { noop as handler } from '@appsemble/utils';
4
4
  export const command = 'resource';
5
5
  export const description = 'Commands related to resources.';
6
6
  export function builder(yargs) {
7
7
  return yargs
8
- .command(create)
8
+ .command(publish)
9
9
  .command(update)
10
10
  .demandCommand(1);
11
11
  }
@@ -1,14 +1,14 @@
1
1
  import { type Argv } from 'yargs';
2
2
  import { type BaseArguments } from '../../types.js';
3
- interface CreateResourceArguments extends BaseArguments {
3
+ interface PublishResourceArguments extends BaseArguments {
4
4
  resourceName: string;
5
5
  paths: string[];
6
6
  appId: number;
7
7
  context: string;
8
8
  app: string;
9
9
  }
10
- export declare const command = "create <resource-name> <paths...>";
11
- export declare const description = "Create resources based on a specified JSON file or directory.";
10
+ export declare const command = "publish <resource-name> <paths...>";
11
+ export declare const description = "Publish resources based on a specified JSON file or directory.";
12
12
  export declare function builder(yargs: Argv): Argv<any>;
13
- export declare function handler({ app, appId, clientCredentials, context, paths, remote, resourceName, }: CreateResourceArguments): Promise<void>;
13
+ export declare function handler({ app, appId, clientCredentials, context, paths, remote, resourceName, }: PublishResourceArguments): Promise<void>;
14
14
  export {};
@@ -3,22 +3,22 @@ import fg from 'fast-glob';
3
3
  import normalizePath from 'normalize-path';
4
4
  import { resolveAppIdAndRemote } from '../../lib/app.js';
5
5
  import { authenticate } from '../../lib/authentication.js';
6
- import { createResource } from '../../lib/resource.js';
7
- export const command = 'create <resource-name> <paths...>';
8
- export const description = 'Create resources based on a specified JSON file or directory.';
6
+ import { publishResource } from '../../lib/resource.js';
7
+ export const command = 'publish <resource-name> <paths...>';
8
+ export const description = 'Publish resources based on a specified JSON file or directory.';
9
9
  export function builder(yargs) {
10
10
  return yargs
11
11
  .positional('resource-name', {
12
- describe: 'The name of the resource that should be created.',
12
+ describe: 'The name of the resource that should be published.',
13
13
  demandOption: true,
14
14
  })
15
15
  .positional('paths', {
16
- describe: 'The path to the resources to create',
16
+ describe: 'The path to the resources to publish',
17
17
  normalize: true,
18
18
  demandOption: true,
19
19
  })
20
20
  .option('app-id', {
21
- describe: 'The ID of the app to create the resources for.',
21
+ describe: 'The ID of the app to publish the resources for.',
22
22
  type: 'number',
23
23
  })
24
24
  .option('app', {
@@ -41,7 +41,7 @@ export async function handler({ app, appId, clientCredentials, context, paths, r
41
41
  logger.info(`Creating resources based on ${files.length} files`);
42
42
  for (const path of files) {
43
43
  logger.info('');
44
- await createResource({
44
+ await publishResource({
45
45
  resourceName,
46
46
  appId: resolvedAppId,
47
47
  path,
@@ -49,4 +49,4 @@ export async function handler({ app, appId, clientCredentials, context, paths, r
49
49
  });
50
50
  }
51
51
  }
52
- //# sourceMappingURL=create.js.map
52
+ //# sourceMappingURL=publish.js.map
package/commands/serve.js CHANGED
@@ -129,21 +129,26 @@ export async function handler(argv) {
129
129
  const cacheExists = existsSync(cachedBlockManifest);
130
130
  if (!cacheExists || (cacheExists && argv['overwrite-block-cache'])) {
131
131
  const blockUrl = `/api/blocks/@${organization}/${blockName}/versions/${identifiableBlock.version}`;
132
- const { data: blockManifest } = await axios.get(String(new URL(blockUrl, argv.remote)));
133
- await writeData(cachedBlockManifest, blockManifest);
134
- const assetsDir = join(blockCacheDir, 'assets');
135
- if (!existsSync(assetsDir)) {
136
- await mkdir(assetsDir);
137
- }
138
- const blockFilesPromises = blockManifest.files.map(async (filename) => {
139
- const writer = createWriteStream(join(assetsDir, filename));
140
- const { data: content } = await axios.get(String(new URL(`${blockUrl}/asset?filename=${filename}`, argv.remote)), {
141
- responseType: 'stream',
132
+ try {
133
+ const { data: blockManifest } = await axios.get(String(new URL(blockUrl, argv.remote)));
134
+ await writeData(cachedBlockManifest, blockManifest);
135
+ const assetsDir = join(blockCacheDir, 'assets');
136
+ if (!existsSync(assetsDir)) {
137
+ await mkdir(assetsDir);
138
+ }
139
+ const blockFilesPromises = blockManifest.files.map(async (filename) => {
140
+ const writer = createWriteStream(join(assetsDir, filename));
141
+ const { data: content } = await axios.get(String(new URL(`${blockUrl}/asset?filename=${filename}`, argv.remote)), {
142
+ responseType: 'stream',
143
+ });
144
+ content.pipe(writer);
142
145
  });
143
- content.pipe(writer);
144
- });
145
- await Promise.all(blockFilesPromises);
146
- return blockManifest;
146
+ await Promise.all(blockFilesPromises);
147
+ return blockManifest;
148
+ }
149
+ catch {
150
+ 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`);
151
+ }
147
152
  }
148
153
  const [blockManifest] = await readData(cachedBlockManifest);
149
154
  return blockManifest;
@@ -230,6 +235,7 @@ export async function handler(argv) {
230
235
  const api = http.createServer(appsembleApiServer.callback());
231
236
  const staticServer = await createStaticServer({
232
237
  context: {
238
+ appPath,
233
239
  apiUrl: `http://localhost:${argv['api-port']}`,
234
240
  appHost: `http://localhost:${argv.port}`,
235
241
  appsembleApp: stubbedApp,
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import process from 'node:process';
3
- import { configureLogger, handleError } from '@appsemble/node-utils';
3
+ import { configureLogger, handleError, version } from '@appsemble/node-utils';
4
4
  import { cosmiconfig } from 'cosmiconfig';
5
5
  import yargs from 'yargs';
6
6
  import * as app from './commands/app/index.js';
@@ -20,12 +20,11 @@ import * as team from './commands/team/index.js';
20
20
  import { CREDENTIALS_ENV_VAR } from './lib/authentication.js';
21
21
  import { coerceRemote } from './lib/coercers.js';
22
22
  import { initAxios } from './lib/initAxios.js';
23
- import pkg from './package.json' assert { type: 'json' };
24
23
  process.title = 'appsemble';
25
24
  const explorer = cosmiconfig('appsembleServer');
26
25
  const found = await explorer.search(process.cwd());
27
26
  let parser = yargs(process.argv.slice(2))
28
- .version(pkg.version)
27
+ .version(version)
29
28
  .option('verbose', {
30
29
  alias: 'v',
31
30
  describe: 'Increase verbosity',
package/lib/app.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  /// <reference types="node" resolution-mode="require"/>
3
3
  import { type ReadStream } from 'node:fs';
4
- import { type App, type AppVisibility } from '@appsemble/types';
4
+ import { type App, type AppsembleContext, type AppsembleRC, type AppVisibility } from '@appsemble/types';
5
5
  import FormData from 'form-data';
6
- import { type AppsembleContext, type AppsembleRC } from '../types.js';
7
- interface CreateAppParams {
6
+ interface PublishAppParams {
8
7
  /**
9
8
  * The OAuth2 client credentials to use.
10
9
  */
@@ -26,7 +25,7 @@ interface CreateAppParams {
26
25
  */
27
26
  visibility: AppVisibility;
28
27
  /**
29
- * The remote server to create the app on.
28
+ * The remote server to publish the app on.
30
29
  */
31
30
  remote: string;
32
31
  /**
@@ -50,12 +49,12 @@ interface CreateAppParams {
50
49
  */
51
50
  dryRun: boolean;
52
51
  /**
53
- * Whether resources from the `resources` directory should be created after creating the app.
52
+ * Whether resources from the `resources` directory should be published after publishing the app.
54
53
  */
55
54
  resources: boolean;
56
55
  /**
57
56
  * If the app context is specified,
58
- * modify it for the current context to include the id of the created app.
57
+ * modify it for the current context to include the id of the published app.
59
58
  */
60
59
  modifyContext: boolean;
61
60
  /**
@@ -162,11 +161,11 @@ export declare function writeAppMessages(path: string, languages: string[], veri
162
161
  */
163
162
  export declare function updateApp({ clientCredentials, context, force, path, ...options }: UpdateAppParams): Promise<void>;
164
163
  /**
165
- * Create a new App.
164
+ * Publish a new app.
166
165
  *
167
- * @param options The options to use for creating an app.
166
+ * @param options The options to use for publishing an app.
168
167
  */
169
- export declare function createApp({ clientCredentials, context, dryRun, modifyContext, path, resources, ...options }: CreateAppParams): Promise<void>;
168
+ export declare function publishApp({ clientCredentials, context, dryRun, modifyContext, path, resources, ...options }: PublishAppParams): Promise<void>;
170
169
  /**
171
170
  * Resolve the app’s ID and remote based on the app context.
172
171
  *
package/lib/app.js CHANGED
@@ -11,7 +11,7 @@ import { traverseBlockThemes } from './block.js';
11
11
  import { coerceRemote } from './coercers.js';
12
12
  import { printAxiosError } from './output.js';
13
13
  import { processCss } from './processCss.js';
14
- import { createResource } from './resource.js';
14
+ import { publishResource } from './resource.js';
15
15
  /**
16
16
  * Traverses an app directory and appends the files it finds to the given FormData object.
17
17
  *
@@ -88,7 +88,7 @@ export async function traverseAppDirectory(path, context, formData) {
88
88
  }
89
89
  const css = await processCss(join(themeDir, 'index.css'));
90
90
  formData.append(`${name}Style`, css);
91
- gatheredData[`${name}Style`] = await processCss(join(themeDir, 'index.css'));
91
+ gatheredData[`${name}Style`] = css;
92
92
  });
93
93
  default:
94
94
  logger.warn(`Found unused file ${filepath}`);
@@ -358,11 +358,11 @@ export async function updateApp({ clientCredentials, context, force, path, ...op
358
358
  logger.info(`App store page: ${new URL(`/apps/${data.id}`, remote)}`);
359
359
  }
360
360
  /**
361
- * Create a new App.
361
+ * Publish a new app.
362
362
  *
363
- * @param options The options to use for creating an app.
363
+ * @param options The options to use for publishing an app.
364
364
  */
365
- export async function createApp({ clientCredentials, context, dryRun, modifyContext, path, resources, ...options }) {
365
+ export async function publishApp({ clientCredentials, context, dryRun, modifyContext, path, resources, ...options }) {
366
366
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
367
367
  const file = await stat(path);
368
368
  const formData = new FormData();
@@ -456,7 +456,7 @@ export async function createApp({ clientCredentials, context, dryRun, modifyCont
456
456
  for (const resource of resourceFiles) {
457
457
  if (resource.isFile()) {
458
458
  const { name } = parse(resource.name);
459
- await createResource({
459
+ await publishResource({
460
460
  appId: data.id,
461
461
  path: join(resourcePath, resource.name),
462
462
  remote,
@@ -468,7 +468,7 @@ export async function createApp({ clientCredentials, context, dryRun, modifyCont
468
468
  withFileTypes: true,
469
469
  });
470
470
  for (const subResource of subDirectoryResources.filter((s) => s.isFile())) {
471
- await createResource({
471
+ await publishResource({
472
472
  appId: data.id,
473
473
  path: join(resourcePath, resource.name, subResource.name),
474
474
  remote,
@@ -490,7 +490,7 @@ export async function createApp({ clientCredentials, context, dryRun, modifyCont
490
490
  logger.info(`Updated .appsemblerc: Set context.${context}.id to ${data.id}`);
491
491
  }
492
492
  const { host, protocol } = new URL(remote);
493
- logger.info(`Successfully created app ${data.definition.name}! 🙌`);
493
+ logger.info(`Successfully published app ${data.definition.name}! 🙌`);
494
494
  logger.info(`App URL: ${protocol}//${data.path}.${data.OrganizationId}.${host}`);
495
495
  logger.info(`App store page: ${new URL(`/apps/${data.id}`, remote)}`);
496
496
  }
package/lib/asset.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- interface CreateAssetParams {
1
+ interface PublishAssetParams {
2
2
  /**
3
3
  * The name of the asset being uploaded.
4
4
  * This must be a unique name for the app. If left empty, the ID is used instead.
@@ -9,13 +9,13 @@ interface CreateAssetParams {
9
9
  */
10
10
  path: string;
11
11
  /**
12
- * The ID of the app to create a resource entry for.
12
+ * The ID of the app to publish a resource entry for.
13
13
  */
14
14
  appId: number;
15
15
  /**
16
- * The remote server to create the app on.
16
+ * The remote server to publish the asset on.
17
17
  */
18
18
  remote: string;
19
19
  }
20
- export declare function createAsset({ appId, name, path, remote }: CreateAssetParams): Promise<void>;
20
+ export declare function publishAsset({ appId, name, path, remote, }: PublishAssetParams): Promise<void>;
21
21
  export {};
package/lib/asset.js CHANGED
@@ -3,7 +3,7 @@ import { logger } from '@appsemble/node-utils';
3
3
  import { normalize } from '@appsemble/utils';
4
4
  import axios from 'axios';
5
5
  import FormData from 'form-data';
6
- export async function createAsset({ appId, name, path, remote }) {
6
+ export async function publishAsset({ appId, name, path, remote, }) {
7
7
  const formData = new FormData();
8
8
  const file = createReadStream(path);
9
9
  formData.append('file', file);
@@ -11,6 +11,6 @@ export async function createAsset({ appId, name, path, remote }) {
11
11
  formData.append('name', normalize(name));
12
12
  }
13
13
  const { data: { id }, } = await axios.post(`/api/apps/${appId}/assets`, formData, { baseURL: remote });
14
- logger.info(`Created asset ${id}${name ? ` with name ${normalize(name)}` : ''}`);
14
+ logger.info(`Published asset ${id}${name ? ` with name ${normalize(name)}` : ''}`);
15
15
  }
16
16
  //# sourceMappingURL=asset.js.map
package/lib/block.d.ts CHANGED
@@ -7,7 +7,14 @@ import { type Stats } from 'webpack';
7
7
  * @param config The config of the block to build.
8
8
  * @returns The Webpack stats object.
9
9
  */
10
+ interface DeleteBlockVersionParams {
11
+ organization: string;
12
+ blockName: string;
13
+ blockVersion: string;
14
+ remote: string;
15
+ }
10
16
  export declare function buildBlock(config: BlockConfig): Promise<Stats>;
17
+ export declare function deleteBlock({ blockName, blockVersion, organization, remote, }: DeleteBlockVersionParams): Promise<void>;
11
18
  /**
12
19
  * Get the block configuration from a block directory.
13
20
  *
@@ -59,3 +66,4 @@ export declare function uploadAppBlockTheme(filePath: string, organization: stri
59
66
  */
60
67
  export declare function traverseBlockThemes(path: string, appId: number, remote: string, force: boolean): Promise<void>;
61
68
  export declare function processBlockMessages(config: BlockConfig, languages: string[]): Promise<void>;
69
+ export {};
package/lib/block.js CHANGED
@@ -12,12 +12,6 @@ import webpack from 'webpack';
12
12
  import { getBlockConfigFromTypeScript } from './getBlockConfigFromTypeScript.js';
13
13
  import { loadWebpackConfig } from './loadWebpackConfig.js';
14
14
  import { processCss } from './processCss.js';
15
- /**
16
- * Builds a block using Webpack.
17
- *
18
- * @param config The config of the block to build.
19
- * @returns The Webpack stats object.
20
- */
21
15
  export async function buildBlock(config) {
22
16
  const conf = await loadWebpackConfig(config, 'production', join(config.dir, config.output));
23
17
  if (existsSync(conf.output.path)) {
@@ -41,6 +35,12 @@ export async function buildBlock(config) {
41
35
  });
42
36
  });
43
37
  }
38
+ export async function deleteBlock({ blockName, blockVersion, organization, remote, }) {
39
+ await axios.delete(`/api/blocks/@${organization}/${blockName}/versions/${blockVersion}`, {
40
+ baseURL: remote,
41
+ });
42
+ logger.info(`Successfully deleted ${blockName} block version.`);
43
+ }
44
44
  /**
45
45
  * Get the block configuration from a block directory.
46
46
  *
@@ -1,6 +1,5 @@
1
- import { bodyParser, boomMiddleware, conditional, frontend, loggerMiddleware, parameters, serializer, } from '@appsemble/node-utils';
1
+ import { bodyParser, conditional, errorMiddleware, frontend, loggerMiddleware, parameters, serializer, version, } from '@appsemble/node-utils';
2
2
  import { api } from '@appsemble/utils';
3
- import { notFound } from '@hapi/boom';
4
3
  import cors from '@koa/cors';
5
4
  import Koa from 'koa';
6
5
  import compose from 'koa-compose';
@@ -9,14 +8,13 @@ import range from 'koa-range';
9
8
  import { koas } from 'koas-core';
10
9
  import { operations } from 'koas-operations';
11
10
  import { statusCode } from 'koas-status-code';
12
- import pkg from '../package.json' assert { type: 'json' };
13
11
  import { argv } from '../server/argv.js';
14
12
  import * as controllers from '../server/controllers/index.js';
15
13
  import { appRouter } from '../server/routes/appRouter/index.js';
16
14
  export async function createStaticServer({ context, webpackConfigs, }) {
17
15
  const app = new Koa();
18
16
  app.use(loggerMiddleware());
19
- app.use(boomMiddleware());
17
+ app.use(errorMiddleware());
20
18
  app.use(range);
21
19
  Object.assign(app.context, context);
22
20
  if (process.env.NODE_ENV === 'production') {
@@ -31,7 +29,7 @@ export async function createStaticServer({ context, webpackConfigs, }) {
31
29
  export function createApiServer({ context }) {
32
30
  const app = new Koa();
33
31
  app.use(loggerMiddleware());
34
- app.use(boomMiddleware());
32
+ app.use(errorMiddleware());
35
33
  app.use(range);
36
34
  Object.assign(app.context, context);
37
35
  if (process.env.NODE_ENV === 'production') {
@@ -39,16 +37,22 @@ export function createApiServer({ context }) {
39
37
  }
40
38
  app.use(compose([
41
39
  conditional((ctx) => ctx.path.startsWith('/api') || ctx.path === '/oauth2/token', cors()),
42
- koas(api(pkg.version, argv), [
40
+ koas(api(version, argv), [
43
41
  parameters(),
44
42
  bodyParser(),
45
43
  serializer(),
46
44
  statusCode(),
47
45
  operations({ controllers, throwOnNotImplemented: false }),
48
46
  ]),
49
- ({ path }, next) => {
50
- if (path.startsWith('/api/')) {
51
- throw notFound('URL not found');
47
+ (ctx, next) => {
48
+ if (ctx.path.startsWith('/api/')) {
49
+ ctx.response.status = 404;
50
+ ctx.response.body = {
51
+ statusCode: 404,
52
+ error: 'Not Found',
53
+ message: 'URL not found',
54
+ };
55
+ ctx.throw();
52
56
  }
53
57
  return next();
54
58
  },
@@ -49,7 +49,9 @@ describe('getBlockConfigFromTypeScript', () => {
49
49
  },
50
50
  });
51
51
  });
52
- it('should not use TypeScript if all metadata is present in the original config', () => {
52
+ // Spying on TypeScript functions no longer works.
53
+ // eslint-disable-next-line vitest/no-disabled-tests
54
+ it.skip('should not use TypeScript if all metadata is present in the original config', () => {
53
55
  vi.spyOn(ts, 'createProgram');
54
56
  const input = {
55
57
  actions: {},
package/lib/initAxios.js CHANGED
@@ -1,6 +1,5 @@
1
- import { configureAxios, logger } from '@appsemble/node-utils';
1
+ import { configureAxios, logger, version } from '@appsemble/node-utils';
2
2
  import axios from 'axios';
3
- import pkg from '../package.json' assert { type: 'json' };
4
3
  /**
5
4
  * Configure the default axios URL.
6
5
  *
@@ -9,6 +8,6 @@ import pkg from '../package.json' assert { type: 'json' };
9
8
  export function initAxios({ remote }) {
10
9
  axios.defaults.baseURL = remote;
11
10
  logger.verbose(`Request remote set to ${remote}`);
12
- configureAxios('AppsembleCLI', pkg.version);
11
+ configureAxios('AppsembleCLI', version);
13
12
  }
14
13
  //# sourceMappingURL=initAxios.js.map
package/lib/resource.d.ts CHANGED
@@ -12,11 +12,11 @@ interface UpdateResourceParams {
12
12
  */
13
13
  appId: number;
14
14
  /**
15
- * The remote server to create the app on.
15
+ * The remote server to create the resource on.
16
16
  */
17
17
  remote: string;
18
18
  }
19
- interface CreateResourceParams {
19
+ interface PublishResourceParams {
20
20
  /**
21
21
  * The name of the resource that a new entry is being created of.
22
22
  */
@@ -26,14 +26,14 @@ interface CreateResourceParams {
26
26
  */
27
27
  path: string;
28
28
  /**
29
- * The ID of the app to create a resource entry for.
29
+ * The ID of the app to publish a resource entry for.
30
30
  */
31
31
  appId: number;
32
32
  /**
33
- * The remote server to create the app on.
33
+ * The remote server to publish the resource on.
34
34
  */
35
35
  remote: string;
36
36
  }
37
- export declare function createResource({ appId, path, remote, resourceName, }: CreateResourceParams): Promise<void>;
37
+ export declare function publishResource({ appId, path, remote, resourceName, }: PublishResourceParams): Promise<void>;
38
38
  export declare function updateResource({ appId, path, remote, resourceName, }: UpdateResourceParams): Promise<void>;
39
39
  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 createResource({ appId, path, remote, resourceName, }) {
4
+ export async function publishResource({ appId, path, remote, resourceName, }) {
5
5
  const csv = path.endsWith('.csv');
6
6
  let resources;
7
7
  if (csv) {
@@ -14,14 +14,14 @@ export async function createResource({ appId, path, remote, resourceName, }) {
14
14
  }
15
15
  resources = [].concat(file);
16
16
  }
17
- logger.info(`Creating resource(s) from ${path}`);
17
+ logger.info(`Publishing resource(s) from ${path}`);
18
18
  const { data } = await axios.post(`/api/apps/${appId}/resources/${resourceName}`, resources, {
19
19
  baseURL: remote,
20
20
  headers: { 'content-type': csv ? 'text/csv' : 'application/json' },
21
21
  });
22
22
  const ids = [].concat(data).map((d) => d.id);
23
23
  const url = new URL(`/apps/${appId}/resources/${resourceName}/`, remote);
24
- logger.info(`Successfully created ${ids.length} resource${resources.length === 1 ? '' : 's'} at: \n${ids
24
+ logger.info(`Successfully published ${ids.length} resource${resources.length === 1 ? '' : 's'} at: \n${ids
25
25
  .map((id) => `${url}${id}`)
26
26
  .join('\n')}`);
27
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appsemble/cli",
3
- "version": "0.21.2",
3
+ "version": "0.22.0",
4
4
  "description": "The CLI for developing with Appsemble apps and blocks",
5
5
  "keywords": [
6
6
  "app",
@@ -21,24 +21,31 @@
21
21
  "license": "LGPL-3.0-only",
22
22
  "author": "Appsemble <info@appsemble.com> (https://appsemble.com)",
23
23
  "type": "module",
24
+ "exports": {
25
+ ".": [
26
+ "./index.js",
27
+ "./index.ts"
28
+ ],
29
+ "./README.md": "./README.md"
30
+ },
24
31
  "bin": {
25
32
  "appsemble": "index.js"
26
33
  },
27
34
  "files": [
28
35
  "**/*.d.ts",
29
36
  "**/*.js",
30
- "!*.config.js"
37
+ "!*.config.js",
38
+ "templates"
31
39
  ],
32
40
  "scripts": {
33
41
  "prepack": "tsc --noEmit false",
34
42
  "test": "vitest"
35
43
  },
36
44
  "dependencies": {
37
- "@appsemble/node-utils": "0.21.2",
38
- "@appsemble/types": "0.21.2",
39
- "@appsemble/utils": "0.21.2",
45
+ "@appsemble/node-utils": "0.22.0",
46
+ "@appsemble/types": "0.22.0",
47
+ "@appsemble/utils": "0.22.0",
40
48
  "@fortawesome/fontawesome-common-types": "^6.0.0",
41
- "@hapi/boom": "^10.0.0",
42
49
  "@koa/cors": "^4.0.0",
43
50
  "@odata/parser": "^0.2.0",
44
51
  "axios": "^1.0.0",
@@ -78,7 +85,7 @@
78
85
  "yargs": "^17.0.0"
79
86
  },
80
87
  "devDependencies": {
81
- "@appsemble/types": "0.21.2",
88
+ "@appsemble/types": "0.22.0",
82
89
  "@types/concat-stream": "^2.0.0",
83
90
  "@types/inquirer": "^9.0.0",
84
91
  "@types/normalize-path": "^3.0.0",
@@ -1,6 +1,7 @@
1
1
  import { getDb } from './index.js';
2
2
  const defaults = {
3
3
  AppId: 1,
4
+ AuthorId: 1,
4
5
  $created: new Date(),
5
6
  $updated: new Date(),
6
7
  expires: null,
@@ -57,6 +58,9 @@ function applyQuery(entity, key, query) {
57
58
  if (query.eq || query.eq === '') {
58
59
  return parsedEntityValue === parseValue(query.eq);
59
60
  }
61
+ if (query.eq == null && entity[key] === undefined) {
62
+ return true;
63
+ }
60
64
  if (query.ne || query.ne === '') {
61
65
  return parsedEntityValue !== parseValue(query.ne);
62
66
  }
@@ -122,7 +126,7 @@ function applyOrder(entities, order) {
122
126
  }
123
127
  }
124
128
  function clearEntity(entity) {
125
- const { AppId, type, ...cleanPayload } = entity;
129
+ const { AppId, AuthorId, type, ...cleanPayload } = entity;
126
130
  if (!cleanPayload.expires) {
127
131
  delete cleanPayload.expires;
128
132
  }