@appsemble/node-utils 0.33.5 → 0.33.9
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/app.d.ts +1 -1
- package/app.js +2 -1
- package/container/helpers.d.ts +1 -1
- package/container/operations.d.ts +1 -1
- package/container/specs.d.ts +1 -1
- package/getMessagesUtil.js +2 -1
- package/package.json +4 -3
- package/resource.d.ts +2 -1
- package/resource.js +43 -38
- package/server/controllers/common/apps/groups/createGetAppGroupsController.js +1 -1
- package/server/controllers/common/apps/resources/createGetAppResourceByIdController.js +1 -1
- package/server/controllers/common/apps/resources/createQueryAppResourcesController.js +1 -1
- package/server/routes/appRouter/bulmaHandler.js +1 -1
- package/server/routes/appRouter/indexHandler.js +2 -1
- package/server/routes/appRouter/manifestHandler.js +2 -1
- package/server/routes/appRouter/serviceWorkerHandler.js +1 -1
- package/server/types.d.ts +2 -2
- package/server/utils/actions.d.ts +2 -1
- package/server/utils/actions.js +1 -1
- package/server/utils/resources.d.ts +2 -1
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#  Appsemble Node Utilities
|
|
2
2
|
|
|
3
3
|
> NodeJS utilities used by Appsemble internally.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@appsemble/node-utils)
|
|
6
|
-
[](https://gitlab.com/appsemble/appsemble/-/releases/0.33.9)
|
|
7
7
|
[](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.33.
|
|
29
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.33.9/LICENSE.md) ©
|
|
30
30
|
[Appsemble](https://appsemble.com)
|
package/app.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { type RemapperContext } from '@appsemble/lang-sdk';
|
|
1
2
|
import { type App, type AppsembleMessages } from '@appsemble/types';
|
|
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';
|
|
5
5
|
/**
|
package/app.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { basename, dirname, join } from 'node:path';
|
|
4
|
-
import { defaultLocale
|
|
4
|
+
import { defaultLocale } from '@appsemble/lang-sdk';
|
|
5
|
+
import { has, objectCache } from '@appsemble/utils';
|
|
5
6
|
import { memoize } from '@formatjs/fast-memoize';
|
|
6
7
|
import { generate, parse, walk } from 'css-tree';
|
|
7
8
|
import { copy, ensureDir } from 'fs-extra';
|
package/container/helpers.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ContainerEnvVar, type ContainerResourceProps, type ContainerResources } from '@appsemble/
|
|
1
|
+
import { type ContainerEnvVar, type ContainerResourceProps, type ContainerResources } from '@appsemble/lang-sdk';
|
|
2
2
|
import { AppsV1Api, CoreV1Api, KubeConfig, type V1EnvVar } from '@kubernetes/client-node';
|
|
3
3
|
export declare const maxCPU: number;
|
|
4
4
|
export declare const maxMemoryGi: number;
|
package/container/specs.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CompanionContainerDefinition } from '@appsemble/
|
|
1
|
+
import { type CompanionContainerDefinition } from '@appsemble/lang-sdk';
|
|
2
2
|
import { type V1Deployment, type V1Service } from '@kubernetes/client-node';
|
|
3
3
|
/**
|
|
4
4
|
* Create the spec objects for a service, deployment, and pod.
|
package/getMessagesUtil.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { defaultLocale, normalizeBlockName } from '@appsemble/lang-sdk';
|
|
1
2
|
import { getAppsembleMessages, mergeMessages, } from '@appsemble/node-utils';
|
|
2
|
-
import {
|
|
3
|
+
import { extractAppMessages } from '@appsemble/utils';
|
|
3
4
|
import tags from 'language-tags';
|
|
4
5
|
import { assertKoaCondition, throwKoaError } from './koa.js';
|
|
5
6
|
export async function getMessagesUtil(ctx, language, appId, merge, { getApp, getAppMessages, getBlockMessages }, override = 'true') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/node-utils",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.9",
|
|
4
4
|
"description": "NodeJS utilities used by Appsemble internally.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -40,8 +40,9 @@
|
|
|
40
40
|
"test": "vitest"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@appsemble/types": "0.33.
|
|
44
|
-
"@appsemble/utils": "0.33.
|
|
43
|
+
"@appsemble/types": "0.33.9",
|
|
44
|
+
"@appsemble/utils": "0.33.9",
|
|
45
|
+
"@appsemble/lang-sdk": "0.33.9",
|
|
45
46
|
"@formatjs/fast-memoize": "^2.0.0",
|
|
46
47
|
"@fortawesome/fontawesome-free": "^6.0.0",
|
|
47
48
|
"@kubernetes/client-node": "^0.22.2",
|
package/resource.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type AppDefinition, type ResourceDefinition
|
|
1
|
+
import { type AppDefinition, type ResourceDefinition } from '@appsemble/lang-sdk';
|
|
2
|
+
import { type Resource as ResourceType } from '@appsemble/types';
|
|
2
3
|
import { type PreValidatePropertyFunction } from 'jsonschema';
|
|
3
4
|
import { type Context, type DefaultContext, type DefaultState, type ParameterizedContext } from 'koa';
|
|
4
5
|
import { type JsonValue } from 'type-fest';
|
package/resource.js
CHANGED
|
@@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { mapValues } from '@appsemble/utils';
|
|
3
3
|
import { addMilliseconds, isPast, parseISO } from 'date-fns';
|
|
4
4
|
import { ValidationError, Validator } from 'jsonschema';
|
|
5
|
+
import { partition } from 'lodash-es';
|
|
5
6
|
import parseDuration from 'parse-duration';
|
|
6
7
|
import { preProcessCSV } from './csv.js';
|
|
7
8
|
import { handleValidatorResult, TempFile } from './index.js';
|
|
@@ -118,6 +119,7 @@ export function extractResourceBody(ctx) {
|
|
|
118
119
|
preValidateProperty,
|
|
119
120
|
];
|
|
120
121
|
}
|
|
122
|
+
// XXX: unify with webhooks logic
|
|
121
123
|
/**
|
|
122
124
|
* Process an incoming resource request body.
|
|
123
125
|
*
|
|
@@ -138,38 +140,41 @@ export function extractResourceBody(ctx) {
|
|
|
138
140
|
export function processResourceBody(ctx, definition, knownAssetIds = [], knownExpires, knownAssetNameIds = [], isPatch = false) {
|
|
139
141
|
const [resource, assets, preValidateProperty] = extractResourceBody(ctx);
|
|
140
142
|
const validator = new Validator();
|
|
141
|
-
const assetIdMap = new Map();
|
|
142
|
-
const assetUsedMap = new Map();
|
|
143
143
|
const reusedAssets = new Set();
|
|
144
|
-
const
|
|
145
|
-
const regularAssets = [];
|
|
144
|
+
const usedAssetIndices = new Set();
|
|
146
145
|
const thumbnailAssetSuffix = '-thumbnail.png';
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
146
|
+
const [thumbnailAssets, regularAssets] = partition(
|
|
147
|
+
// Preserve original index to handle asset references in data
|
|
148
|
+
assets.map((asset, index) => ({ asset, index })), ({ asset }) => asset.filename?.endsWith(thumbnailAssetSuffix));
|
|
149
|
+
const preparedRegularAssets = regularAssets.map(({ asset: { filename, mime, path }, index }) => ({
|
|
150
|
+
index,
|
|
151
|
+
asset: {
|
|
152
|
+
id: randomUUID(),
|
|
153
|
+
filename,
|
|
154
|
+
mime,
|
|
155
|
+
path,
|
|
156
|
+
},
|
|
157
|
+
}));
|
|
158
|
+
// Maps 1 unique thumbnail asset to 1 unique regular asset (without other thumbnail assets
|
|
159
|
+
// pointing to it), or a random UUID if no match is found
|
|
160
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
161
|
+
const { prepared: preparedThumbnailAssets } = thumbnailAssets.reduce(({ prepared, used }, { asset, index }) => {
|
|
162
|
+
const reg = preparedRegularAssets.find((regular) => regular.asset.filename?.startsWith(asset.filename.replace(thumbnailAssetSuffix, '')) &&
|
|
163
|
+
!used.includes(regular.asset.id));
|
|
164
|
+
const id = reg ? `${reg.asset.id}-thumbnail` : randomUUID();
|
|
165
|
+
return {
|
|
166
|
+
prepared: [...prepared, { index, asset: { ...asset, id } }],
|
|
167
|
+
used: used.concat(reg?.asset.id ?? []),
|
|
168
|
+
};
|
|
169
|
+
}, { used: [], prepared: [] });
|
|
170
|
+
const assetIndexIdMap = new Map();
|
|
171
|
+
for (const { asset, index } of preparedRegularAssets) {
|
|
172
|
+
assetIndexIdMap.set(index, asset.id);
|
|
154
173
|
}
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return { path, filename, id, mime };
|
|
160
|
-
});
|
|
161
|
-
const usedPreparedRegularAssets = [];
|
|
162
|
-
const preparedThumbnailAssets = thumbnailAssets.map(({ filename, mime, path }, index) => {
|
|
163
|
-
const regularAsset = preparedRegularAssets.find((ra) => !usedPreparedRegularAssets.includes(ra.id) &&
|
|
164
|
-
ra.filename?.startsWith(filename.replace(thumbnailAssetSuffix, '')));
|
|
165
|
-
const id = regularAsset ? `${regularAsset.id}-thumbnail` : randomUUID();
|
|
166
|
-
// @ts-expect-error 2322 null is not assignable to type (strictNullChecks) - Severe
|
|
167
|
-
usedPreparedRegularAssets.push(regularAsset?.id);
|
|
168
|
-
assetIdMap.set(index + preparedRegularAssets.length, id);
|
|
169
|
-
assetUsedMap.set(index, false);
|
|
170
|
-
return { path, filename, id, mime };
|
|
171
|
-
});
|
|
172
|
-
const preparedAssets = [...preparedRegularAssets, ...preparedThumbnailAssets];
|
|
174
|
+
for (const { asset, index } of preparedThumbnailAssets) {
|
|
175
|
+
assetIndexIdMap.set(index, asset.id);
|
|
176
|
+
}
|
|
177
|
+
const preparedAssets = [...preparedRegularAssets, ...preparedThumbnailAssets].map(({ asset }) => asset);
|
|
173
178
|
validator.customFormats.binary = (input) => {
|
|
174
179
|
if (knownAssetIds.includes(input)) {
|
|
175
180
|
reusedAssets.add(input);
|
|
@@ -184,7 +189,7 @@ export function processResourceBody(ctx, definition, knownAssetIds = [], knownEx
|
|
|
184
189
|
return false;
|
|
185
190
|
}
|
|
186
191
|
const num = Number(input);
|
|
187
|
-
if (
|
|
192
|
+
if (usedAssetIndices.has(num)) {
|
|
188
193
|
return false;
|
|
189
194
|
}
|
|
190
195
|
return num >= 0 && num < assets.length;
|
|
@@ -200,7 +205,9 @@ export function processResourceBody(ctx, definition, knownAssetIds = [], knownEx
|
|
|
200
205
|
{ type: 'string', format: 'date-time' },
|
|
201
206
|
{
|
|
202
207
|
type: 'string',
|
|
203
|
-
pattern:
|
|
208
|
+
pattern:
|
|
209
|
+
// TODO: This pattern is duplicated at least 5 times across the codebase
|
|
210
|
+
/^(\d+(y|yr|years))?\s*(\d+months)?\s*(\d+(w|wk|weeks))?\s*(\d+(d|days))?\s*(\d+(h|hr|hours))?\s*(\d+(m|min|minutes))?\s*(\d+(s|sec|seconds))?$/
|
|
204
211
|
.source,
|
|
205
212
|
},
|
|
206
213
|
],
|
|
@@ -270,24 +277,22 @@ export function processResourceBody(ctx, definition, knownAssetIds = [], knownEx
|
|
|
270
277
|
return value;
|
|
271
278
|
}
|
|
272
279
|
const num = Number(value);
|
|
273
|
-
if (!
|
|
280
|
+
if (!assetIndexIdMap.has(num)) {
|
|
274
281
|
return value;
|
|
275
282
|
}
|
|
276
|
-
const uuid =
|
|
283
|
+
const uuid = assetIndexIdMap.get(num);
|
|
277
284
|
const currentResource = Array.isArray(resource) ? resource[path[0]] : resource;
|
|
278
285
|
const preparedAsset = preparedAssets.find((asset) => asset.id === uuid);
|
|
279
286
|
if (preparedAsset) {
|
|
280
287
|
preparedAsset.resource = currentResource;
|
|
281
288
|
}
|
|
282
|
-
|
|
289
|
+
usedAssetIndices.add(num);
|
|
283
290
|
return uuid;
|
|
284
291
|
},
|
|
285
292
|
});
|
|
286
293
|
result.errors.push(...customErrors);
|
|
287
|
-
for (const [
|
|
288
|
-
|
|
289
|
-
result.errors.push(new ValidationError('is not referenced from the resource', assetId, undefined, ['assets', assetId], 'binary', 'format'));
|
|
290
|
-
}
|
|
294
|
+
for (const index of [...assetIndexIdMap.keys()].filter((idx) => !usedAssetIndices.has(idx))) {
|
|
295
|
+
result.errors.push(new ValidationError('is not referenced from the resource', index, undefined, ['assets', index], 'binary', 'format'));
|
|
291
296
|
}
|
|
292
297
|
handleValidatorResult(ctx, result, 'Resource validation failed');
|
|
293
298
|
return [resource, preparedAssets, knownAssetIds.filter((id) => !reusedAssets.has(id))];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AppPermission } from '@appsemble/
|
|
1
|
+
import { AppPermission } from '@appsemble/lang-sdk';
|
|
2
2
|
import { assertKoaCondition } from '../../../../../koa.js';
|
|
3
3
|
export function createGetAppGroupsController({ checkAuthSubjectAppPermissions, getApp, getAppGroups, }) {
|
|
4
4
|
return async (ctx) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { defaultLocale, remap } from '@appsemble/lang-sdk';
|
|
1
2
|
import { assertKoaCondition, getRemapperContext, getResourceDefinition, } from '@appsemble/node-utils';
|
|
2
|
-
import { defaultLocale, remap } from '@appsemble/utils';
|
|
3
3
|
export function createGetAppResourceByIdController(options) {
|
|
4
4
|
return async (ctx) => {
|
|
5
5
|
const { pathParams: { appId, resourceId, resourceType }, queryParams: { selectedGroupId, view }, user: authSubject, } = ctx;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { defaultLocale, remap } from '@appsemble/lang-sdk';
|
|
1
2
|
import { getRemapperContext, getResourceDefinition, } from '@appsemble/node-utils';
|
|
2
|
-
import { defaultLocale, remap } from '@appsemble/utils';
|
|
3
3
|
import { generateResourceQuery } from '../../../../utils/resources.js';
|
|
4
4
|
export function createQueryAppResourcesController(options) {
|
|
5
5
|
return async (ctx) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
+
import { baseTheme } from '@appsemble/lang-sdk';
|
|
2
3
|
import { bulmaVersion, logger } from '@appsemble/node-utils';
|
|
3
|
-
import { baseTheme } from '@appsemble/utils';
|
|
4
4
|
import { renderSync } from 'sass';
|
|
5
5
|
import stripBom from 'strip-bom';
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { getAppBlocks } from '@appsemble/lang-sdk';
|
|
3
|
+
import { createThemeURL, defaultLocale, mergeThemes } from '@appsemble/utils';
|
|
3
4
|
import { organizationBlocklist } from '../../../organizationBlocklist.js';
|
|
4
5
|
import { makeCSP, render } from '../../../render.js';
|
|
5
6
|
import { bulmaVersion, faVersion } from '../../../versions.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { baseTheme } from '@appsemble/lang-sdk';
|
|
1
2
|
import { assertKoaCondition } from '@appsemble/node-utils';
|
|
2
|
-
import {
|
|
3
|
+
import { normalize } from '@appsemble/utils';
|
|
3
4
|
import { extension } from 'mime-types';
|
|
4
5
|
const iconSizes = [48, 144, 192, 512];
|
|
5
6
|
export function createManifestHandler({ getApp, getAppScreenshots }) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { getAppBlocks } from '@appsemble/lang-sdk';
|
|
2
3
|
import { assertKoaCondition } from '@appsemble/node-utils';
|
|
3
|
-
import { getAppBlocks } from '@appsemble/utils';
|
|
4
4
|
export function createServiceWorkerHandler({ getApp, getBlocksAssetsPaths }) {
|
|
5
5
|
return async (ctx) => {
|
|
6
6
|
const production = process.env.NODE_ENV === 'production';
|
package/server/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Readable } from 'node:stream';
|
|
2
|
-
import { type
|
|
3
|
-
import { type
|
|
2
|
+
import { type BlockDefinition, type ControllerDefinition, type CustomAppPermission, type EmailActionDefinition, type IdentifiableBlock, type ResourceDefinition, type Theme as ThemeType } from '@appsemble/lang-sdk';
|
|
3
|
+
import { type App, type AppConfigEntry, type AppMemberInfo, type AppMessages, type Asset, type BlockManifest, type Group, type OrganizationPermission, type Resource } from '@appsemble/types';
|
|
4
4
|
import { type RawAxiosRequestConfig } from 'axios';
|
|
5
5
|
import { type DefaultContext as DefaultContextInterface, type DefaultState, type ParameterizedContext } from 'koa';
|
|
6
6
|
export interface AuthSubject {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { type EmailActionDefinition, type NotifyActionDefinition } from '@appsemble/lang-sdk';
|
|
1
2
|
import { type Options } from '@appsemble/node-utils';
|
|
2
|
-
import { type App
|
|
3
|
+
import { type App } from '@appsemble/types';
|
|
3
4
|
import { type Context, type Middleware } from 'koa';
|
|
4
5
|
export declare function handleEmail(ctx: Context, app: App, action: EmailActionDefinition, options: Options): Promise<void>;
|
|
5
6
|
export declare function handleNotify(ctx: Context, app: App, action: NotifyActionDefinition, options: Options): Promise<void>;
|
package/server/utils/actions.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { defaultLocale, remap, } from '@appsemble/lang-sdk';
|
|
1
2
|
import { assertKoaCondition, createFormData, EmailQuotaExceededError, getContainerNamespace, getRemapperContext, logger, parseServiceUrl, scaleDeployment, setLastRequestAnnotation, throwKoaError, version, waitForPodReadiness, } from '@appsemble/node-utils';
|
|
2
|
-
import { defaultLocale, remap } from '@appsemble/utils';
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import { get, mapValues, pick } from 'lodash-es';
|
|
5
5
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ResourceDefinition } from '@appsemble/lang-sdk';
|
|
2
|
+
import { type App } from '@appsemble/types';
|
|
2
3
|
import { type Context } from 'koa';
|
|
3
4
|
import { type Options, type OrderItem, type WhereOptions } from '../types.js';
|
|
4
5
|
export declare function generateResourceQuery(ctx: Context, { parseQuery }: Options, resourceDefinition?: ResourceDefinition): {
|