@kinevolution/appwrite-functions-shared-utils 0.1.2
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/dist/utils.d.ts +29 -0
- package/dist/utils.js +117 -0
- package/package.json +38 -0
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
method: Method;
|
|
3
|
+
fields: Array<FieldDefinition>;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Validates the input of an Appwrite function based on the provided configuration
|
|
7
|
+
* @param config - The configuration defining expected method and fields
|
|
8
|
+
* @param req - The Appwrite function request object
|
|
9
|
+
* @returns An object containing the validation result
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateInput(config: Config, req: any): ValidationResult;
|
|
12
|
+
type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
13
|
+
interface FieldDefinition {
|
|
14
|
+
key: string;
|
|
15
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
16
|
+
required: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface ValidationResult {
|
|
19
|
+
valid: boolean;
|
|
20
|
+
data?: any;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface AppwriteContext {
|
|
24
|
+
req: any;
|
|
25
|
+
res: any;
|
|
26
|
+
log: (message: string) => void;
|
|
27
|
+
error: (message: string) => void;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates the input of an Appwrite function based on the provided configuration
|
|
3
|
+
* @param config - The configuration defining expected method and fields
|
|
4
|
+
* @param req - The Appwrite function request object
|
|
5
|
+
* @returns An object containing the validation result
|
|
6
|
+
*/
|
|
7
|
+
export function validateInput(config, req) {
|
|
8
|
+
// Check that the request method matches
|
|
9
|
+
if (req.method !== config.method) {
|
|
10
|
+
return {
|
|
11
|
+
valid: false,
|
|
12
|
+
error: `Invalid request method: expected ${config.method}, received ${req.method}`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
// Check that the body exists (if this is a POST, PATCH or PUT request)
|
|
16
|
+
if (config.method === 'POST' ||
|
|
17
|
+
config.method === 'PUT' ||
|
|
18
|
+
config.method === 'PATCH') {
|
|
19
|
+
if (!req.bodyJson) {
|
|
20
|
+
return {
|
|
21
|
+
valid: false,
|
|
22
|
+
error: 'No body provided in the request',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
// Validate the request body
|
|
26
|
+
const validation = validateRequestBody(req.bodyJson, config.fields);
|
|
27
|
+
if (validation.valid) {
|
|
28
|
+
return {
|
|
29
|
+
valid: true,
|
|
30
|
+
data: validation.data,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return {
|
|
35
|
+
valid: false,
|
|
36
|
+
error: `Validation error: ${validation.error}`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
valid: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Validates and parses the JSON body of the request
|
|
46
|
+
* @param bodyJson - The already parsed JSON from req.bodyJson
|
|
47
|
+
* @param fields - The definitions of expected fields
|
|
48
|
+
* @returns An object containing the validation result
|
|
49
|
+
*/
|
|
50
|
+
function validateRequestBody(bodyJson, fields) {
|
|
51
|
+
// Check that bodyJson is an object
|
|
52
|
+
if (!bodyJson || typeof bodyJson !== 'object' || Array.isArray(bodyJson)) {
|
|
53
|
+
return {
|
|
54
|
+
valid: false,
|
|
55
|
+
error: 'Body must be a valid JSON object',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const validatedData = {};
|
|
59
|
+
const errors = [];
|
|
60
|
+
// Create a Set of allowed keys for fast lookup
|
|
61
|
+
const allowedKeys = new Set(fields.map((f) => f.key));
|
|
62
|
+
// Check for unauthorized fields
|
|
63
|
+
const bodyKeys = Object.keys(bodyJson);
|
|
64
|
+
const unexpectedKeys = bodyKeys.filter((key) => !allowedKeys.has(key));
|
|
65
|
+
if (unexpectedKeys.length > 0) {
|
|
66
|
+
errors.push(`Unauthorized fields detected: ${unexpectedKeys.join(', ')}`);
|
|
67
|
+
}
|
|
68
|
+
// Check each defined field
|
|
69
|
+
for (const field of fields) {
|
|
70
|
+
const value = bodyJson[field.key];
|
|
71
|
+
// Check if required field is present
|
|
72
|
+
if (field.required && (value === undefined || value === null)) {
|
|
73
|
+
errors.push(`Field "${field.key}" is required`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// If field is optional and absent, skip to next
|
|
77
|
+
if (!field.required && (value === undefined || value === null)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Check field type
|
|
81
|
+
let isValidType = false;
|
|
82
|
+
switch (field.type) {
|
|
83
|
+
case 'string':
|
|
84
|
+
isValidType = typeof value === 'string';
|
|
85
|
+
break;
|
|
86
|
+
case 'number':
|
|
87
|
+
isValidType = typeof value === 'number' && !isNaN(value);
|
|
88
|
+
break;
|
|
89
|
+
case 'boolean':
|
|
90
|
+
isValidType = typeof value === 'boolean';
|
|
91
|
+
break;
|
|
92
|
+
case 'object':
|
|
93
|
+
isValidType =
|
|
94
|
+
typeof value === 'object' && !Array.isArray(value) && value !== null;
|
|
95
|
+
break;
|
|
96
|
+
case 'array':
|
|
97
|
+
isValidType = Array.isArray(value);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
if (!isValidType) {
|
|
101
|
+
errors.push(`Field "${field.key}" must be of type ${field.type}, received: ${typeof value}`);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
validatedData[field.key] = value;
|
|
105
|
+
}
|
|
106
|
+
// If errors were found
|
|
107
|
+
if (errors.length > 0) {
|
|
108
|
+
return {
|
|
109
|
+
valid: false,
|
|
110
|
+
error: errors.join(', '),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
valid: true,
|
|
115
|
+
data: validatedData,
|
|
116
|
+
};
|
|
117
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kinevolution/appwrite-functions-shared-utils",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.1.2",
|
|
7
|
+
"license": "ISC",
|
|
8
|
+
"author": "Nicolas Forêt <nicolas4@gmail.com>",
|
|
9
|
+
"description": "Shared utilities for Appwrite functions",
|
|
10
|
+
"type": "module",
|
|
11
|
+
"main": "dist/utils.js",
|
|
12
|
+
"module": "dist/utils.js",
|
|
13
|
+
"types": "dist/utils.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./dist/utils.js",
|
|
16
|
+
"./utils": "./dist/utils.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.json",
|
|
23
|
+
"build-remove": "shx rm -rf dist/",
|
|
24
|
+
"bump-version": "npm run bump-version:patch",
|
|
25
|
+
"bump-version:major": "gulp bump-version --type=major",
|
|
26
|
+
"bump-version:minor": "gulp bump-version --type=minor",
|
|
27
|
+
"bump-version:patch": "gulp bump-version --type=patch",
|
|
28
|
+
"deploy": "npm run build-remove && npm run build && npm run bump-version && npm publish --access public"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20.12.12",
|
|
32
|
+
"gulp": "4.0.2",
|
|
33
|
+
"gulp-replace": "1.1.4",
|
|
34
|
+
"minimist": "1.2.8",
|
|
35
|
+
"shx": "0.3.4",
|
|
36
|
+
"typescript": "^5.4.5"
|
|
37
|
+
}
|
|
38
|
+
}
|