@appsemble/node-utils 0.36.5-test.6 → 0.36.6-test.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.
- package/README.md +3 -3
- package/createUser.d.ts +2 -1
- package/createUser.js +12 -1
- package/package.json +4 -4
- package/resource.d.ts +6 -2
- package/resource.js +32 -8
- package/server/routes/appRouter/blockAssetHandler.js +1 -0
- package/server/routes/appRouter/index.js +1 -1
- package/server/routes/appRouter/serviceWorkerHandler.d.ts +1 -2
- package/server/routes/appRouter/serviceWorkerHandler.js +2 -12
- package/server/types.d.ts +13 -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.36.6-test.0)
|
|
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.36.
|
|
29
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.36.6-test.0/LICENSE.md) ©
|
|
30
30
|
[Appsemble](https://appsemble.com)
|
package/createUser.d.ts
CHANGED
|
@@ -6,5 +6,6 @@
|
|
|
6
6
|
* @param password Password
|
|
7
7
|
* @param timezone Timezone of the user
|
|
8
8
|
* @param clientCredentials Used to make OAuth client credentials for permissions
|
|
9
|
+
* @param organization Optional organization id to add the user to if it exists
|
|
9
10
|
*/
|
|
10
|
-
export declare function createUser(name: string, email: string, password: string, timezone?: string, clientCredentials?: string): Promise<void>;
|
|
11
|
+
export declare function createUser(name: string, email: string, password: string, timezone?: string, clientCredentials?: string, organization?: string): Promise<void>;
|
package/createUser.js
CHANGED
|
@@ -16,8 +16,9 @@ async function insert(table, columns, values, client) {
|
|
|
16
16
|
* @param password Password
|
|
17
17
|
* @param timezone Timezone of the user
|
|
18
18
|
* @param clientCredentials Used to make OAuth client credentials for permissions
|
|
19
|
+
* @param organization Optional organization id to add the user to if it exists
|
|
19
20
|
*/
|
|
20
|
-
export async function createUser(name, email, password, timezone, clientCredentials) {
|
|
21
|
+
export async function createUser(name, email, password, timezone, clientCredentials, organization) {
|
|
21
22
|
if (!DATABASE_HOST || !DATABASE_NAME || !DATABASE_PASSWORD || !DATABASE_PORT || !DATABASE_USER) {
|
|
22
23
|
throw new Error('Missing database credentials');
|
|
23
24
|
}
|
|
@@ -33,6 +34,16 @@ export async function createUser(name, email, password, timezone, clientCredenti
|
|
|
33
34
|
const userId = uuid();
|
|
34
35
|
await insert('User', ['id', 'name', '"primaryEmail"', 'password', 'timezone', 'created', 'updated'], [userId, name, email, hashedPassword, timezone ?? 'Europe/Amsterdam', 'NOW()', 'NOW()'], client);
|
|
35
36
|
await insert('EmailAuthorization', ['email', 'verified', 'created', 'updated', '"UserId"'], [email, true, 'NOW()', 'NOW()', userId], client);
|
|
37
|
+
const organizationIds = new Set(['appsemble']);
|
|
38
|
+
if (organization) {
|
|
39
|
+
organizationIds.add(organization);
|
|
40
|
+
}
|
|
41
|
+
for (const organizationId of organizationIds) {
|
|
42
|
+
const organizationResult = await client.query('SELECT id FROM "Organization" WHERE id = $1', [organizationId]);
|
|
43
|
+
if (organizationResult.rows.length > 0) {
|
|
44
|
+
await insert('OrganizationMember', ['"OrganizationId"', '"UserId"', 'role', 'created', 'updated'], [organizationId, userId, 'Maintainer', 'NOW()', 'NOW()'], client);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
36
47
|
if (clientCredentials) {
|
|
37
48
|
const [clientId, clientPassword] = clientCredentials.split(':');
|
|
38
49
|
const hashedClientPassword = await hash(clientPassword, 10);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/node-utils",
|
|
3
|
-
"version": "0.36.
|
|
3
|
+
"version": "0.36.6-test.0",
|
|
4
4
|
"description": "NodeJS utilities used by Appsemble internally.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"test": "vitest"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@appsemble/lang-sdk": "0.36.
|
|
44
|
-
"@appsemble/types": "0.36.
|
|
45
|
-
"@appsemble/utils": "0.36.
|
|
43
|
+
"@appsemble/lang-sdk": "0.36.6-test.0",
|
|
44
|
+
"@appsemble/types": "0.36.6-test.0",
|
|
45
|
+
"@appsemble/utils": "0.36.6-test.0",
|
|
46
46
|
"@formatjs/fast-memoize": "^2.0.0",
|
|
47
47
|
"@fortawesome/fontawesome-free": "^6.0.0",
|
|
48
48
|
"@kubernetes/client-node": "1.4.0",
|
package/resource.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare function serializeServerResource(data: any): JsonValue | {
|
|
|
16
16
|
resource: JsonValue;
|
|
17
17
|
assets: TempFile[];
|
|
18
18
|
};
|
|
19
|
+
export type SerializedServerResourceBody = ReturnType<typeof serializeServerResource>;
|
|
19
20
|
/**
|
|
20
21
|
* Get the resource definition of an app by name.
|
|
21
22
|
*
|
|
@@ -32,13 +33,15 @@ export declare function getResourceDefinition(appDefinition: AppDefinition, reso
|
|
|
32
33
|
* Extracts the IDs of resource request body.
|
|
33
34
|
*
|
|
34
35
|
* @param ctx The Koa context to extract the body from.
|
|
36
|
+
* @param suppliedBody A resource body to use directly without reading from context.
|
|
37
|
+
* Supports multipart-style `{ resource, assets }` input.
|
|
35
38
|
* @returns A tuple which consists of:
|
|
36
39
|
*
|
|
37
40
|
* 1. One or more resources processed from the request body.
|
|
38
41
|
* 2. A list of newly uploaded assets which should be linked to the resources.
|
|
39
42
|
* 3. preValidateProperty function used for reconstructing resources from a CSV file.
|
|
40
43
|
*/
|
|
41
|
-
export declare function extractResourceBody(ctx: Context | ParameterizedContext<DefaultState, DefaultContext, any>): [
|
|
44
|
+
export declare function extractResourceBody(ctx: Context | ParameterizedContext<DefaultState, DefaultContext, any> | undefined, suppliedBody?: SerializedServerResourceBody): [
|
|
42
45
|
Record<string, unknown> | Record<string, unknown>[],
|
|
43
46
|
TempFile[],
|
|
44
47
|
PreValidatePropertyFunction | undefined
|
|
@@ -54,6 +57,7 @@ export declare function extractResourceBody(ctx: Context | ParameterizedContext<
|
|
|
54
57
|
* @param knownExpires A previously known expires value.
|
|
55
58
|
* @param knownAssetNameIds A list of asset ids with asset names that already exist.
|
|
56
59
|
* @param [isPatch] if the "PATCH" HTTP method is being used.
|
|
60
|
+
* @param resourceBody Used to process resources from non-request contexts.
|
|
57
61
|
* @returns A tuple which consists of:
|
|
58
62
|
*
|
|
59
63
|
* 1. One or more resources processed from the request body.
|
|
@@ -63,4 +67,4 @@ export declare function extractResourceBody(ctx: Context | ParameterizedContext<
|
|
|
63
67
|
export declare function processResourceBody(ctx: Context | ParameterizedContext<DefaultState, DefaultContext, any>, definition: ResourceDefinition, knownAssetIds?: string[], knownExpires?: Date, knownAssetNameIds?: {
|
|
64
68
|
id: string;
|
|
65
69
|
name?: string;
|
|
66
|
-
}[], isPatch?: boolean): [Record<string, unknown> | Record<string, unknown>[], PreparedAsset[], string[]];
|
|
70
|
+
}[], isPatch?: boolean, resourceBody?: SerializedServerResourceBody): [Record<string, unknown> | Record<string, unknown>[], PreparedAsset[], string[]];
|
package/resource.js
CHANGED
|
@@ -43,6 +43,14 @@ export function serializeServerResource(data) {
|
|
|
43
43
|
assets,
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
+
function isSerializedMultipartBody(value) {
|
|
47
|
+
return (value != null &&
|
|
48
|
+
typeof value === 'object' &&
|
|
49
|
+
!Array.isArray(value) &&
|
|
50
|
+
'resource' in value &&
|
|
51
|
+
'assets' in value &&
|
|
52
|
+
Array.isArray(value.assets));
|
|
53
|
+
}
|
|
46
54
|
/**
|
|
47
55
|
* Get the resource definition of an app by name.
|
|
48
56
|
*
|
|
@@ -86,17 +94,31 @@ export function getResourceDefinition(appDefinition, resourceType, ctx, view) {
|
|
|
86
94
|
* Extracts the IDs of resource request body.
|
|
87
95
|
*
|
|
88
96
|
* @param ctx The Koa context to extract the body from.
|
|
97
|
+
* @param suppliedBody A resource body to use directly without reading from context.
|
|
98
|
+
* Supports multipart-style `{ resource, assets }` input.
|
|
89
99
|
* @returns A tuple which consists of:
|
|
90
100
|
*
|
|
91
101
|
* 1. One or more resources processed from the request body.
|
|
92
102
|
* 2. A list of newly uploaded assets which should be linked to the resources.
|
|
93
103
|
* 3. preValidateProperty function used for reconstructing resources from a CSV file.
|
|
94
104
|
*/
|
|
95
|
-
export function extractResourceBody(ctx) {
|
|
105
|
+
export function extractResourceBody(ctx, suppliedBody) {
|
|
96
106
|
let body;
|
|
97
|
-
let assets;
|
|
107
|
+
let assets = [];
|
|
98
108
|
let preValidateProperty;
|
|
99
|
-
if (
|
|
109
|
+
if (suppliedBody !== undefined) {
|
|
110
|
+
if (isSerializedMultipartBody(suppliedBody)) {
|
|
111
|
+
assets = suppliedBody.assets;
|
|
112
|
+
body = suppliedBody.resource;
|
|
113
|
+
if (Array.isArray(body) && body.length === 1) {
|
|
114
|
+
[body] = body;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
body = suppliedBody;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else if (ctx?.request?.body && ctx.is('multipart/form-data')) {
|
|
100
122
|
({ assets = [], resource: body } = ctx.request.body);
|
|
101
123
|
if (Array.isArray(body) && body.length === 1) {
|
|
102
124
|
[body] = body;
|
|
@@ -107,11 +129,12 @@ export function extractResourceBody(ctx) {
|
|
|
107
129
|
preValidateProperty = preProcessCSV;
|
|
108
130
|
}
|
|
109
131
|
({ body } = ctx.request);
|
|
110
|
-
assets = [];
|
|
111
132
|
}
|
|
112
|
-
else {
|
|
133
|
+
else if (ctx) {
|
|
113
134
|
({ body } = ctx);
|
|
114
|
-
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
throw new Error('No resource body provided.');
|
|
115
138
|
}
|
|
116
139
|
return [
|
|
117
140
|
Array.isArray(body) ? body.map(stripResource) : stripResource(body),
|
|
@@ -131,14 +154,15 @@ export function extractResourceBody(ctx) {
|
|
|
131
154
|
* @param knownExpires A previously known expires value.
|
|
132
155
|
* @param knownAssetNameIds A list of asset ids with asset names that already exist.
|
|
133
156
|
* @param [isPatch] if the "PATCH" HTTP method is being used.
|
|
157
|
+
* @param resourceBody Used to process resources from non-request contexts.
|
|
134
158
|
* @returns A tuple which consists of:
|
|
135
159
|
*
|
|
136
160
|
* 1. One or more resources processed from the request body.
|
|
137
161
|
* 2. A list of newly uploaded assets which should be linked to the resources.
|
|
138
162
|
* 3. Asset IDs from the `knownAssetIds` array which are no longer used.
|
|
139
163
|
*/
|
|
140
|
-
export function processResourceBody(ctx, definition, knownAssetIds = [], knownExpires, knownAssetNameIds = [], isPatch = false) {
|
|
141
|
-
const [resource, assets, preValidateProperty] = extractResourceBody(ctx);
|
|
164
|
+
export function processResourceBody(ctx, definition, knownAssetIds = [], knownExpires, knownAssetNameIds = [], isPatch = false, resourceBody) {
|
|
165
|
+
const [resource, assets, preValidateProperty] = extractResourceBody(ctx, resourceBody);
|
|
142
166
|
const validator = new Validator();
|
|
143
167
|
const reusedAssets = new Set();
|
|
144
168
|
const usedAssetIndices = new Set();
|
|
@@ -6,6 +6,7 @@ export function createBlockAssetHandler({ getBlockAsset }) {
|
|
|
6
6
|
params: { filename, name, version }, } = ctx;
|
|
7
7
|
const blockAsset = await getBlockAsset({ filename, name, version, context: ctx });
|
|
8
8
|
assertKoaCondition(blockAsset != null, ctx, 404, 'Block asset not found');
|
|
9
|
+
ctx.set('Cache-Control', 'max-age=31536000,immutable');
|
|
9
10
|
ctx.body = blockAsset.content;
|
|
10
11
|
ctx.type = blockAsset.mime;
|
|
11
12
|
};
|
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
|
|
3
|
-
import { assertKoaCondition } from '@appsemble/node-utils';
|
|
4
|
-
export function createServiceWorkerHandler({ getApp, getBlocksAssetsPaths }) {
|
|
2
|
+
export function createServiceWorkerHandler() {
|
|
5
3
|
return async (ctx) => {
|
|
6
4
|
const production = process.env.NODE_ENV === 'production';
|
|
7
5
|
const filename = production ? '/service-worker.js' : '/app/service-worker.js';
|
|
8
6
|
const serviceWorker = await (production
|
|
9
7
|
? readFile(new URL('../../../../../dist/app/service-worker.js', import.meta.url), 'utf8')
|
|
10
8
|
: ctx.fs.promises.readFile(filename, 'utf8'));
|
|
11
|
-
|
|
12
|
-
context: ctx,
|
|
13
|
-
query: { attributes: ['id', 'definition'] },
|
|
14
|
-
});
|
|
15
|
-
assertKoaCondition(app != null, ctx, 404, 'App does not exist.');
|
|
16
|
-
const identifiableBlocks = getAppBlocks(app.definition);
|
|
17
|
-
const blocksAssetsPaths = await getBlocksAssetsPaths({ identifiableBlocks, context: ctx });
|
|
18
|
-
// App.version is a virtual column and comes from App.AppSnapshots
|
|
19
|
-
ctx.body = `const appVersion = ${app.version};const blockAssets=${JSON.stringify(blocksAssetsPaths)};${serviceWorker}`;
|
|
9
|
+
ctx.body = serviceWorker;
|
|
20
10
|
ctx.type = 'application/javascript';
|
|
21
11
|
};
|
|
22
12
|
}
|
package/server/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Readable } from 'node:stream';
|
|
2
|
-
import { type AppMemberGroup, type BlockDefinition, type ControllerDefinition, type CustomAppPermission, type EmailActionDefinition, type IdentifiableBlock, type ResourceDefinition, type Theme as ThemeType } from '@appsemble/lang-sdk';
|
|
2
|
+
import { type ActionDefinition, type AppMemberGroup, type BlockDefinition, type ControllerDefinition, type CustomAppPermission, type EmailActionDefinition, type IdentifiableBlock, type ResourceDefinition, type Theme as ThemeType } from '@appsemble/lang-sdk';
|
|
3
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';
|
|
@@ -332,6 +332,16 @@ export interface SendNotificationsParams {
|
|
|
332
332
|
body: string;
|
|
333
333
|
link: string;
|
|
334
334
|
}
|
|
335
|
+
export interface HandleActionParams {
|
|
336
|
+
app: App;
|
|
337
|
+
action: ActionDefinition;
|
|
338
|
+
mailer: any;
|
|
339
|
+
data: any;
|
|
340
|
+
options: Options;
|
|
341
|
+
context: ParameterizedContext<DefaultState, DefaultContextInterface, any>;
|
|
342
|
+
}
|
|
343
|
+
export type ServerAction = (params: HandleActionParams) => Promise<any>;
|
|
344
|
+
export type ServerActions = Partial<Record<ActionDefinition['type'], ServerAction>>;
|
|
335
345
|
export interface AppDetails {
|
|
336
346
|
appPath: string;
|
|
337
347
|
organizationId: string;
|
|
@@ -416,6 +426,8 @@ export interface Options {
|
|
|
416
426
|
email: (params: EmailParams) => Promise<void>;
|
|
417
427
|
sendNotifications: (params: SendNotificationsParams) => Promise<void>;
|
|
418
428
|
getAppVariables: (params: GetAppVariablesParams) => Promise<AppConfigEntry[]>;
|
|
429
|
+
handleAction?: (serverAction: ServerAction, params: HandleActionParams) => Promise<any>;
|
|
430
|
+
serverActions?: ServerActions;
|
|
419
431
|
}
|
|
420
432
|
export declare class TempFile {
|
|
421
433
|
readonly filename: string;
|