@appsemble/node-utils 0.36.5-test.6 → 0.36.5

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.36.5-test.6/config/assets/logo.svg) Appsemble Node Utilities
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.36.5/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.36.5-test.6/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.36.5-test.6)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.36.5/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.36.5)
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.36.5-test.6/LICENSE.md) ©
29
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.36.5/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.5-test.6",
3
+ "version": "0.36.5",
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.5-test.6",
44
- "@appsemble/types": "0.36.5-test.6",
45
- "@appsemble/utils": "0.36.5-test.6",
43
+ "@appsemble/lang-sdk": "0.36.5",
44
+ "@appsemble/types": "0.36.5",
45
+ "@appsemble/utils": "0.36.5",
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 (ctx?.request?.body && ctx.is('multipart/form-data')) {
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
- assets = [];
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();
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;