@appsemble/node-utils 0.27.9 → 0.27.10

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.27.9/config/assets/logo.svg) Appsemble Node Utilities
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.27.10/config/assets/logo.svg) Appsemble Node Utilities
2
2
 
3
3
  > NodeJS utilities used by Appsemble internally.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@appsemble/node-utils)](https://www.npmjs.com/package/@appsemble/node-utils)
6
- [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.27.9/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.27.9)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.27.10/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.27.10)
7
7
  [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://prettier.io)
8
8
 
9
9
  ## Table of Contents
@@ -26,5 +26,5 @@ compatibility is not guaranteed.
26
26
 
27
27
  ## License
28
28
 
29
- [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.27.9/LICENSE.md) ©
29
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.27.10/LICENSE.md) ©
30
30
  [Appsemble](https://appsemble.com)
package/app.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type App, type UserInfo } from '@appsemble/types';
1
+ import { type App, type AppsembleMessages, type UserInfo } from '@appsemble/types';
2
2
  import { type RemapperContext } from '@appsemble/utils';
3
3
  import { type DefaultContext, type DefaultState, type ParameterizedContext } from 'koa';
4
4
  import { type Options } from './server/types.js';
@@ -15,4 +15,20 @@ import { type Options } from './server/types.js';
15
15
  * @returns A localized remapper context for the app.
16
16
  */
17
17
  export declare function getRemapperContext(app: App, language: string, userInfo: UserInfo, options: Options, context: ParameterizedContext<DefaultState, DefaultContext, any>): Promise<RemapperContext>;
18
+ /**
19
+ * Patch an app definition of an app inside the `apps` folder.
20
+ *
21
+ * @param appPath The path to the app to patch.
22
+ * @param patches Patches to apply to the YAML.
23
+ */
24
+ export declare function patchDefinition(appPath: string, patches: [key: (number | string)[], value: unknown][]): Promise<void>;
25
+ /**
26
+ * Patch app messages.
27
+ *
28
+ * The replacements will be deep merged into the original content.
29
+ *
30
+ * @param appPath The name of the app to patch.
31
+ * @param replacements Replacements for the original messages.
32
+ */
33
+ export declare function patchMessages(appPath: string, replacements: Record<string, Partial<AppsembleMessages>>): Promise<void>;
18
34
  export declare function applyAppVariant(appPath: string, appVariant: string): Promise<void>;
package/app.js CHANGED
@@ -9,7 +9,7 @@ import { IntlMessageFormat } from 'intl-messageformat';
9
9
  import lodash from 'lodash';
10
10
  import { format, resolveConfig } from 'prettier';
11
11
  import { parseDocument } from 'yaml';
12
- import { readData, writeData } from './fs.js';
12
+ import { opendirSafe, readData, writeData } from './fs.js';
13
13
  import { logger } from './logger.js';
14
14
  const getNumberFormat = memoize((locale, opts) => new Intl.NumberFormat(locale, opts));
15
15
  const getPluralRules = memoize((locale, opts) => new Intl.PluralRules(locale, opts));
