@appsemble/node-utils 0.30.14-test.3 → 0.30.14-test.4
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.js +3 -5
- package/container/helpers.js +3 -5
- package/container/logs.js +8 -9
- package/container/operations.js +17 -20
- package/container/scale.js +2 -7
- package/container/specs.js +7 -8
- package/getAppsembleMessages.js +1 -1
- package/getMessagesUtil.js +6 -7
- package/logger.js +2 -3
- package/package.json +4 -4
- package/render.js +1 -1
- package/resource.js +7 -10
- package/server/controllers/common/apps/resources/createCountAppResourcesController.js +2 -2
- package/server/controllers/common/apps/resources/createCreateAppResourceController.js +2 -3
- package/server/controllers/common/apps/resources/createDeleteAppResourceController.js +2 -3
- package/server/controllers/common/apps/resources/createGetAppResourceByIdController.js +2 -3
- package/server/controllers/common/apps/resources/createQueryAppResourcesController.js +4 -5
- package/server/controllers/common/apps/resources/createUpdateAppResourceController.js +2 -3
- package/server/controllers/main/apps/resources/createDeleteAppSeedResourcesController.js +1 -2
- package/server/routes/appRouter/bulmaHandler.js +1 -1
- package/server/routes/appRouter/iconHandler.js +1 -1
- package/server/routes/appRouter/indexHandler.js +1 -2
- package/server/utils/actions.js +4 -4
- package/server/utils/resources.js +1 -4
- package/tinyRouter.js +1 -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.30.14-test.4)
|
|
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.30.14-test.
|
|
29
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.30.14-test.4/LICENSE.md) ©
|
|
30
30
|
[Appsemble](https://appsemble.com)
|
package/app.js
CHANGED
|
@@ -25,7 +25,6 @@ const getPluralRules = memoize((locale, opts) => new Intl.PluralRules(locale, op
|
|
|
25
25
|
* @returns A localized remapper context for the app.
|
|
26
26
|
*/
|
|
27
27
|
export async function getRemapperContext(app, language, options, context) {
|
|
28
|
-
var _a, _b;
|
|
29
28
|
const { getAppMessages, getAppUrl, getAppVariables, getCurrentAppMember } = options;
|
|
30
29
|
const appUrl = String(await getAppUrl({ context, app }));
|
|
31
30
|
const appMessages = await getAppMessages({
|
|
@@ -39,7 +38,7 @@ export async function getRemapperContext(app, language, options, context) {
|
|
|
39
38
|
formatters: {
|
|
40
39
|
getNumberFormat,
|
|
41
40
|
getPluralRules,
|
|
42
|
-
getDateTimeFormat: memoize((locale, opts) => new Intl.DateTimeFormat(locale, { ...opts, timeZone: appMemberInfo
|
|
41
|
+
getDateTimeFormat: memoize((locale, opts) => new Intl.DateTimeFormat(locale, { ...opts, timeZone: appMemberInfo?.zoneinfo })),
|
|
43
42
|
},
|
|
44
43
|
}));
|
|
45
44
|
return {
|
|
@@ -52,12 +51,11 @@ export async function getRemapperContext(app, language, options, context) {
|
|
|
52
51
|
return cache(message || `'{${id}}'`);
|
|
53
52
|
},
|
|
54
53
|
getVariable(variableName) {
|
|
55
|
-
|
|
56
|
-
return (_a = appVariables.find((appVariable) => appVariable.name === variableName)) === null || _a === void 0 ? void 0 : _a.value;
|
|
54
|
+
return appVariables.find((appVariable) => appVariable.name === variableName)?.value;
|
|
57
55
|
},
|
|
58
56
|
appMemberInfo,
|
|
59
57
|
context: {},
|
|
60
|
-
locale:
|
|
58
|
+
locale: appMemberInfo?.locale ?? app.definition.defaultLanguage ?? defaultLocale,
|
|
61
59
|
};
|
|
62
60
|
}
|
|
63
61
|
function replaceStyle(stylesheet, selector, property, value) {
|
package/container/helpers.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
var _a, _b;
|
|
2
1
|
import { logger } from '@appsemble/node-utils';
|
|
3
2
|
import { AppsV1Api, CoreV1Api, HttpError, KubeConfig, } from '@kubernetes/client-node';
|
|
4
|
-
export const maxCPU =
|
|
3
|
+
export const maxCPU = process.env.MAX_CONTAINER_CPU ?? 3;
|
|
5
4
|
// In gigabytes
|
|
6
|
-
export const maxMemoryGi =
|
|
5
|
+
export const maxMemoryGi = process.env.MAX_CONTAINER_MEMORY ?? 3;
|
|
7
6
|
export const appIdLabel = 'appId';
|
|
8
7
|
export const resourceDefaults = { memory: '128Mi', cpu: '0.1' };
|
|
9
8
|
export function getKubeConfig() {
|
|
@@ -14,8 +13,7 @@ export function getKubeConfig() {
|
|
|
14
13
|
return { appsApi, coreApi, kubeconfig };
|
|
15
14
|
}
|
|
16
15
|
export function getContainerNamespace() {
|
|
17
|
-
|
|
18
|
-
return `companion-containers-${(_a = process.env.SERVICE_NAME) !== null && _a !== void 0 ? _a : 'appsemble'}`;
|
|
16
|
+
return `companion-containers-${process.env.SERVICE_NAME ?? 'appsemble'}`;
|
|
19
17
|
}
|
|
20
18
|
export function formatServiceName(containerName, appName, appId) {
|
|
21
19
|
const serviceName = `${containerName}-${appName}-${appId}`.replaceAll(' ', '-').toLowerCase();
|
package/container/logs.js
CHANGED
|
@@ -35,12 +35,11 @@ function filterLogEntries(entries, deploymentName, fromAppsemble) {
|
|
|
35
35
|
return res;
|
|
36
36
|
}
|
|
37
37
|
export async function getLogs(deploymentName, fromAppsemble) {
|
|
38
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
39
38
|
const { coreApi } = getKubeConfig();
|
|
40
39
|
let pods;
|
|
41
40
|
const containerNamespace = getContainerNamespace();
|
|
42
41
|
let appsembleNamespace = 'appsemble';
|
|
43
|
-
const appsembleServiceName =
|
|
42
|
+
const appsembleServiceName = process.env.SERVICE_NAME ?? 'appsemble';
|
|
44
43
|
logger.silly(`Using service name ${appsembleServiceName}`);
|
|
45
44
|
try {
|
|
46
45
|
const NAMESPACE_FILE_PATH = '/var/run/secrets/kubernetes.io/serviceaccount/namespace';
|
|
@@ -65,19 +64,19 @@ export async function getLogs(deploymentName, fromAppsemble) {
|
|
|
65
64
|
}
|
|
66
65
|
const podLogs = [];
|
|
67
66
|
for (const pod of pods.items) {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
if (fromAppsemble && !
|
|
67
|
+
if (pod.metadata?.ownerReferences?.find((r) => r.kind === 'ReplicaSet') &&
|
|
68
|
+
pod.status?.phase === 'Running') {
|
|
69
|
+
if (fromAppsemble && !pod.metadata?.name.includes(appsembleServiceName)) {
|
|
71
70
|
continue;
|
|
72
71
|
}
|
|
73
|
-
if (!fromAppsemble && !
|
|
72
|
+
if (!fromAppsemble && !pod.metadata?.name.includes(deploymentName)) {
|
|
74
73
|
continue;
|
|
75
74
|
}
|
|
76
|
-
logger.silly(`Pod: ${
|
|
75
|
+
logger.silly(`Pod: ${pod.metadata?.name}, status: ${pod.status}, deployment: ${deploymentName}`);
|
|
77
76
|
try {
|
|
78
|
-
const res = await fetchLogs(fromAppsemble ? appsembleNamespace : containerNamespace,
|
|
77
|
+
const res = await fetchLogs(fromAppsemble ? appsembleNamespace : containerNamespace, pod.metadata?.name, fromAppsemble ? 'appsemble' : deploymentName);
|
|
79
78
|
let entries = res.split('\n');
|
|
80
|
-
logger.silly(`Number of entries found for pod ${
|
|
79
|
+
logger.silly(`Number of entries found for pod ${pod.metadata?.name}: ${entries.length}`);
|
|
81
80
|
entries = filterLogEntries([...entries], deploymentName, fromAppsemble);
|
|
82
81
|
podLogs.push({ fromAppsemble, entries });
|
|
83
82
|
}
|
package/container/operations.js
CHANGED
|
@@ -12,7 +12,6 @@ import { generateDeploymentAndServiceSpecs } from './specs.js';
|
|
|
12
12
|
* @param appId Id of the app.
|
|
13
13
|
*/
|
|
14
14
|
export async function updateNamespacedSecret(secretName, value, appName, appId) {
|
|
15
|
-
var _a, _b;
|
|
16
15
|
// If testing, don't create Kubernetes resources
|
|
17
16
|
if (process.env.TEST) {
|
|
18
17
|
return;
|
|
@@ -50,16 +49,15 @@ export async function updateNamespacedSecret(secretName, value, appName, appId)
|
|
|
50
49
|
return;
|
|
51
50
|
}
|
|
52
51
|
try {
|
|
53
|
-
logger.verbose(`Creating secret ${
|
|
52
|
+
logger.verbose(`Creating secret ${secretSpec.metadata?.name} ...`);
|
|
54
53
|
const { body: secret } = await coreApi.createNamespacedSecret(namespace, secretSpec);
|
|
55
|
-
logger.info(`Secret ${
|
|
54
|
+
logger.info(`Secret ${secret.metadata?.name} created successfully`);
|
|
56
55
|
}
|
|
57
56
|
catch (error) {
|
|
58
57
|
handleKubernetesError(error);
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
export async function deleteSecret(appName, appId, key) {
|
|
62
|
-
var _a;
|
|
63
61
|
if (process.env.TEST) {
|
|
64
62
|
return;
|
|
65
63
|
}
|
|
@@ -71,7 +69,7 @@ export async function deleteSecret(appName, appId, key) {
|
|
|
71
69
|
const { body: secret } = await coreApi.readNamespacedSecret(secretName, namespace);
|
|
72
70
|
logger.verbose(`Deleteing key ${key} of secret ${secretName} from namespace ${namespace} ...`);
|
|
73
71
|
if (!(key in secret.data)) {
|
|
74
|
-
logger.warn(`Key ${key} does not exist on secret ${
|
|
72
|
+
logger.warn(`Key ${key} does not exist on secret ${secret.metadata?.name}`);
|
|
75
73
|
return;
|
|
76
74
|
}
|
|
77
75
|
delete secret.data[key];
|
|
@@ -96,7 +94,6 @@ export async function deleteCompanionContainers(serviceName) {
|
|
|
96
94
|
await deleteResource('deployment', namespace, serviceName);
|
|
97
95
|
}
|
|
98
96
|
export async function updateCompanionContainers(definitions, appName, appId, registry) {
|
|
99
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
100
97
|
// If testing, don't create Kubernetes resources
|
|
101
98
|
if (process.env.TEST) {
|
|
102
99
|
return;
|
|
@@ -116,12 +113,12 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
116
113
|
// Update or create deployment and service
|
|
117
114
|
for (const def of definitions) {
|
|
118
115
|
const serviceName = formatServiceName(def.name, appName, appId);
|
|
119
|
-
const existing =
|
|
116
|
+
const existing = services?.items?.find((s) => s.metadata.name === serviceName);
|
|
120
117
|
// Update
|
|
121
118
|
if (existing) {
|
|
122
119
|
logger.verbose(`Updating resources for ${existing.metadata.name} in namespace ${namespace}`);
|
|
123
120
|
const patchOptions = [
|
|
124
|
-
|
|
121
|
+
existing.metadata?.name,
|
|
125
122
|
namespace,
|
|
126
123
|
[
|
|
127
124
|
{
|
|
@@ -132,7 +129,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
132
129
|
{
|
|
133
130
|
op: 'replace',
|
|
134
131
|
path: '/spec/ports/0/targetPort',
|
|
135
|
-
value:
|
|
132
|
+
value: def.port ?? 8080,
|
|
136
133
|
},
|
|
137
134
|
{
|
|
138
135
|
op: 'add',
|
|
@@ -150,7 +147,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
150
147
|
// Update service
|
|
151
148
|
try {
|
|
152
149
|
const updatedService = await coreApi.patchNamespacedService(...patchOptions);
|
|
153
|
-
logger.info(`Service ${
|
|
150
|
+
logger.info(`Service ${updatedService?.body?.metadata?.name} updated`);
|
|
154
151
|
}
|
|
155
152
|
catch (error) {
|
|
156
153
|
logger.error('Error updating service:');
|
|
@@ -167,7 +164,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
167
164
|
{
|
|
168
165
|
op: 'replace',
|
|
169
166
|
path: '/spec/template/spec/containers/0/ports/0/containerPort',
|
|
170
|
-
value:
|
|
167
|
+
value: def.port ?? 8080,
|
|
171
168
|
},
|
|
172
169
|
{
|
|
173
170
|
op: 'replace',
|
|
@@ -187,7 +184,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
187
184
|
];
|
|
188
185
|
try {
|
|
189
186
|
const updatedDeployment = await appsApi.patchNamespacedDeployment(...patchOptions);
|
|
190
|
-
logger.info(`Deployment ${
|
|
187
|
+
logger.info(`Deployment ${updatedDeployment?.body?.metadata?.name} updated`);
|
|
191
188
|
}
|
|
192
189
|
catch (error) {
|
|
193
190
|
logger.error('Error updating deployment:');
|
|
@@ -196,11 +193,11 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
196
193
|
// Update pod
|
|
197
194
|
try {
|
|
198
195
|
const { body } = await coreApi.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, `appId=${appId}`);
|
|
199
|
-
if (
|
|
196
|
+
if (body?.items?.length === 0) {
|
|
200
197
|
logger.silly(`Deployment ${serviceName} has 0 pods, skipping ...`);
|
|
201
198
|
continue;
|
|
202
199
|
}
|
|
203
|
-
const pod =
|
|
200
|
+
const pod = body?.items?.find((i) => i.metadata.labels.app === existing.metadata.name);
|
|
204
201
|
// Set base labels, such as selector, pod name, pod hash
|
|
205
202
|
const props = {
|
|
206
203
|
...def.metadata,
|
|
@@ -212,7 +209,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
212
209
|
},
|
|
213
210
|
name: pod.metadata.name,
|
|
214
211
|
};
|
|
215
|
-
patchOptions[0] =
|
|
212
|
+
patchOptions[0] = pod?.metadata?.name;
|
|
216
213
|
patchOptions[2] = [
|
|
217
214
|
{
|
|
218
215
|
op: 'replace',
|
|
@@ -221,7 +218,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
221
218
|
},
|
|
222
219
|
];
|
|
223
220
|
const updatedPod = await coreApi.patchNamespacedPod(...patchOptions);
|
|
224
|
-
logger.verbose(`Pod updated: ${
|
|
221
|
+
logger.verbose(`Pod updated: ${updatedPod?.body?.metadata?.name}`);
|
|
225
222
|
}
|
|
226
223
|
catch (error) {
|
|
227
224
|
handleKubernetesError(error);
|
|
@@ -234,7 +231,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
234
231
|
logger.verbose(`Creating resources in namespace ${namespace} ...`);
|
|
235
232
|
try {
|
|
236
233
|
const deploymentObj = await appsApi.createNamespacedDeployment(namespace, deployment);
|
|
237
|
-
logger.info(`Deployment created: ${
|
|
234
|
+
logger.info(`Deployment created: ${deploymentObj.body?.metadata?.name}`);
|
|
238
235
|
}
|
|
239
236
|
catch (error) {
|
|
240
237
|
handleKubernetesError(error);
|
|
@@ -242,7 +239,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
242
239
|
}
|
|
243
240
|
try {
|
|
244
241
|
const serviceObj = await coreApi.createNamespacedService(namespace, service);
|
|
245
|
-
logger.info(`Service created: ${
|
|
242
|
+
logger.info(`Service created: ${serviceObj.body.metadata?.name}`);
|
|
246
243
|
}
|
|
247
244
|
catch (error) {
|
|
248
245
|
handleKubernetesError(error);
|
|
@@ -258,12 +255,12 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
258
255
|
if (service.spec.type === 'ExternalName') {
|
|
259
256
|
continue;
|
|
260
257
|
}
|
|
261
|
-
if (
|
|
258
|
+
if (service.metadata?.labels &&
|
|
262
259
|
appIdLabel in service.metadata.labels &&
|
|
263
260
|
service.metadata.labels[appIdLabel] === appId) {
|
|
264
261
|
const existing = definitions.find((d) => formatServiceName(d.name, appName, appId) === service.metadata.name);
|
|
265
262
|
if (!existing) {
|
|
266
|
-
await deleteCompanionContainers(
|
|
263
|
+
await deleteCompanionContainers(service.metadata?.name);
|
|
267
264
|
}
|
|
268
265
|
}
|
|
269
266
|
}
|
package/container/scale.js
CHANGED
|
@@ -19,7 +19,6 @@ export async function scaleDeployment(namespace, deploymentName, replicas = 0) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
export async function stopIdleContainers(interval = 10) {
|
|
22
|
-
var _a;
|
|
23
22
|
const { appsApi } = getKubeConfig();
|
|
24
23
|
let deployments;
|
|
25
24
|
logger.verbose('Scaling containers');
|
|
@@ -32,7 +31,7 @@ export async function stopIdleContainers(interval = 10) {
|
|
|
32
31
|
}
|
|
33
32
|
for (const deployment of deployments.items) {
|
|
34
33
|
const { annotations, name, namespace } = deployment.metadata;
|
|
35
|
-
if (
|
|
34
|
+
if (deployment.metadata?.namespace !== getContainerNamespace() ||
|
|
36
35
|
deployment.spec.replicas === 0) {
|
|
37
36
|
continue;
|
|
38
37
|
}
|
|
@@ -68,7 +67,6 @@ export async function stopIdleContainers(interval = 10) {
|
|
|
68
67
|
}
|
|
69
68
|
}
|
|
70
69
|
export async function waitForPodReadiness(namespace, appSelector, maxWait = 10000) {
|
|
71
|
-
var _a;
|
|
72
70
|
let isReady;
|
|
73
71
|
const interval = 500;
|
|
74
72
|
let elapsed = 0;
|
|
@@ -76,10 +74,7 @@ export async function waitForPodReadiness(namespace, appSelector, maxWait = 1000
|
|
|
76
74
|
while (!isReady) {
|
|
77
75
|
const pods = await coreApi.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, `app=${appSelector}`);
|
|
78
76
|
if (pods.body.items.length > 0) {
|
|
79
|
-
isReady =
|
|
80
|
-
var _a, _b;
|
|
81
|
-
return (_b = (_a = pod.status) === null || _a === void 0 ? void 0 : _a.conditions) === null || _b === void 0 ? void 0 : _b.some((condition) => condition.type === 'Ready' && condition.status === 'True');
|
|
82
|
-
});
|
|
77
|
+
isReady = pods.body?.items.every((pod) => pod.status?.conditions?.some((condition) => condition.type === 'Ready' && condition.status === 'True'));
|
|
83
78
|
}
|
|
84
79
|
if (!isReady) {
|
|
85
80
|
logger.silly(`Waiting for ${appSelector} to be ready ...`);
|
package/container/specs.js
CHANGED
|
@@ -11,7 +11,6 @@ import { formatEnv, logger, resourceDefaults, validateContainerResources, } from
|
|
|
11
11
|
* @returns `V1Service` and `V1Deployment` spec objects.
|
|
12
12
|
*/
|
|
13
13
|
export function generateDeploymentAndServiceSpecs(definition, name, appName, appId, registry) {
|
|
14
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
15
14
|
let { image, resources } = definition;
|
|
16
15
|
logger.silly(`Using image ${image} ${registry ? `from registry ${registry}` : ''}`);
|
|
17
16
|
if (registry && !image.includes('/')) {
|
|
@@ -24,14 +23,14 @@ export function generateDeploymentAndServiceSpecs(definition, name, appName, app
|
|
|
24
23
|
const podTemplateSpec = {
|
|
25
24
|
metadata: {
|
|
26
25
|
...definition.metadata,
|
|
27
|
-
labels: { app: name, ...
|
|
26
|
+
labels: { app: name, ...definition.metadata?.labels, appId },
|
|
28
27
|
},
|
|
29
28
|
spec: {
|
|
30
29
|
containers: [
|
|
31
30
|
{
|
|
32
31
|
name,
|
|
33
32
|
image,
|
|
34
|
-
ports: [{ containerPort:
|
|
33
|
+
ports: [{ containerPort: definition.port ?? 8080 }],
|
|
35
34
|
env,
|
|
36
35
|
resources: {
|
|
37
36
|
limits: { ...validatedResources.limits },
|
|
@@ -46,7 +45,7 @@ export function generateDeploymentAndServiceSpecs(definition, name, appName, app
|
|
|
46
45
|
replicas: 1,
|
|
47
46
|
selector: {
|
|
48
47
|
matchLabels: { app: name, appId },
|
|
49
|
-
...
|
|
48
|
+
...definition.metadata?.selector,
|
|
50
49
|
},
|
|
51
50
|
template: podTemplateSpec,
|
|
52
51
|
};
|
|
@@ -55,20 +54,20 @@ export function generateDeploymentAndServiceSpecs(definition, name, appName, app
|
|
|
55
54
|
metadata: {
|
|
56
55
|
name,
|
|
57
56
|
...definition.metadata,
|
|
58
|
-
labels: { ...
|
|
57
|
+
labels: { ...definition.metadata?.labels, appId },
|
|
59
58
|
},
|
|
60
59
|
spec: deploymentSpec,
|
|
61
60
|
};
|
|
62
61
|
// Default service type is ClusterIP
|
|
63
62
|
const serviceSpec = {
|
|
64
|
-
selector: { app: name, ...
|
|
65
|
-
ports: [{ port: 80, targetPort:
|
|
63
|
+
selector: { app: name, ...definition.metadata?.selector?.matchLabels, appId },
|
|
64
|
+
ports: [{ port: 80, targetPort: definition.port ?? 8080 }],
|
|
66
65
|
};
|
|
67
66
|
const service = {
|
|
68
67
|
metadata: {
|
|
69
68
|
name,
|
|
70
69
|
...definition.metadata,
|
|
71
|
-
labels: { ...
|
|
70
|
+
labels: { ...definition.metadata?.labels, appId },
|
|
72
71
|
},
|
|
73
72
|
spec: serviceSpec,
|
|
74
73
|
};
|
package/getAppsembleMessages.js
CHANGED
|
@@ -14,7 +14,7 @@ export async function getSupportedLanguages() {
|
|
|
14
14
|
*/
|
|
15
15
|
export async function getAppsembleMessages(language, baseLanguage) {
|
|
16
16
|
const lang = language.toLowerCase();
|
|
17
|
-
const baseLang = baseLanguage
|
|
17
|
+
const baseLang = baseLanguage?.toLowerCase();
|
|
18
18
|
const languages = await getSupportedLanguages();
|
|
19
19
|
const messages = {};
|
|
20
20
|
if (baseLang && languages.has(baseLanguage)) {
|
package/getMessagesUtil.js
CHANGED
|
@@ -3,7 +3,6 @@ import { defaultLocale, extractAppMessages, normalizeBlockName, } from '@appsemb
|
|
|
3
3
|
import tags from 'language-tags';
|
|
4
4
|
import { assertKoaError, throwKoaError } from './koa.js';
|
|
5
5
|
export async function getMessagesUtil(ctx, language, appId, merge, { getApp, getAppMessages, getBlockMessages }, override = 'true') {
|
|
6
|
-
var _a, _b, _c, _d, _e;
|
|
7
6
|
if (!tags.check(language)) {
|
|
8
7
|
throwKoaError(ctx, 400, '`Language “${language}” is invalid`');
|
|
9
8
|
}
|
|
@@ -37,13 +36,13 @@ export async function getMessagesUtil(ctx, language, appId, merge, { getApp, get
|
|
|
37
36
|
const languageMessages = override === 'true' && appMessages.find((m) => m.language === lang);
|
|
38
37
|
for (const block of blockMessages) {
|
|
39
38
|
const { name } = block;
|
|
40
|
-
const defaultMessages =
|
|
41
|
-
const blockBaseLanguageMessages = baseLang &&
|
|
42
|
-
const blockLanguageMessages =
|
|
39
|
+
const defaultMessages = block.messages?.[defaultLocale];
|
|
40
|
+
const blockBaseLanguageMessages = baseLang && block.messages?.[baseLang];
|
|
41
|
+
const blockLanguageMessages = block.messages?.[language];
|
|
43
42
|
const blockVersionMessages = {
|
|
44
43
|
...defaultMessages,
|
|
45
|
-
...Object.fromEntries(Object.entries(blockBaseLanguageMessages
|
|
46
|
-
...Object.fromEntries(Object.entries(blockLanguageMessages
|
|
44
|
+
...Object.fromEntries(Object.entries(blockBaseLanguageMessages ?? {}).filter(([, value]) => value)),
|
|
45
|
+
...Object.fromEntries(Object.entries(blockLanguageMessages ?? {}).filter(([, value]) => value)),
|
|
47
46
|
};
|
|
48
47
|
if (messages.blocks[name]) {
|
|
49
48
|
messages.blocks[name][block.version] = blockVersionMessages;
|
|
@@ -64,7 +63,7 @@ export async function getMessagesUtil(ctx, language, appId, merge, { getApp, get
|
|
|
64
63
|
}
|
|
65
64
|
return {
|
|
66
65
|
language: lang,
|
|
67
|
-
messages: mergeMessages(messages,
|
|
66
|
+
messages: mergeMessages(messages, baseLanguageMessages?.messages ?? {}, languageMessages?.messages ?? {}),
|
|
68
67
|
};
|
|
69
68
|
}
|
|
70
69
|
//# sourceMappingURL=getMessagesUtil.js.map
|
package/logger.js
CHANGED
|
@@ -11,12 +11,11 @@ function headerCase(header) {
|
|
|
11
11
|
return header.replaceAll(/(^|-)\w/g, (a) => a.toUpperCase());
|
|
12
12
|
}
|
|
13
13
|
function httpErrorToString(error) {
|
|
14
|
-
var _a, _b, _c;
|
|
15
14
|
const { config, request, response } = error;
|
|
16
15
|
return [
|
|
17
16
|
chalk.blue.bold('Request:'),
|
|
18
17
|
highlight([
|
|
19
|
-
`${config.method.toUpperCase()} ${axios.getUri(config)} HTTP/${
|
|
18
|
+
`${config.method.toUpperCase()} ${axios.getUri(config)} HTTP/${request?.res?.httpVersion ?? '1.1'}`,
|
|
20
19
|
...Object.entries(config.headers)
|
|
21
20
|
.map(([key, value]) => [headerCase(key), value])
|
|
22
21
|
.map(([key, value]) => `${key}: ${key === 'Authorization' ? 'xxxxxxxxxx' : value}`)
|
|
@@ -26,7 +25,7 @@ function httpErrorToString(error) {
|
|
|
26
25
|
chalk.blue.bold('Response:'),
|
|
27
26
|
response
|
|
28
27
|
? highlight([
|
|
29
|
-
`HTTP/${
|
|
28
|
+
`HTTP/${request.res?.httpVersion} ${response.status} ${response.statusText}`,
|
|
30
29
|
...Object.entries(response.headers)
|
|
31
30
|
.map(([key, value]) => `${headerCase(key)}: ${value}`)
|
|
32
31
|
.sort(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/node-utils",
|
|
3
|
-
"version": "0.30.14-test.
|
|
3
|
+
"version": "0.30.14-test.4",
|
|
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.30.14-test.
|
|
42
|
-
"@appsemble/utils": "0.30.14-test.
|
|
41
|
+
"@appsemble/types": "0.30.14-test.4",
|
|
42
|
+
"@appsemble/utils": "0.30.14-test.4",
|
|
43
43
|
"@formatjs/fast-memoize": "^2.0.0",
|
|
44
44
|
"@fortawesome/fontawesome-free": "^6.0.0",
|
|
45
45
|
"@kubernetes/client-node": "0.21.0",
|
|
@@ -114,6 +114,6 @@
|
|
|
114
114
|
}
|
|
115
115
|
},
|
|
116
116
|
"engines": {
|
|
117
|
-
"node": ">=
|
|
117
|
+
"node": ">=20"
|
|
118
118
|
}
|
|
119
119
|
}
|
package/render.js
CHANGED
|
@@ -38,7 +38,7 @@ export async function render(ctx, filename, data) {
|
|
|
38
38
|
export function makeCSP(csp) {
|
|
39
39
|
return Object.entries(csp)
|
|
40
40
|
.map(([key, values]) => [key, values.filter(Boolean)])
|
|
41
|
-
.filter(([, values]) => values
|
|
41
|
+
.filter(([, values]) => values?.length)
|
|
42
42
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
43
43
|
.map(([key, values]) => `${key} ${[...new Set(values)].sort(compareStrings).join(' ')}`)
|
|
44
44
|
.join('; ');
|
package/resource.js
CHANGED
|
@@ -20,7 +20,6 @@ export function stripResource({ $author, $created, $editor, $ephemeral, $group,
|
|
|
20
20
|
* @returns The matching resource definition.
|
|
21
21
|
*/
|
|
22
22
|
export function getResourceDefinition(appDefinition, resourceType, ctx, view) {
|
|
23
|
-
var _a;
|
|
24
23
|
if (!appDefinition) {
|
|
25
24
|
if (ctx === undefined) {
|
|
26
25
|
throw new Error('App not found');
|
|
@@ -29,7 +28,7 @@ export function getResourceDefinition(appDefinition, resourceType, ctx, view) {
|
|
|
29
28
|
throwKoaError(ctx, 404, 'App not found');
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
|
-
const definition =
|
|
31
|
+
const definition = appDefinition.resources?.[resourceType];
|
|
33
32
|
if (!definition) {
|
|
34
33
|
if (ctx === undefined || ctx.response === undefined) {
|
|
35
34
|
throw new Error(`App does not have resources called ${resourceType}`);
|
|
@@ -59,17 +58,16 @@ export function getResourceDefinition(appDefinition, resourceType, ctx, view) {
|
|
|
59
58
|
* 3. preValidateProperty function used for reconstructing resources from a CSV file.
|
|
60
59
|
*/
|
|
61
60
|
export function extractResourceBody(ctx) {
|
|
62
|
-
var _a, _b;
|
|
63
61
|
let body;
|
|
64
62
|
let assets;
|
|
65
63
|
let preValidateProperty;
|
|
66
|
-
if (
|
|
64
|
+
if (ctx?.request?.body && ctx.is('multipart/form-data')) {
|
|
67
65
|
({ assets = [], resource: body } = ctx.request.body);
|
|
68
66
|
if (Array.isArray(body) && body.length === 1) {
|
|
69
67
|
[body] = body;
|
|
70
68
|
}
|
|
71
69
|
}
|
|
72
|
-
else if (
|
|
70
|
+
else if (ctx?.request?.body) {
|
|
73
71
|
if (ctx.is('text/csv')) {
|
|
74
72
|
preValidateProperty = preProcessCSV;
|
|
75
73
|
}
|
|
@@ -104,7 +102,6 @@ export function extractResourceBody(ctx) {
|
|
|
104
102
|
* 3. Asset IDs from the `knownAssetIds` array which are no longer used.
|
|
105
103
|
*/
|
|
106
104
|
export function processResourceBody(ctx, definition, knownAssetIds = [], knownExpires, knownAssetNameIds = [], isPatch = false) {
|
|
107
|
-
var _a, _b, _c;
|
|
108
105
|
const [resource, assets, preValidateProperty] = extractResourceBody(ctx);
|
|
109
106
|
const validator = new Validator();
|
|
110
107
|
const assetIdMap = new Map();
|
|
@@ -114,7 +111,7 @@ export function processResourceBody(ctx, definition, knownAssetIds = [], knownEx
|
|
|
114
111
|
const regularAssets = [];
|
|
115
112
|
const thumbnailAssetSuffix = '-thumbnail.png';
|
|
116
113
|
for (const asset of assets) {
|
|
117
|
-
if (
|
|
114
|
+
if (asset.filename?.endsWith(thumbnailAssetSuffix)) {
|
|
118
115
|
thumbnailAssets.push(asset);
|
|
119
116
|
}
|
|
120
117
|
else {
|
|
@@ -132,7 +129,7 @@ export function processResourceBody(ctx, definition, knownAssetIds = [], knownEx
|
|
|
132
129
|
const regularAsset = preparedRegularAssets.find((ra) => !usedPreparedRegularAssets.includes(ra.id) &&
|
|
133
130
|
ra.filename.startsWith(filename.replace(thumbnailAssetSuffix, '')));
|
|
134
131
|
const id = regularAsset ? `${regularAsset.id}-thumbnail` : randomUUID();
|
|
135
|
-
usedPreparedRegularAssets.push(regularAsset
|
|
132
|
+
usedPreparedRegularAssets.push(regularAsset?.id);
|
|
136
133
|
assetIdMap.set(index + preparedRegularAssets.length, id);
|
|
137
134
|
assetUsedMap.set(index, false);
|
|
138
135
|
return { data: contents, filename, id, mime };
|
|
@@ -159,7 +156,7 @@ export function processResourceBody(ctx, definition, knownAssetIds = [], knownEx
|
|
|
159
156
|
};
|
|
160
157
|
const patchedSchema = {
|
|
161
158
|
...definition.schema,
|
|
162
|
-
required:
|
|
159
|
+
required: ctx.request?.method === 'PATCH' || isPatch ? [] : definition.schema.required,
|
|
163
160
|
properties: {
|
|
164
161
|
...definition.schema.properties,
|
|
165
162
|
id: { type: 'integer' },
|
|
@@ -178,7 +175,7 @@ export function processResourceBody(ctx, definition, knownAssetIds = [], knownEx
|
|
|
178
175
|
type: 'array',
|
|
179
176
|
items: { type: 'string', format: 'binary' },
|
|
180
177
|
},
|
|
181
|
-
...Object.fromEntries(Object.values(
|
|
178
|
+
...Object.fromEntries(Object.values(definition.references ?? {}).map((reference) => [
|
|
182
179
|
`$${reference.resource}`,
|
|
183
180
|
{ type: 'integer' },
|
|
184
181
|
])),
|
|
@@ -21,10 +21,10 @@ export function createCountAppResourcesController(options) {
|
|
|
21
21
|
{
|
|
22
22
|
type: resourceType,
|
|
23
23
|
AppId: appId,
|
|
24
|
-
GroupId: selectedGroupId
|
|
24
|
+
GroupId: selectedGroupId ?? null,
|
|
25
25
|
expires: { or: [{ gt: new Date() }, null] },
|
|
26
26
|
...(app.demoMode ? { seed: false, ephemeral: true } : {}),
|
|
27
|
-
...($own ? { AuthorId: authSubject
|
|
27
|
+
...($own ? { AuthorId: authSubject?.id } : {}),
|
|
28
28
|
},
|
|
29
29
|
],
|
|
30
30
|
},
|
|
@@ -32,13 +32,12 @@ export function createCreateAppResourceController(options) {
|
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
const resources = Array.isArray(processedBody) ? processedBody : [processedBody];
|
|
35
|
-
if (!(ctx.client && 'app' in ctx.client) &&
|
|
35
|
+
if (!(ctx.client && 'app' in ctx.client) && query?.seed === 'true') {
|
|
36
36
|
const preparedSeedAssets = structuredClone(preparedAssets);
|
|
37
37
|
const preparedSeedResources = resources.map((resource) => {
|
|
38
|
-
var _a;
|
|
39
38
|
const cleanResource = { ...resource };
|
|
40
39
|
if (app.demoMode) {
|
|
41
|
-
for (const referencedProperty of Object.keys(
|
|
40
|
+
for (const referencedProperty of Object.keys(resourceDefinition.references ?? {})) {
|
|
42
41
|
delete cleanResource[referencedProperty];
|
|
43
42
|
}
|
|
44
43
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { assertKoaError } from '@appsemble/node-utils';
|
|
2
2
|
export function createDeleteAppResourceController(options) {
|
|
3
3
|
return async (ctx) => {
|
|
4
|
-
var _a;
|
|
5
4
|
const { pathParams: { appId, resourceId, resourceType }, queryParams: { selectedGroupId }, user: authSubject, } = ctx;
|
|
6
5
|
const { checkAppPermissions, deleteAppResource, getApp, getAppResource } = options;
|
|
7
6
|
const app = await getApp({ context: ctx, query: { where: { id: appId } } });
|
|
@@ -10,7 +9,7 @@ export function createDeleteAppResourceController(options) {
|
|
|
10
9
|
id: resourceId,
|
|
11
10
|
type: resourceType,
|
|
12
11
|
AppId: appId,
|
|
13
|
-
GroupId: selectedGroupId
|
|
12
|
+
GroupId: selectedGroupId ?? null,
|
|
14
13
|
expires: { or: [{ gt: new Date() }, { eq: null }] },
|
|
15
14
|
...(app.demoMode ? { seed: false, ephemeral: true } : {}),
|
|
16
15
|
},
|
|
@@ -26,7 +25,7 @@ export function createDeleteAppResourceController(options) {
|
|
|
26
25
|
await checkAppPermissions({
|
|
27
26
|
context: ctx,
|
|
28
27
|
permissions: [
|
|
29
|
-
|
|
28
|
+
resource.$author?.id === authSubject.id
|
|
30
29
|
? `$resource:${resourceType}:own:delete`
|
|
31
30
|
: `$resource:${resourceType}:delete`,
|
|
32
31
|
],
|
|
@@ -2,7 +2,6 @@ import { assertKoaError, getRemapperContext, getResourceDefinition, } from '@app
|
|
|
2
2
|
import { defaultLocale, remap } from '@appsemble/utils';
|
|
3
3
|
export function createGetAppResourceByIdController(options) {
|
|
4
4
|
return async (ctx) => {
|
|
5
|
-
var _a;
|
|
6
5
|
const { pathParams: { appId, resourceId, resourceType }, queryParams: { selectedGroupId, view }, user: authSubject, } = ctx;
|
|
7
6
|
const { checkAppPermissions, getApp, getAppResource } = options;
|
|
8
7
|
const app = await getApp({ context: ctx, query: { where: { id: appId } } });
|
|
@@ -11,7 +10,7 @@ export function createGetAppResourceByIdController(options) {
|
|
|
11
10
|
id: resourceId,
|
|
12
11
|
type: resourceType,
|
|
13
12
|
AppId: appId,
|
|
14
|
-
GroupId: selectedGroupId
|
|
13
|
+
GroupId: selectedGroupId ?? null,
|
|
15
14
|
expires: { or: [{ gt: new Date() }, null] },
|
|
16
15
|
...(app.demoMode ? { seed: false, ephemeral: true } : {}),
|
|
17
16
|
},
|
|
@@ -27,7 +26,7 @@ export function createGetAppResourceByIdController(options) {
|
|
|
27
26
|
await checkAppPermissions({
|
|
28
27
|
context: ctx,
|
|
29
28
|
permissions: [
|
|
30
|
-
|
|
29
|
+
resource.$author?.id === authSubject?.id
|
|
31
30
|
? `$resource:${resourceType}:own:get`
|
|
32
31
|
: view
|
|
33
32
|
? `$resource:${resourceType}:get:${view}`
|
|
@@ -3,7 +3,6 @@ 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) => {
|
|
6
|
-
var _a, _b;
|
|
7
6
|
const { pathParams: { appId, resourceType }, queryParams: { $own, $select, $skip, $top, selectedGroupId, view }, user: authSubject, } = ctx;
|
|
8
7
|
const { checkAppPermissions, getApp, getAppResources } = options;
|
|
9
8
|
const app = await getApp({ context: ctx, query: { where: { id: appId } } });
|
|
@@ -21,21 +20,21 @@ export function createQueryAppResourcesController(options) {
|
|
|
21
20
|
app,
|
|
22
21
|
groupId: selectedGroupId,
|
|
23
22
|
});
|
|
24
|
-
const isSameOrigin =
|
|
23
|
+
const isSameOrigin = ctx?.headers?.origin === ctx?.headers?.host;
|
|
25
24
|
const findOptions = {
|
|
26
25
|
limit: $top,
|
|
27
26
|
offset: $skip,
|
|
28
|
-
attributes: $select
|
|
27
|
+
attributes: $select?.split(',').map((s) => s.trim()),
|
|
29
28
|
where: {
|
|
30
29
|
and: [
|
|
31
30
|
where,
|
|
32
31
|
{
|
|
33
32
|
type: resourceType,
|
|
34
33
|
AppId: appId,
|
|
35
|
-
GroupId: selectedGroupId
|
|
34
|
+
GroupId: selectedGroupId ?? null,
|
|
36
35
|
expires: { or: [{ gt: new Date() }, null] },
|
|
37
36
|
...(app.demoMode && !isSameOrigin ? { seed: false, ephemeral: true } : {}),
|
|
38
|
-
...($own ? { AuthorId: authSubject
|
|
37
|
+
...($own ? { AuthorId: authSubject?.id } : {}),
|
|
39
38
|
},
|
|
40
39
|
],
|
|
41
40
|
},
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { assertKoaError, getResourceDefinition, processResourceBody, } from '@appsemble/node-utils';
|
|
2
2
|
export function createUpdateAppResourceController(options) {
|
|
3
3
|
return async (ctx) => {
|
|
4
|
-
var _a;
|
|
5
4
|
const { pathParams: { appId, resourceId, resourceType }, queryParams: { selectedGroupId }, user: authSubject, } = ctx;
|
|
6
5
|
const { checkAppPermissions, getApp, getAppAssets, getAppResource, updateAppResource } = options;
|
|
7
6
|
const app = await getApp({ context: ctx, query: { where: { id: appId } } });
|
|
@@ -10,7 +9,7 @@ export function createUpdateAppResourceController(options) {
|
|
|
10
9
|
id: resourceId,
|
|
11
10
|
type: resourceType,
|
|
12
11
|
AppId: appId,
|
|
13
|
-
GroupId: selectedGroupId
|
|
12
|
+
GroupId: selectedGroupId ?? null,
|
|
14
13
|
expires: { or: [{ gt: new Date() }, null] },
|
|
15
14
|
...(app.demoMode ? { seed: false, ephemeral: true } : {}),
|
|
16
15
|
},
|
|
@@ -26,7 +25,7 @@ export function createUpdateAppResourceController(options) {
|
|
|
26
25
|
await checkAppPermissions({
|
|
27
26
|
context: ctx,
|
|
28
27
|
permissions: [
|
|
29
|
-
|
|
28
|
+
oldResource.$author?.id === authSubject?.id
|
|
30
29
|
? `$resource:${resourceType}:own:update`
|
|
31
30
|
: `$resource:${resourceType}:update`,
|
|
32
31
|
],
|
|
@@ -2,12 +2,11 @@ import { assertKoaError } from '../../../../../koa.js';
|
|
|
2
2
|
import { deleteResourcesRecursively } from '../../../../utils/resources.js';
|
|
3
3
|
export function createDeleteAppSeedResourcesController(options) {
|
|
4
4
|
return async (ctx) => {
|
|
5
|
-
var _a;
|
|
6
5
|
const { pathParams: { appId }, } = ctx;
|
|
7
6
|
const { getApp } = options;
|
|
8
7
|
const app = await getApp({ context: ctx, query: { where: { id: appId } } });
|
|
9
8
|
assertKoaError(!app, ctx, 404, 'App not found');
|
|
10
|
-
for (const resourceType of Object.keys(
|
|
9
|
+
for (const resourceType of Object.keys(app.definition.resources ?? {})) {
|
|
11
10
|
await deleteResourcesRecursively(resourceType, app, options, ctx);
|
|
12
11
|
}
|
|
13
12
|
};
|
|
@@ -88,7 +88,7 @@ export function createBulmaHandler({ createTheme, getTheme }) {
|
|
|
88
88
|
fontSource: getQueryParameter(query.fontSource) || baseTheme.font.source,
|
|
89
89
|
};
|
|
90
90
|
const result = await getTheme({ theme });
|
|
91
|
-
let css = result
|
|
91
|
+
let css = result?.css;
|
|
92
92
|
if (!css) {
|
|
93
93
|
css = stripBom(String(renderSync({
|
|
94
94
|
data: processStyle(theme),
|
|
@@ -10,7 +10,7 @@ export function createIconHandler({ getApp, getAppIcon, getDbUpdated }) {
|
|
|
10
10
|
const dbUpdated = app ? await getDbUpdated({ app, maskable, context: ctx }) : false;
|
|
11
11
|
const appIcon = app ? await getAppIcon({ app, context: ctx }) : null;
|
|
12
12
|
await serveIcon(ctx, {
|
|
13
|
-
background: maskable ?
|
|
13
|
+
background: maskable ? app?.iconBackground || '#ffffff' : undefined,
|
|
14
14
|
cache: dbUpdated ? isEqual(parseISO(updated), dbUpdated) : false,
|
|
15
15
|
fallback: 'mobile-alt-solid.png',
|
|
16
16
|
height: size && Number.parseInt(size),
|
|
@@ -7,7 +7,6 @@ export const bulmaURL = `/bulma/${bulmaVersion}/bulma.min.css`;
|
|
|
7
7
|
export const faURL = `/fa/${faVersion}/css/all.min.css`;
|
|
8
8
|
export function createIndexHandler({ createSettings, getApp, getAppDetails, getAppMessages, getAppUrl, getCsp, getHost, }) {
|
|
9
9
|
return async (ctx) => {
|
|
10
|
-
var _a;
|
|
11
10
|
const { hostname, path } = ctx;
|
|
12
11
|
const host = getHost({ context: ctx });
|
|
13
12
|
const app = await getApp({ context: ctx });
|
|
@@ -61,7 +60,7 @@ export function createIndexHandler({ createSettings, getApp, getAppDetails, getA
|
|
|
61
60
|
faURL,
|
|
62
61
|
nonce,
|
|
63
62
|
settings,
|
|
64
|
-
themeColor:
|
|
63
|
+
themeColor: app.definition.theme?.themeColor || '#ffffff',
|
|
65
64
|
appUpdated: updated.toISOString(),
|
|
66
65
|
});
|
|
67
66
|
};
|
package/server/utils/actions.js
CHANGED
|
@@ -60,7 +60,6 @@ function deserializeResource(data) {
|
|
|
60
60
|
return replaceAssets(resource);
|
|
61
61
|
}
|
|
62
62
|
async function handleRequestProxy(ctx, app, action, useBody, options) {
|
|
63
|
-
var _a, _b;
|
|
64
63
|
const { method, query, request: { body, headers }, } = ctx;
|
|
65
64
|
let data;
|
|
66
65
|
if (useBody) {
|
|
@@ -97,7 +96,7 @@ async function handleRequestProxy(ctx, app, action, useBody, options) {
|
|
|
97
96
|
throwKoaError(ctx, 400, 'params should be a JSON object.');
|
|
98
97
|
}
|
|
99
98
|
let axiosConfig = {
|
|
100
|
-
method:
|
|
99
|
+
method: action.method ?? 'GET',
|
|
101
100
|
url: String(proxyUrl),
|
|
102
101
|
params,
|
|
103
102
|
responseType: 'arraybuffer',
|
|
@@ -114,6 +113,7 @@ async function handleRequestProxy(ctx, app, action, useBody, options) {
|
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
axiosConfig.headers['user-agent'] = `AppsembleServer/${version}`;
|
|
116
|
+
axiosConfig.headers.connection = 'close';
|
|
117
117
|
axiosConfig.responseType = 'stream';
|
|
118
118
|
axiosConfig.validateStatus = () => true;
|
|
119
119
|
axiosConfig.decompress = false;
|
|
@@ -139,7 +139,7 @@ async function handleRequestProxy(ctx, app, action, useBody, options) {
|
|
|
139
139
|
const { deploymentName, namespace } = parseServiceUrl(String(proxyUrl));
|
|
140
140
|
try {
|
|
141
141
|
await scaleDeployment(namespace, deploymentName, 1);
|
|
142
|
-
await waitForPodReadiness(namespace, deploymentName,
|
|
142
|
+
await waitForPodReadiness(namespace, deploymentName, process.env.POD_READINESS_TIMEOUT ?? undefined);
|
|
143
143
|
response = await axios(axiosConfig);
|
|
144
144
|
}
|
|
145
145
|
catch {
|
|
@@ -165,7 +165,7 @@ export function createProxyHandler(useBody, options) {
|
|
|
165
165
|
const app = await options.getApp({ context: ctx, query: { where: { id: appId } } });
|
|
166
166
|
assertKoaError(!app, ctx, 404, 'App not found');
|
|
167
167
|
const appAction = get(app.definition, path);
|
|
168
|
-
const action = supportedActions.find((act) => act ===
|
|
168
|
+
const action = supportedActions.find((act) => act === appAction?.type);
|
|
169
169
|
switch (action) {
|
|
170
170
|
case 'email':
|
|
171
171
|
return handleEmail(ctx, app, appAction, options);
|
|
@@ -18,10 +18,7 @@ export function generateResourceQuery(ctx, { parseQuery }, resourceDefinition) {
|
|
|
18
18
|
}
|
|
19
19
|
export async function deleteResourcesRecursively(type, app, options, context) {
|
|
20
20
|
const { deleteAppResource, getAppResources } = options;
|
|
21
|
-
const referencingResources = Object.entries(app.definition.resources).filter(([, resourceDefinition]) => {
|
|
22
|
-
var _a;
|
|
23
|
-
return Object.values((_a = resourceDefinition.references) !== null && _a !== void 0 ? _a : {}).find((resourceReference) => resourceReference.resource === type);
|
|
24
|
-
});
|
|
21
|
+
const referencingResources = Object.entries(app.definition.resources).filter(([, resourceDefinition]) => Object.values(resourceDefinition.references ?? {}).find((resourceReference) => resourceReference.resource === type));
|
|
25
22
|
for (const [referencingResourceType] of referencingResources) {
|
|
26
23
|
await deleteResourcesRecursively(referencingResourceType, app, options, context);
|
|
27
24
|
}
|
package/tinyRouter.js
CHANGED
|
@@ -27,7 +27,7 @@ export function tinyRouter(routes) {
|
|
|
27
27
|
}
|
|
28
28
|
m = 'any';
|
|
29
29
|
}
|
|
30
|
-
ctx.params =
|
|
30
|
+
ctx.params = match?.groups ? { ...match.groups } : null;
|
|
31
31
|
return result[m](ctx, next);
|
|
32
32
|
};
|
|
33
33
|
}
|