web_plsql 0.17.1 → 0.18.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/package.json +9 -6
- package/src/handler/plsql/errorPage.js +2 -6
- package/src/handler/plsql/parsePage.js +8 -8
- package/src/handler/plsql/procedure.js +25 -23
- package/src/handler/plsql/procedureNamed.js +0 -5
- package/src/handler/plsql/procedureSanitize.js +0 -4
- package/src/handler/plsql/request.js +3 -3
- package/src/handler/plsql/sendResponse.js +42 -10
- package/src/handler/plsql/stream.js +1 -1
- package/src/handler/plsql/upload.js +1 -1
- package/src/types.js +1 -1
- package/src/util/file.js +5 -9
- package/src/version.js +1 -1
- package/types/handler/plsql/sendResponse.d.ts +1 -1
- package/types/types.d.ts +1 -1
- package/types/handler/plsql/stream.d.ts +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "web_plsql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"author": "Dieter Oberkofler <dieter.oberkofler@gmail.com>",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "The Express Middleware for Oracle PL/SQL",
|
|
@@ -44,10 +44,11 @@
|
|
|
44
44
|
"type": "module",
|
|
45
45
|
"scripts": {
|
|
46
46
|
"lint": "prettier --check --experimental-cli . && eslint . && tsc --noEmit",
|
|
47
|
-
"test": "
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"test:coverage": "vitest run --coverage",
|
|
48
49
|
"types": "rm -rf types && tsc --noEmit false --declaration true --declarationDir types --emitDeclarationOnly true --allowJs true --target es2020 --module es2020 --moduleResolution node --allowSyntheticDefaultImports true src/*.js",
|
|
49
50
|
"clean": "shx rm -f *.tgz && shx rm -f *.log",
|
|
50
|
-
"ci": "npm run clean && npm run version && npm run
|
|
51
|
+
"ci": "npm run clean && npm run version && npm run types && npm run lint && npm run test:coverage",
|
|
51
52
|
"version": "node update-version.js",
|
|
52
53
|
"create-package": "shx rm -f *.tgz && npm pack",
|
|
53
54
|
"image-build": "docker build --no-cache --progress=plain --tag=web_plsql .",
|
|
@@ -73,16 +74,18 @@
|
|
|
73
74
|
"@types/debug": "4.1.12",
|
|
74
75
|
"@types/morgan": "1.9.10",
|
|
75
76
|
"@types/multer": "2.0.0",
|
|
76
|
-
"@types/node": "25.2.
|
|
77
|
+
"@types/node": "25.2.1",
|
|
77
78
|
"@types/oracledb": "6.10.1",
|
|
78
79
|
"@types/supertest": "6.0.3",
|
|
80
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
79
81
|
"eslint": "9.39.2",
|
|
80
|
-
"eslint-plugin-jsdoc": "62.5.
|
|
82
|
+
"eslint-plugin-jsdoc": "62.5.2",
|
|
81
83
|
"oracledb": "6.10.0",
|
|
82
84
|
"prettier": "3.8.1",
|
|
83
85
|
"shx": "0.4.0",
|
|
84
86
|
"supertest": "7.2.2",
|
|
85
87
|
"typescript": "5.9.3",
|
|
86
|
-
"typescript-eslint": "8.54.0"
|
|
88
|
+
"typescript-eslint": "8.54.0",
|
|
89
|
+
"vitest": "^4.0.18"
|
|
87
90
|
}
|
|
88
91
|
}
|
|
@@ -36,30 +36,26 @@ const getError = (req, error) => {
|
|
|
36
36
|
// what type of Error did we receive
|
|
37
37
|
if (error instanceof ProcedureError) {
|
|
38
38
|
timestamp = error.timestamp;
|
|
39
|
-
/* istanbul ignore next */
|
|
40
39
|
message = error.stack ?? '';
|
|
41
40
|
environment = error.environment;
|
|
42
41
|
sql = error.sql;
|
|
43
42
|
bind = error.bind;
|
|
44
43
|
} else if (error instanceof RequestError) {
|
|
45
44
|
timestamp = error.timestamp;
|
|
46
|
-
/* istanbul ignore next */
|
|
47
45
|
message = error.stack ?? '';
|
|
48
46
|
} else if (error instanceof Error) {
|
|
49
|
-
/* istanbul ignore next */
|
|
50
47
|
message = errorToString(error);
|
|
51
48
|
} else {
|
|
52
49
|
if (typeof error === 'string') {
|
|
53
|
-
/* istanbul ignore next */
|
|
54
50
|
message = `${error}\n`;
|
|
55
51
|
}
|
|
52
|
+
/* v8 ignore start - unreachable code: creating Error without throwing */
|
|
56
53
|
try {
|
|
57
|
-
/* istanbul ignore next */
|
|
58
54
|
new Error();
|
|
59
55
|
} catch (err) {
|
|
60
|
-
/* istanbul ignore next */
|
|
61
56
|
message += errorToString(err);
|
|
62
57
|
}
|
|
58
|
+
/* v8 ignore stop */
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
return getFormattedMessage({type: 'error', timestamp, message, req, environment, sql, bind});
|
|
@@ -55,7 +55,7 @@ export const parsePage = (text) => {
|
|
|
55
55
|
{
|
|
56
56
|
const cookie = parseCookie(header.value);
|
|
57
57
|
debug(`oracle header "set-cookie" with value "${header.value}" was received has been parsed to ${JSON.stringify(cookie)}`);
|
|
58
|
-
/*
|
|
58
|
+
/* v8 ignore else - parseCookie validation ensures non-null */
|
|
59
59
|
if (cookie !== null) {
|
|
60
60
|
page.head.cookies.push(cookie);
|
|
61
61
|
} else {
|
|
@@ -72,7 +72,7 @@ export const parsePage = (text) => {
|
|
|
72
72
|
case 'x-db-content-length':
|
|
73
73
|
{
|
|
74
74
|
const contentLength = parseInt(header.value, 10);
|
|
75
|
-
/*
|
|
75
|
+
/* v8 ignore else - parseInt validation */
|
|
76
76
|
if (!Number.isNaN(contentLength)) {
|
|
77
77
|
page.head.contentLength = contentLength;
|
|
78
78
|
debug(`oracle header "x-db-content-length" with value "${page.head.contentLength}" was parsed`);
|
|
@@ -85,12 +85,12 @@ export const parsePage = (text) => {
|
|
|
85
85
|
case 'status':
|
|
86
86
|
{
|
|
87
87
|
const statusCode = parseInt(header.value, 10);
|
|
88
|
-
/*
|
|
88
|
+
/* v8 ignore else - parseInt validation */
|
|
89
89
|
if (!Number.isNaN(statusCode)) {
|
|
90
90
|
page.head.statusCode = statusCode;
|
|
91
91
|
debug(`oracle header "status" with value "${page.head.statusCode}" was parsed`);
|
|
92
92
|
const index = header.value.indexOf(' ');
|
|
93
|
-
/*
|
|
93
|
+
/* v8 ignore else - status code may not have description */
|
|
94
94
|
if (index !== -1) {
|
|
95
95
|
page.head.statusDescription = header.value.substring(index + 1);
|
|
96
96
|
}
|
|
@@ -143,7 +143,7 @@ const getHeader = (line) => {
|
|
|
143
143
|
*/
|
|
144
144
|
const parseCookie = (text) => {
|
|
145
145
|
// validate
|
|
146
|
-
/*
|
|
146
|
+
/* v8 ignore next - input validation */
|
|
147
147
|
if (typeof text !== 'string' || text.trim().length === 0) {
|
|
148
148
|
return null;
|
|
149
149
|
}
|
|
@@ -156,7 +156,7 @@ const parseCookie = (text) => {
|
|
|
156
156
|
|
|
157
157
|
// get name and value
|
|
158
158
|
const index = cookieElements[0].indexOf('=');
|
|
159
|
-
/*
|
|
159
|
+
/* v8 ignore next - cookie format validation */
|
|
160
160
|
if (index <= 0) {
|
|
161
161
|
// if the index is -1, there is no equal sign and if it's 0 the name is empty
|
|
162
162
|
return null;
|
|
@@ -179,7 +179,7 @@ const parseCookie = (text) => {
|
|
|
179
179
|
} else if (element.toLowerCase().startsWith('domain=')) {
|
|
180
180
|
cookie.options.domain = element.substring(7);
|
|
181
181
|
} else if (element.toLowerCase().startsWith('secure=')) {
|
|
182
|
-
/*
|
|
182
|
+
/* v8 ignore next - secure cookie attribute */
|
|
183
183
|
cookie.options.secure = true;
|
|
184
184
|
} else if (element.toLowerCase().startsWith('expires=')) {
|
|
185
185
|
const date = tryDecodeDate(element.substring(8));
|
|
@@ -203,7 +203,7 @@ const tryDecodeDate = (value) => {
|
|
|
203
203
|
try {
|
|
204
204
|
return new Date(value);
|
|
205
205
|
} catch (err) {
|
|
206
|
-
/*
|
|
206
|
+
/* v8 ignore next - invalid date format */
|
|
207
207
|
return null;
|
|
208
208
|
}
|
|
209
209
|
};
|
|
@@ -9,7 +9,6 @@ import oracledb from 'oracledb';
|
|
|
9
9
|
import stream from 'node:stream';
|
|
10
10
|
import z from 'zod';
|
|
11
11
|
|
|
12
|
-
import {streamToBuffer} from './stream.js';
|
|
13
12
|
import {uploadFile} from './upload.js';
|
|
14
13
|
import {getProcedureVariable} from './procedureVariable.js';
|
|
15
14
|
import {getProcedureNamed} from './procedureNamed.js';
|
|
@@ -154,7 +153,7 @@ const procedureGetPage = async (test, databaseConnection) => {
|
|
|
154
153
|
|
|
155
154
|
// Make sure that we have retrieved all the rows
|
|
156
155
|
if (irows > MAX_IROWS) {
|
|
157
|
-
/*
|
|
156
|
+
/* v8 ignore next - defensive check for row limit */
|
|
158
157
|
throw new ProcedureError(`procedureGetPage: error when retrieving rows. irows="${irows}"`, {}, sqlStatement, bindParameter);
|
|
159
158
|
}
|
|
160
159
|
|
|
@@ -274,35 +273,38 @@ export const invokeProcedure = async (req, res, argObj, cgiObj, filesToUpload, o
|
|
|
274
273
|
|
|
275
274
|
debug('invokeProcedure: download files');
|
|
276
275
|
const fileBlob = await databaseConnection.createLob(oracledb.BLOB);
|
|
277
|
-
const fileDownload = await procedureDownloadFiles(fileBlob, databaseConnection);
|
|
278
|
-
if (debug.enabled) {
|
|
279
|
-
debug(getBlock('fileDownload', inspect({fileType: fileDownload.fileType, fileSize: fileDownload.fileSize})));
|
|
280
|
-
}
|
|
281
276
|
|
|
282
|
-
|
|
277
|
+
try {
|
|
278
|
+
const fileDownload = await procedureDownloadFiles(fileBlob, databaseConnection);
|
|
279
|
+
if (debug.enabled) {
|
|
280
|
+
debug(getBlock('fileDownload', inspect({fileType: fileDownload.fileType, fileSize: fileDownload.fileSize})));
|
|
281
|
+
}
|
|
283
282
|
|
|
284
|
-
|
|
285
|
-
const pageComponents = parsePage(lines);
|
|
283
|
+
// 7) parse the page
|
|
286
284
|
|
|
287
|
-
|
|
288
|
-
|
|
285
|
+
debug('invokeProcedure: parse the page');
|
|
286
|
+
const pageComponents = parsePage(lines);
|
|
289
287
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
pageComponents.file.fileType = fileDownload.fileType;
|
|
293
|
-
pageComponents.file.fileSize = fileDownload.fileSize;
|
|
294
|
-
pageComponents.file.fileBlob = await streamToBuffer(fileDownload.fileBlob);
|
|
295
|
-
}
|
|
288
|
+
// add "Server" header
|
|
289
|
+
pageComponents.head.server = cgiObj.SERVER_SOFTWARE;
|
|
296
290
|
|
|
297
|
-
|
|
291
|
+
// add file download information
|
|
292
|
+
if (fileDownload.fileType !== '' && fileDownload.fileSize > 0 && fileDownload.fileBlob !== null) {
|
|
293
|
+
pageComponents.file.fileType = fileDownload.fileType;
|
|
294
|
+
pageComponents.file.fileSize = fileDownload.fileSize;
|
|
295
|
+
pageComponents.file.fileBlob = fileDownload.fileBlob;
|
|
296
|
+
}
|
|
298
297
|
|
|
299
|
-
|
|
300
|
-
sendResponse(req, res, pageComponents);
|
|
298
|
+
// 8) send the page to browser
|
|
301
299
|
|
|
302
|
-
|
|
300
|
+
debug('invokeProcedure: send the page to browser');
|
|
301
|
+
await sendResponse(req, res, pageComponents);
|
|
302
|
+
} finally {
|
|
303
|
+
// 9) cleanup
|
|
303
304
|
|
|
304
|
-
|
|
305
|
-
|
|
305
|
+
debug('invokeProcedure: cleanup');
|
|
306
|
+
fileBlob.destroy();
|
|
307
|
+
}
|
|
306
308
|
|
|
307
309
|
debug('invokeProcedure: end');
|
|
308
310
|
};
|
|
@@ -89,9 +89,7 @@ const loadArguments = async (procedure, databaseConnection) => {
|
|
|
89
89
|
result = await databaseConnection.execute(SQL_GET_ARGUMENT, bind);
|
|
90
90
|
} catch (err) {
|
|
91
91
|
debug('result', result);
|
|
92
|
-
/* istanbul ignore next */
|
|
93
92
|
const message = `Error when retrieving arguments\n${SQL_GET_ARGUMENT}\n${errorToString(err)}`;
|
|
94
|
-
/* istanbul ignore next */
|
|
95
93
|
throw new RequestError(message);
|
|
96
94
|
}
|
|
97
95
|
|
|
@@ -106,14 +104,11 @@ const loadArguments = async (procedure, databaseConnection) => {
|
|
|
106
104
|
.parse(result.outBinds);
|
|
107
105
|
} catch (err) {
|
|
108
106
|
debug('result.outBinds', result.outBinds);
|
|
109
|
-
/* istanbul ignore next */
|
|
110
107
|
const message = `Error when decoding arguments\n${SQL_GET_ARGUMENT}\n${errorToString(err)}`;
|
|
111
|
-
/* istanbul ignore next */
|
|
112
108
|
throw new RequestError(message);
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
if (data.names.length !== data.types.length) {
|
|
116
|
-
/* istanbul ignore next */
|
|
117
112
|
throw new RequestError('Error when decoding arguments. The number of names and types does not match');
|
|
118
113
|
}
|
|
119
114
|
|
|
@@ -128,9 +128,7 @@ const loadRequestValid = async (procName, requestValidationFunction, databaseCon
|
|
|
128
128
|
result = await databaseConnection.execute(SQL, bind);
|
|
129
129
|
} catch (err) {
|
|
130
130
|
debug('result', result);
|
|
131
|
-
/* istanbul ignore next */
|
|
132
131
|
const message = `Error when validating procedure name "${procName}"\n${SQL}\n${errorToString(err)}`;
|
|
133
|
-
/* istanbul ignore next */
|
|
134
132
|
throw new RequestError(message);
|
|
135
133
|
}
|
|
136
134
|
|
|
@@ -139,9 +137,7 @@ const loadRequestValid = async (procName, requestValidationFunction, databaseCon
|
|
|
139
137
|
return data.valid === 1;
|
|
140
138
|
} catch (err) {
|
|
141
139
|
debug('result', result.outBinds);
|
|
142
|
-
/* istanbul ignore next */
|
|
143
140
|
const message = `Internal error when parsing ${result.outBinds}\n${errorToString(err)}`;
|
|
144
|
-
/* istanbul ignore next */
|
|
145
141
|
throw new Error(message);
|
|
146
142
|
}
|
|
147
143
|
};
|
|
@@ -98,16 +98,16 @@ const normalizeBody = (req) => {
|
|
|
98
98
|
/** @type {Record<string, string | string[]>} */
|
|
99
99
|
const args = {};
|
|
100
100
|
|
|
101
|
-
/*
|
|
101
|
+
/* v8 ignore else - body validation */
|
|
102
102
|
if (typeof req.body === 'object' && req.body !== null) {
|
|
103
103
|
for (const key in req.body) {
|
|
104
104
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
105
105
|
const value = req.body[key];
|
|
106
|
-
/*
|
|
106
|
+
/* v8 ignore else - type validation */
|
|
107
107
|
if (isStringOrArrayOfString(value)) {
|
|
108
108
|
args[key] = value;
|
|
109
109
|
} else {
|
|
110
|
-
/*
|
|
110
|
+
/* v8 ignore next - invalid body type */
|
|
111
111
|
throw new RequestError(
|
|
112
112
|
`The element "${key}" in the body is not a string or an array of strings!\n${util.inspect(req.body, {showHidden: false, depth: null, colors: false})}`,
|
|
113
113
|
);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import debugModule from 'debug';
|
|
6
6
|
const debug = debugModule('webplsql:sendResponse');
|
|
7
7
|
|
|
8
|
+
import stream from 'node:stream';
|
|
8
9
|
import {getBlock} from '../../util/trace.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -20,9 +21,9 @@ import {getBlock} from '../../util/trace.js';
|
|
|
20
21
|
* @param {Request} req - The req object represents the HTTP request.
|
|
21
22
|
* @param {Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
|
|
22
23
|
* @param {pageType} page - The page to send.
|
|
23
|
-
* @returns {void}
|
|
24
|
+
* @returns {Promise<void>}
|
|
24
25
|
*/
|
|
25
|
-
export const sendResponse = (req, res, page) => {
|
|
26
|
+
export const sendResponse = async (req, res, page) => {
|
|
26
27
|
/** @type {string[]} */
|
|
27
28
|
const debugText = [];
|
|
28
29
|
|
|
@@ -57,20 +58,51 @@ export const sendResponse = (req, res, page) => {
|
|
|
57
58
|
|
|
58
59
|
// If this is a file download, we eventually set the "Content-Type" and the file content and then return.
|
|
59
60
|
if (page.file.fileType === 'B' || page.file.fileType === 'F') {
|
|
61
|
+
/** @type {Record<string, string>} */
|
|
62
|
+
const headers = {};
|
|
63
|
+
|
|
60
64
|
if (typeof page.head.contentType === 'string' && page.head.contentType.length > 0) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
65
|
+
headers['Content-Type'] = page.head.contentType;
|
|
66
|
+
}
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
if (typeof page.file.fileSize === 'number' && page.file.fileSize > 0) {
|
|
69
|
+
headers['Content-Length'] = page.file.fileSize.toString();
|
|
66
70
|
}
|
|
67
71
|
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
if (Object.keys(headers).length > 0) {
|
|
73
|
+
if (debug.enabled) {
|
|
74
|
+
debugText.push(`res.writeHead(200, ${JSON.stringify(headers)})`);
|
|
75
|
+
}
|
|
76
|
+
res.writeHead(200, headers);
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
|
|
79
|
+
// Check if fileBlob is a stream
|
|
80
|
+
if (page.file.fileBlob instanceof stream.Readable) {
|
|
81
|
+
if (debug.enabled) {
|
|
82
|
+
debugText.push(`res.pipe("${page.file.fileType}") - streaming`);
|
|
83
|
+
debug(getBlock('RESPONSE', debugText.join('\n')));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** @type {Promise<void>} */
|
|
87
|
+
const streamComplete = new Promise((resolve, reject) => {
|
|
88
|
+
if (page.file.fileBlob instanceof stream.Readable) {
|
|
89
|
+
page.file.fileBlob.pipe(res);
|
|
90
|
+
page.file.fileBlob.on('end', () => resolve());
|
|
91
|
+
/* v8 ignore next - error handler */
|
|
92
|
+
page.file.fileBlob.on('error', (/** @type {Error} */ err) => reject(err));
|
|
93
|
+
/* v8 ignore next - error handler */
|
|
94
|
+
res.on('close', () => resolve());
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
await streamComplete;
|
|
98
|
+
} else {
|
|
99
|
+
if (debug.enabled) {
|
|
100
|
+
debugText.push(`res.end("${page.file.fileType}") - buffer`);
|
|
101
|
+
debug(getBlock('RESPONSE', debugText.join('\n')));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
res.end(page.file.fileBlob, 'binary');
|
|
105
|
+
}
|
|
74
106
|
return;
|
|
75
107
|
}
|
|
76
108
|
|
|
@@ -70,7 +70,7 @@ export const getFiles = (req) => {
|
|
|
70
70
|
export const uploadFile = async (file, doctable, databaseConnection) => {
|
|
71
71
|
debug(`uploadFile`, file, doctable);
|
|
72
72
|
|
|
73
|
-
/*
|
|
73
|
+
/* v8 ignore next - defensive validation */
|
|
74
74
|
if (typeof doctable !== 'string' || doctable.length === 0) {
|
|
75
75
|
throw new Error(`Unable to upload file "${file.filename}" because the option ""doctable" has not been defined`);
|
|
76
76
|
}
|
package/src/types.js
CHANGED
|
@@ -140,5 +140,5 @@ export const z$configType = z.strictObject({
|
|
|
140
140
|
* @property {object} file - The file.
|
|
141
141
|
* @property {string | null} file.fileType - The file type.
|
|
142
142
|
* @property {number | null} file.fileSize - The file size.
|
|
143
|
-
* @property {Buffer | null} file.fileBlob - The file blob.
|
|
143
|
+
* @property {import('node:stream').Readable | Buffer | null} file.fileBlob - The file blob.
|
|
144
144
|
*/
|
package/src/util/file.js
CHANGED
|
@@ -10,7 +10,6 @@ export const readFileSyncUtf8 = (filePath) => {
|
|
|
10
10
|
try {
|
|
11
11
|
return readFileSync(filePath, 'utf8');
|
|
12
12
|
} catch (err) {
|
|
13
|
-
/* istanbul ignore next */
|
|
14
13
|
throw new Error(`Unable to read file "${filePath}"`);
|
|
15
14
|
}
|
|
16
15
|
};
|
|
@@ -21,11 +20,10 @@ export const readFileSyncUtf8 = (filePath) => {
|
|
|
21
20
|
* @param {string} filePath - File name.
|
|
22
21
|
* @returns {Promise<Buffer>} The buffer.
|
|
23
22
|
*/
|
|
24
|
-
export const readFile = (filePath) => {
|
|
23
|
+
export const readFile = async (filePath) => {
|
|
25
24
|
try {
|
|
26
|
-
return fs.readFile(filePath);
|
|
25
|
+
return await fs.readFile(filePath);
|
|
27
26
|
} catch (err) {
|
|
28
|
-
/* istanbul ignore next */
|
|
29
27
|
throw new Error(`Unable to read file "${filePath}"`);
|
|
30
28
|
}
|
|
31
29
|
};
|
|
@@ -36,11 +34,10 @@ export const readFile = (filePath) => {
|
|
|
36
34
|
* @param {string} filePath - File name.
|
|
37
35
|
* @returns {Promise<void>}.
|
|
38
36
|
*/
|
|
39
|
-
export const removeFile = (filePath) => {
|
|
37
|
+
export const removeFile = async (filePath) => {
|
|
40
38
|
try {
|
|
41
|
-
return fs.unlink(filePath);
|
|
39
|
+
return await fs.unlink(filePath);
|
|
42
40
|
} catch (err) {
|
|
43
|
-
/* istanbul ignore next */
|
|
44
41
|
throw new Error(`Unable to remove file "${filePath}"`);
|
|
45
42
|
}
|
|
46
43
|
};
|
|
@@ -52,9 +49,8 @@ export const removeFile = (filePath) => {
|
|
|
52
49
|
* @returns {unknown} The json object.
|
|
53
50
|
*/
|
|
54
51
|
export const getJsonFile = (filePath) => {
|
|
55
|
-
const fileContent = readFileSync(filePath, 'utf8');
|
|
56
|
-
|
|
57
52
|
try {
|
|
53
|
+
const fileContent = readFileSync(filePath, 'utf8');
|
|
58
54
|
return JSON.parse(fileContent);
|
|
59
55
|
} catch (err) {
|
|
60
56
|
throw new Error(`Unable to load file "${filePath}"`);
|
package/src/version.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function sendResponse(req: Request, res: Response, page: pageType): void
|
|
1
|
+
export function sendResponse(req: Request, res: Response, page: pageType): Promise<void>;
|
|
2
2
|
export type Request = import("express").Request;
|
|
3
3
|
export type Response = import("express").Response;
|
|
4
4
|
export type CookieOptions = import("express").CookieOptions;
|
package/types/types.d.ts
CHANGED