@@ -87,7 +87,7 @@ function replaceStyle(stylesheet, selector, property, value) {
87
87
  * @param appPath The path to the app to patch.
88
88
  * @param patches Patches to apply to the YAML.
89
89
  */
90
- async function patchDefinition(appPath, patches) {
90
+ export async function patchDefinition(appPath, patches) {
91
91
  try {
92
92
  const path = join(appPath, 'app-definition.yaml');
93
93
  logger.verbose(`Updating ${path}`);
@@ -118,11 +118,15 @@ async function patchDefinition(appPath, patches) {
118
118
  * @param appPath The name of the app to patch.
119
119
  * @param replacements Replacements for the original messages.
120
120
  */
121
- async function patchMessages(appPath, replacements) {
121
+ export async function patchMessages(appPath, replacements) {
122
122
  try {
123
123
  const i18nPath = join(appPath, 'i18n');
124
124
  for (const [language, replacementMessages] of Object.entries(replacements)) {
125
125
  const originalMessagesPath = join(i18nPath, `${language}.json`);
126
+ if (!existsSync(originalMessagesPath)) {
127
+ logger.warn(`Missing translation file at ${originalMessagesPath}`);
128
+ return;
129
+ }
126
130
  logger.verbose(`Updating ${originalMessagesPath}`);
127
131
  const [originalMessages] = await readData(originalMessagesPath);
128
132
  await (replacementMessages
@@ -201,6 +205,21 @@ async function transferAppVariantFiles(appPath, appVariantDefDir, appVariantDest
201
205
  logger.error(error);
202
206
  }
203
207
  }
208
+ async function transferReadmes(appPath, appVariantDefDir, appVariantDestDir) {
209
+ try {
210
+ await opendirSafe(appVariantDefDir, async (filePath, fileStat) => {
211
+ if (fileStat.isFile()) {
212
+ const fileBasename = basename(filePath);
213
+ if (fileBasename.toLowerCase().startsWith('readme')) {
214
+ await transferAppVariantFiles(appPath, appVariantDefDir, appVariantDestDir, fileBasename);
215
+ }
216
+ }
217
+ });
218
+ }
219
+ catch (error) {
220
+ logger.error(error);
221
+ }
222
+ }
204
223
  export async function applyAppVariant(appPath, appVariant) {
205
224
  try {
206
225
  logger.info(`Applying ${appVariant} variant to ${appPath}`);
@@ -214,6 +233,7 @@ export async function applyAppVariant(appPath, appVariant) {
214
233
  await transferAppVariantFiles(appPath, appVariantDefDir, appVariantDestDir, 'resources');
215
234
  await transferAppVariantFiles(appPath, appVariantDefDir, appVariantDestDir, 'screenshots');
216
235
  await transferAppVariantFiles(appPath, appVariantDefDir, appVariantDestDir, 'icon.png');
236
+ await transferReadmes(appPath, appVariantDefDir, appVariantDestDir);
217
237
  const patchesPath = join(appVariantDefDir, 'patches');
218
238
  try {
219
239
  const definitionPath = join(patchesPath, 'app-definition.json');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appsemble/node-utils",
3
- "version": "0.27.9",
3
+ "version": "0.27.10",
4
4
  "description": "NodeJS utilities used by Appsemble internally.",
5
5
  "keywords": [
6
6
  "app",
@@ -38,8 +38,8 @@
38
38
  "test": "vitest"
39
39
  },
40
40
  "dependencies": {
41
- "@appsemble/types": "0.27.9",
42
- "@appsemble/utils": "0.27.9",
41
+ "@appsemble/types": "0.27.10",
42
+ "@appsemble/utils": "0.27.10",
43
43
  "@formatjs/fast-memoize": "^2.0.0",
44
44
  "@fortawesome/fontawesome-free": "^6.0.0",
45
45
  "@koa/cors": "^4.0.0",
@@ -11,6 +11,7 @@ import { createCssHandler } from './cssHandler.js';
11
11
  import { createIconHandler } from './iconHandler.js';
12
12
  import { createIndexHandler } from './indexHandler.js';
13
13
  import { createManifestHandler } from './manifestHandler.js';
14
+ import { createReadmeHandler } from './readmeHandler.js';
14
15
  import { createRobotsHandler } from './robotsHandler.js';
15
16
  import { createScreenshotHandler } from './screenshotHandler.js';
16
17
  import { createServiceWorkerHandler } from './serviceWorkerHandler.js';
@@ -39,6 +40,10 @@ export function createAppRouter(options) {
39
40
  route: /^\/screenshots\/(?<id>\d+)\.(?<ext>[a-z]+)$/,
40
41
  get: createScreenshotHandler(options),
41
42
  },
43
+ {
44
+ route: /^\/readmes\/(?<id>\d+)\.md$/,
45
+ get: createReadmeHandler(options),
46
+ },
42
47
  {
43
48
  route: new RegExp(`^/api/blocks/${blockName}/versions/(?<version>${partialSemver.source})/(?<filename>.+)$`),
44
49
  get: createBlockAssetHandler(options),
@@ -0,0 +1,3 @@
1
+ import { type Options } from '@appsemble/node-utils';
2
+ import { type Middleware } from 'koa';
3
+ export declare function createReadmeHandler({ getApp, getAppReadmes }: Options): Middleware;
@@ -0,0 +1,15 @@
1
+ import { assertKoaError } from '@appsemble/node-utils';
2
+ export function createReadmeHandler({ getApp, getAppReadmes }) {
3
+ return async (ctx) => {
4
+ const { id } = ctx.params;
5
+ const app = await getApp({ context: ctx });
6
+ assertKoaError(!app, ctx, 404, 'App not found');
7
+ const appReadmes = await getAppReadmes({ app, context: ctx });
8
+ const appReadme = appReadmes.find((readme) => readme.id === Number.parseInt(id));
9
+ assertKoaError(!appReadme, ctx, 404, 'Readme not found');
10
+ const { file } = appReadme;
11
+ ctx.type = 'text/markdown';
12
+ ctx.body = file;
13
+ };
14
+ }
15
+ //# sourceMappingURL=readmeHandler.js.map
package/server/types.d.ts CHANGED
@@ -28,6 +28,7 @@ declare module 'koa' {
28
28
  appUserInfo: UserInfo;
29
29
  appTeams: ExtendedTeam[];
30
30
  appAssets: AppAsset[];
31
+ appReadmes: AppReadme[];
31
32
  blockConfigs: ContextBlockConfig[];
32
33
  params?: Record<string, string>;
33
34
  }
@@ -73,6 +74,7 @@ declare module 'koas-parameters' {
73
74
  resourceTypeId: string;
74
75
  schemaId: string;
75
76
  screenshotId: number;
77
+ readmeId: number;
76
78
  snapshotId: number;
77
79
  teamId: string;
78
80
  token: string;
@@ -96,6 +98,8 @@ declare module 'koas-parameters' {
96
98
  view: string;
97
99
  resources: boolean;
98
100
  assets: boolean;
101
+ screenshots: boolean;
102
+ readmes: boolean;
99
103
  roles: string[];
100
104
  }
101
105
  }
@@ -313,6 +317,10 @@ export interface AppScreenshot {
313
317
  height: number;
314
318
  width: number;
315
319
  }
320
+ export interface AppReadme {
321
+ id: number;
322
+ file: Buffer;
323
+ }
316
324
  export interface AppBlockStyle {
317
325
  style: string;
318
326
  }
@@ -344,6 +352,7 @@ export interface Options {
344
352
  getAppTeams: (params: GetAppTeamsParams) => Promise<ExtendedTeam[]>;
345
353
  getAppStyles: (params: GetAppParams | GetAppSubEntityParams) => Promise<AppStyles>;
346
354
  getAppScreenshots: (params: GetAppSubEntityParams) => Promise<AppScreenshot[]>;
355
+ getAppReadmes: (params: GetAppSubEntityParams) => Promise<AppReadme[]>;
347
356
  getAppBlockStyles: (params: GetAppBlockStylesParams) => Promise<AppBlockStyle[]>;
348
357
  getAppIcon: (params: GetAppSubEntityParams) => Promise<Buffer>;
349
358
  getAppUrl: (params: GetAppSubEntityParams) => Promise<URL>;