web_plsql 0.5.0 → 0.6.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.
Files changed (96) hide show
  1. package/README.md +123 -110
  2. package/examples/server_apex.js +28 -0
  3. package/examples/server_sample.js +30 -0
  4. package/examples/sql/{doc_table.sql → doctable.sql} +1 -1
  5. package/examples/sql/install.sql +6 -9
  6. package/examples/sql/sample_package.sql +27 -0
  7. package/examples/sql/sample_package_body.sql +245 -0
  8. package/examples/static/sample.css +11 -10
  9. package/package.json +90 -83
  10. package/src/cgi.js +127 -0
  11. package/src/error.js +24 -0
  12. package/src/errorPage.js +296 -0
  13. package/src/file.js +77 -0
  14. package/src/handlerLogger.js +21 -0
  15. package/src/handlerMetrics.js +46 -0
  16. package/src/handlerPlSql.js +65 -0
  17. package/src/handlerUpload.js +32 -0
  18. package/src/index.js +17 -0
  19. package/src/oracle.js +80 -0
  20. package/src/parsePage.js +193 -0
  21. package/src/procedure.js +260 -0
  22. package/src/procedureError.js +40 -0
  23. package/src/procedureNamed.js +233 -0
  24. package/src/procedureSanitize.js +215 -0
  25. package/src/procedureVariable.js +57 -0
  26. package/src/request.js +103 -0
  27. package/src/{requestError.ts → requestError.js} +8 -4
  28. package/src/sendResponse.js +104 -0
  29. package/src/server.js +106 -0
  30. package/src/shutdown.js +53 -0
  31. package/src/stream.js +28 -0
  32. package/src/trace.js +74 -0
  33. package/src/tty.js +48 -0
  34. package/src/types.js +146 -0
  35. package/src/upload.js +92 -0
  36. package/src/version.js +23 -0
  37. package/types/cgi.d.ts +4 -0
  38. package/types/error.d.ts +1 -0
  39. package/types/errorPage.d.ts +10 -0
  40. package/types/file.d.ts +5 -0
  41. package/types/handlerLogger.d.ts +2 -0
  42. package/types/handlerMetrics.d.ts +4 -0
  43. package/types/handlerPlSql.d.ts +8 -0
  44. package/types/handlerUpload.d.ts +7 -0
  45. package/types/index.d.ts +10 -0
  46. package/types/oracle.d.ts +5 -0
  47. package/types/parsePage.d.ts +3 -0
  48. package/types/procedure.d.ts +10 -0
  49. package/types/procedureError.d.ts +23 -0
  50. package/types/procedureNamed.d.ts +14 -0
  51. package/types/procedureSanitize.d.ts +14 -0
  52. package/types/procedureVariable.d.ts +9 -0
  53. package/types/request.d.ts +7 -0
  54. package/types/requestError.d.ts +8 -0
  55. package/types/sendResponse.d.ts +4 -0
  56. package/types/server.d.ts +7 -0
  57. package/types/shutdown.d.ts +2 -0
  58. package/types/stream.d.ts +1 -0
  59. package/types/trace.d.ts +5 -0
  60. package/types/tty.d.ts +4 -0
  61. package/types/types.d.ts +251 -0
  62. package/types/upload.d.ts +5 -0
  63. package/types/version.d.ts +7 -0
  64. package/.editorconfig +0 -8
  65. package/.eslintignore +0 -3
  66. package/.eslintrc.js +0 -347
  67. package/CHANGELOG.md +0 -127
  68. package/examples/apex.js +0 -70
  69. package/examples/credentials.js +0 -22
  70. package/examples/oracledb_example.js +0 -30
  71. package/examples/sample.js +0 -101
  72. package/examples/sql/sample.pkb +0 -223
  73. package/examples/sql/sample.pks +0 -24
  74. package/jest.config.js +0 -204
  75. package/src/cgi.ts +0 -95
  76. package/src/config.ts +0 -97
  77. package/src/errorPage.ts +0 -286
  78. package/src/fileUpload.ts +0 -126
  79. package/src/index.ts +0 -65
  80. package/src/page.ts +0 -275
  81. package/src/procedure.ts +0 -360
  82. package/src/procedureError.ts +0 -27
  83. package/src/request.ts +0 -139
  84. package/src/stream.ts +0 -26
  85. package/src/trace.ts +0 -194
  86. package/test/.eslintrc.json +0 -5
  87. package/test/__tests__/cgi.ts +0 -96
  88. package/test/__tests__/config.ts +0 -41
  89. package/test/__tests__/errorPage.ts +0 -101
  90. package/test/__tests__/oracledb_mock.ts +0 -98
  91. package/test/__tests__/server.ts +0 -495
  92. package/test/__tests__/stream.ts +0 -21
  93. package/test/mock/oracledb.ts +0 -85
  94. package/test/static/static.html +0 -1
  95. package/tsconfig.json +0 -24
  96. package/tsconfig.src.json +0 -23
package/package.json CHANGED
@@ -1,85 +1,92 @@
1
1
  {
2
- "name": "web_plsql",
3
- "version": "0.5.0",
4
- "author": "Dieter Oberkofler <dieter.oberkofler@gmail.com>",
5
- "license": "MIT",
6
- "description": "The Express Middleware for Oracle PL/SQL",
7
- "keywords": [
8
- "node",
9
- "nodejs",
10
- "express",
11
- "middleware",
12
- "mod_plsql",
13
- "plsql",
14
- "pl/sql",
15
- "oracle",
16
- "ohs",
17
- "ords",
18
- "gateway",
19
- "apex"
20
- ],
21
- "homepage": "https://github.com/doberkofler/web_plsql",
22
- "engines": {
23
- "node": ">=16"
24
- },
25
- "maintainers": [
26
- {
27
- "name": "Dieter Oberkofler",
28
- "email": "dieter.oberkofler@gmail.com"
29
- }
30
- ],
31
- "bugs": {
32
- "url": "https://github.com/doberkofler/web_plsql/issues"
33
- },
34
- "repository": {
35
- "type": "git",
36
- "url": "git://github.com/doberkofler/web_plsql.git"
37
- },
38
- "scripts": {
39
- "clean": "rimraf access.log lib trace coverage .nyc_output",
40
- "build": "tsc --project ./tsconfig.src.json",
41
- "eslint": "eslint --cache --report-unused-disable-directives \"./**/*.ts\"",
42
- "type-check": "tsc --project ./tsconfig.json --noEmit",
43
- "lint": "npm run eslint && npm run type-check",
44
- "test": "jest --coverage=false",
45
- "test:coverage": "jest",
46
- "sample": "node examples/sample.js",
47
- "rebuild": "npm run clean && npm run lint && npm run build && npm run test",
48
- "create-package": "shx rm -f *.tgz && npm pack",
49
- "install": "npm run build"
50
- },
51
- "dependencies": {
52
- "body-parser": "1.20.0",
53
- "compression": "1.7.4",
54
- "connect-multiparty": "2.2.0",
55
- "cookie-parser": "1.4.6",
56
- "escape-html": "1.0.3",
57
- "express": "4.18.1",
58
- "express-status-monitor": "1.3.4",
59
- "http-parser-js": "0.5.6",
60
- "mkdirp": "1.0.4",
61
- "morgan": "1.10.0",
62
- "oracledb": "5.3.0"
63
- },
64
- "devDependencies": {
65
- "@types/body-parser": "1.19.2",
66
- "@types/compression": "1.7.2",
67
- "@types/cookie-parser": "1.4.3",
68
- "@types/escape-html": "1.0.2",
69
- "@types/mkdirp": "1.0.2",
70
- "@types/morgan": "1.9.3",
71
- "@types/node": "17.0.31",
72
- "@types/oracledb": "5.2.3",
73
- "@types/supertest": "2.0.12",
74
- "@typescript-eslint/eslint-plugin": "5.22.0",
75
- "@typescript-eslint/parser": "5.22.0",
76
- "eslint": "8.15.0",
77
- "jest": "28.1.0",
78
- "rimraf": "3.0.2",
79
- "shx": "0.3.4",
80
- "supertest": "6.2.3",
81
- "ts-jest": "28.0.2",
82
- "ts-node": "10.7.0",
83
- "typescript": "4.6.4"
84
- }
2
+ "name": "web_plsql",
3
+ "version": "0.6.0",
4
+ "author": "Dieter Oberkofler <dieter.oberkofler@gmail.com>",
5
+ "license": "MIT",
6
+ "description": "The Express Middleware for Oracle PL/SQL",
7
+ "keywords": [
8
+ "node",
9
+ "nodejs",
10
+ "express",
11
+ "middleware",
12
+ "plsql",
13
+ "pl/sql",
14
+ "oracle",
15
+ "ohs",
16
+ "ords",
17
+ "apex"
18
+ ],
19
+ "homepage": "https://github.com/doberkofler/web_plsql",
20
+ "engines": {
21
+ "npm": ">=10.0.0",
22
+ "node": ">=22.0.0"
23
+ },
24
+ "maintainers": [
25
+ {
26
+ "name": "Dieter Oberkofler",
27
+ "email": "dieter.oberkofler@gmail.com"
28
+ }
29
+ ],
30
+ "bugs": {
31
+ "url": "https://github.com/doberkofler/web_plsql/issues"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git://github.com/doberkofler/web_plsql.git"
36
+ },
37
+ "files": [
38
+ "src/",
39
+ "examples/",
40
+ "types"
41
+ ],
42
+ "main": "./src/index.js",
43
+ "types": "./types/index.d.ts",
44
+ "type": "module",
45
+ "scripts": {
46
+ "lint": "prettier --check . && eslint . && tsc --noEmit",
47
+ "test": "node --test --test-concurrency=1 \"./tests/**/*.test.js\"",
48
+ "types": "rm -rf types && tsc --noEmit false --declaration true --declarationDir types --emitDeclarationOnly true --allowJs true --target es2020 --module es2020 --moduleResolution node src/*.js",
49
+ "clean": "shx rm -f *.tgz && shx rm -f *.log",
50
+ "ci": "npm run clean && npm run lint && npm run test",
51
+ "create-package": "shx rm -f *.tgz && npm pack"
52
+ },
53
+ "dependencies": {
54
+ "basic-auth": "2.0.1",
55
+ "body-parser": "1.20.3",
56
+ "compression": "1.7.5",
57
+ "connect-multiparty": "2.2.0",
58
+ "cookie-parser": "1.4.7",
59
+ "debug": "4.4.0",
60
+ "escape-html": "1.0.3",
61
+ "express": "4.21.2",
62
+ "fs-extra": "11.3.0",
63
+ "http-parser-js": "0.5.9",
64
+ "morgan": "1.10.0",
65
+ "multer": "^1.4.5-lts.1",
66
+ "oracledb": "6.7.1",
67
+ "rotating-file-stream": "3.2.5",
68
+ "zod": "3.24.1"
69
+ },
70
+ "devDependencies": {
71
+ "@types/basic-auth": "1.1.8",
72
+ "@types/body-parser": "1.19.5",
73
+ "@types/compression": "1.7.5",
74
+ "@types/cookie-parser": "1.4.8",
75
+ "@types/debug": "4.1.12",
76
+ "@types/escape-html": "1.0.4",
77
+ "@types/fs-extra": "11.0.4",
78
+ "@types/morgan": "1.9.9",
79
+ "@types/multer": "^1.4.12",
80
+ "@types/node": "22.13.1",
81
+ "@types/oracledb": "6.5.3",
82
+ "@types/supertest": "6.0.2",
83
+ "eslint": "9.20.0",
84
+ "eslint-plugin-jsdoc": "50.6.3",
85
+ "prettier": "3.5.0",
86
+ "rimraf": "6.0.1",
87
+ "shx": "0.3.4",
88
+ "supertest": "7.0.0",
89
+ "typescript": "5.7.3",
90
+ "typescript-eslint": "8.23.0"
91
+ }
85
92
  }
package/src/cgi.js ADDED
@@ -0,0 +1,127 @@
1
+ /*
2
+ * Prepare the CGI information
3
+ */
4
+
5
+ import os from 'node:os';
6
+ import {URL} from 'node:url';
7
+
8
+ /**
9
+ * @typedef {import('express').Request} Request
10
+ * @typedef {import('./types.js').environmentType} environmentType
11
+ * @typedef {import('./types.js').configPlSqlType} configPlSqlType
12
+ */
13
+
14
+ /** @type {environmentType} */
15
+ const DEFAULT_CGI = {
16
+ PLSQL_GATEWAY: 'WebDb',
17
+ GATEWAY_IVERSION: '2',
18
+ SERVER_SOFTWARE: 'web_plsql',
19
+ GATEWAY_INTERFACE: 'CGI/1.1',
20
+ SERVER_PORT: '',
21
+ SERVER_NAME: os.hostname(),
22
+ REQUEST_METHOD: '',
23
+ PATH_INFO: '',
24
+ SCRIPT_NAME: '',
25
+ REMOTE_ADDR: '',
26
+ SERVER_PROTOCOL: '',
27
+ REQUEST_PROTOCOL: '',
28
+ REMOTE_USER: '',
29
+ HTTP_COOKIE: '',
30
+ HTTP_USER_AGENT: '',
31
+ HTTP_HOST: '',
32
+ HTTP_ACCEPT: '',
33
+ HTTP_ACCEPT_ENCODING: '',
34
+ HTTP_ACCEPT_LANGUAGE: '',
35
+ HTTP_REFERER: '',
36
+ HTTP_X_FORWARDED_FOR: '',
37
+ WEB_AUTHENT_PREFIX: '',
38
+ DAD_NAME: '',
39
+ DOC_ACCESS_PATH: 'doc',
40
+ DOCUMENT_TABLE: '',
41
+ PATH_ALIAS: '',
42
+ REQUEST_CHARSET: 'UTF8',
43
+ REQUEST_IANA_CHARSET: 'UTF-8',
44
+ SCRIPT_PREFIX: '',
45
+ };
46
+
47
+ /**
48
+ * Create the HTTP_COOKIE string
49
+ *
50
+ * @param {Request} req - The req object represents the HTTP request.
51
+ * @returns {string} - The string representation of the cookies.
52
+ */
53
+ const getCookieString = (req) => {
54
+ let cookieString = '';
55
+
56
+ for (const propName in req.cookies) {
57
+ cookieString += `${propName}=${req.cookies[propName]};`;
58
+ }
59
+
60
+ return cookieString;
61
+ };
62
+
63
+ /**
64
+ * Get the script name and DAD name from a URL
65
+ *
66
+ * @param {Request} req - The req object represents the HTTP request.
67
+ * @returns {{script: string; prefix: string; dad: string}} - The DAD structure.
68
+ */
69
+ const getPath = (req) => {
70
+ // create a valid url
71
+ const validUrl = `${req.protocol}://${os.hostname()}${req.originalUrl}`;
72
+
73
+ // get the pathname from the url (new URL('https://example.org/abc/xyz?123').pathname => /abc/xyz)
74
+ const pathname = new URL(validUrl).pathname;
75
+
76
+ const tmp = trimPath(pathname.substring(0, pathname.lastIndexOf('/') + 1));
77
+ const script = `/${tmp}`;
78
+ const prefix = `/${tmp.substring(0, tmp.lastIndexOf('/'))}`;
79
+ const dad = tmp.substring(tmp.indexOf('/') + 1);
80
+
81
+ return {script, prefix, dad};
82
+ };
83
+
84
+ /**
85
+ * Get a path that is not enclodes in slashes
86
+ *
87
+ * @param {string} value - The value to trim.
88
+ * @returns {string} - The trimmed value.
89
+ */
90
+ const trimPath = (value) => value.replace(/^\/+|\/+$/g, '');
91
+
92
+ /**
93
+ * Create a CGI object
94
+ *
95
+ * @param {Request} req - The req object represents the HTTP request.
96
+ * @param {string} doctable - The document table.
97
+ * @param {environmentType} cgi - The additional cgi.
98
+ * @returns {environmentType} CGI object
99
+ */
100
+ export const getCGI = (req, doctable, cgi) => {
101
+ const PROTOCOL = req.protocol ? req.protocol.toUpperCase() : '';
102
+ const PATH = getPath(req);
103
+
104
+ /** @type {environmentType} */
105
+ const CGI = {
106
+ SERVER_PORT: typeof req.socket.localPort === 'number' ? req.socket.localPort.toString() : '',
107
+ REQUEST_METHOD: req.method,
108
+ PATH_INFO: req.params.name,
109
+ SCRIPT_NAME: PATH.script,
110
+ REMOTE_ADDR: (req.ip ?? '').replace('::ffff:', ''),
111
+ SERVER_PROTOCOL: `${PROTOCOL}/${req.httpVersion}`,
112
+ REQUEST_PROTOCOL: PROTOCOL,
113
+ HTTP_COOKIE: getCookieString(req),
114
+ HTTP_USER_AGENT: req.get('user-agent') ?? '',
115
+ HTTP_HOST: req.get('host') ?? '',
116
+ HTTP_ACCEPT: req.get('accept') ?? '',
117
+ HTTP_ACCEPT_ENCODING: req.get('accept-encoding') ?? '',
118
+ HTTP_ACCEPT_LANGUAGE: req.get('accept-language') ?? '',
119
+ HTTP_REFERER: req.get('referer') ?? '',
120
+ HTTP_X_FORWARDED_FOR: req.get('x-forwarded-for') ?? '',
121
+ DAD_NAME: PATH.dad,
122
+ DOCUMENT_TABLE: doctable,
123
+ SCRIPT_PREFIX: PATH.prefix,
124
+ };
125
+
126
+ return Object.assign({}, DEFAULT_CGI, CGI, cgi);
127
+ };
package/src/error.js ADDED
@@ -0,0 +1,24 @@
1
+ import {inspect} from './trace.js';
2
+
3
+ /**
4
+ * Convert Error to a string.
5
+ *
6
+ * @param {unknown} error - The error.
7
+ * @returns {string} The string representation.
8
+ */
9
+ export const errorToString = (error) => {
10
+ if (typeof error === 'string') {
11
+ return error;
12
+ } else if (error instanceof Error) {
13
+ const parts = [error.name];
14
+ if (typeof error.message === 'string' && error.message.length > 0) {
15
+ parts.push(error.message);
16
+ }
17
+ if (typeof error.stack === 'string' && error.stack.length > 0) {
18
+ parts.push(error.stack);
19
+ }
20
+ return parts.join('\n');
21
+ } else {
22
+ return inspect(error);
23
+ }
24
+ };
@@ -0,0 +1,296 @@
1
+ /*
2
+ * Error handling
3
+ */
4
+
5
+ import util from 'node:util';
6
+ import escape from 'escape-html';
7
+ import {ProcedureError} from './procedureError.js';
8
+ import {RequestError} from './requestError.js';
9
+ import {inspectRequest, logToFile} from './trace.js';
10
+ import {errorToString} from './error.js';
11
+
12
+ /**
13
+ * @typedef {import('express').Request} Request
14
+ * @typedef {import('express').Response} Response
15
+ * @typedef {import('./types.js').BindParameterConfig} BindParameterConfig
16
+ * @typedef {import('./types.js').environmentType} environmentType
17
+ * @typedef {import('./types.js').configPlSqlHandlerType} configPlSqlHandlerType
18
+ * @typedef {{html: string; text: string}} outputType
19
+ */
20
+
21
+ /**
22
+ * Convert value to string
23
+ * @param {unknown} value - The value to convert.
24
+ * @returns {string} - The string representation of the value.
25
+ */
26
+ const inspect = (value) => util.inspect(value, {showHidden: false, depth: null, colors: false});
27
+
28
+ /**
29
+ * Convert LF and/or CR to <br>
30
+ * @param {string} text - The text to convert.
31
+ * @returns {string} - The converted text.
32
+ */
33
+ const convertToHtml = (text) => {
34
+ let html = escape(text);
35
+
36
+ html = html.replace(/(?:\r\n|\r|\n)/g, '<br />');
37
+ html = html.replace(/\t/g, '&nbsp;&nbsp;&nbsp;');
38
+
39
+ return html;
40
+ };
41
+
42
+ /**
43
+ * Get html
44
+ * @param {string} text - The text to convert.
45
+ * @returns {string} - The converted text.
46
+ */
47
+ const getHtml = (text) => `<p>${convertToHtml(text)}</p>`;
48
+
49
+ /**
50
+ * Get text header
51
+ * @param {string} text - The text to convert.
52
+ * @returns {string} - The converted text.
53
+ */
54
+ const getHeaderText = (text) => `\n${text}\n${'='.repeat(text.length)}\n`;
55
+
56
+ /**
57
+ * Get html header
58
+ * @param {string} text - The text to convert.
59
+ * @returns {string} - The converted text.
60
+ */
61
+ const getHeaderHtml = (text) => `<h1>${text}</h1>`;
62
+
63
+ /**
64
+ * Get text
65
+ * @param {string} text - The text to convert.
66
+ * @returns {string} - The converted text.
67
+ */
68
+ const getText = (text) => `${text}\n`;
69
+
70
+ /**
71
+ * Get evnironment
72
+ * @param {outputType} output - The output.
73
+ * @param {environmentType} environment - The environment.
74
+ */
75
+ const getEnvironment = (output, environment) => {
76
+ let html = '<table>';
77
+ let text = '';
78
+
79
+ try {
80
+ for (const key in environment) {
81
+ html += `<tr><td>${key}:</td><td>${environment[key]}</td></tr>`;
82
+ text += `${key}=${environment[key]}\n`;
83
+ }
84
+ } catch (err) {
85
+ /* istanbul ignore next */
86
+ output.html += errorToString(err);
87
+
88
+ /* istanbul ignore next */
89
+ output.text += errorToString(err);
90
+
91
+ /* istanbul ignore next */
92
+ return;
93
+ }
94
+
95
+ html += '</table>';
96
+
97
+ output.html += html;
98
+ output.text += text;
99
+ };
100
+
101
+ /**
102
+ * Show an error page
103
+ * @param {Request} req - The req object represents the HTTP request.
104
+ * @param {unknown} error - The error.
105
+ * @returns {outputType} - The output.
106
+ */
107
+ const getError = (req, error) => {
108
+ let timestamp = new Date();
109
+ let message = '';
110
+ /** @type {environmentType | null} */
111
+ let environment = null;
112
+ /** @type {string | null} */
113
+ let sql = null;
114
+ /** @type {BindParameterConfig} */
115
+ let bind = {};
116
+
117
+ // what type of Error did we receive
118
+ if (error instanceof ProcedureError) {
119
+ timestamp = error.timestamp;
120
+ /* istanbul ignore next */
121
+ message = error.stack ?? '';
122
+ environment = error.environment;
123
+ sql = error.sql;
124
+ bind = error.bind;
125
+ } else if (error instanceof RequestError) {
126
+ timestamp = error.timestamp;
127
+ /* istanbul ignore next */
128
+ message = error.stack ?? '';
129
+ } else if (error instanceof Error) {
130
+ /* istanbul ignore next */
131
+ message = errorToString(error);
132
+ } else {
133
+ if (typeof error === 'string') {
134
+ /* istanbul ignore next */
135
+ message = `${error}\n`;
136
+ }
137
+ try {
138
+ /* istanbul ignore next */
139
+ new Error();
140
+ } catch (err) {
141
+ /* istanbul ignore next */
142
+ message += errorToString(err);
143
+ }
144
+ }
145
+
146
+ /** @type {outputType} */
147
+ const output = {
148
+ html: '',
149
+ text: '',
150
+ };
151
+
152
+ // timestamp
153
+ let header = 'TIMESTAMP';
154
+ output.html += getHeaderHtml(header);
155
+ output.html += getHtml(timestamp.toUTCString());
156
+
157
+ // error
158
+ header = 'ERROR';
159
+ output.html += getHeaderHtml(header);
160
+ output.html += getHtml(message);
161
+ output.text += getHeaderText(header);
162
+ output.text += getText(message);
163
+
164
+ // request
165
+ header = 'REQUEST';
166
+ output.text += getHeaderText(header);
167
+ output.text += getText(inspectRequest(req));
168
+
169
+ // parameters
170
+ if (typeof sql === 'string' && bind) {
171
+ header = 'PROCEDURE';
172
+ output.html += getHeaderHtml(header);
173
+ output.text += getHeaderText(header);
174
+ getProcedure(output, sql, bind);
175
+ }
176
+
177
+ // environment
178
+ if (environment) {
179
+ header = 'ENVIRONMENT';
180
+ output.html += getHeaderHtml(header);
181
+ output.text += getHeaderText(header);
182
+ getEnvironment(output, environment);
183
+ }
184
+
185
+ return output;
186
+ };
187
+
188
+ /**
189
+ * Get procedure
190
+ * @param {outputType} output - The output.
191
+ * @param {string} sql - The SQL to execute.
192
+ * @param {BindParameterConfig} bind - The bind parameters.
193
+ */
194
+ const getProcedure = (output, sql, bind) => {
195
+ let html = '<table>';
196
+ let text = '';
197
+
198
+ text += `PROCEDURE: ${sql}\n`;
199
+ html += `<tr><td>PROCEDURE:</td><td>${sql}</td></tr>`;
200
+
201
+ try {
202
+ /* istanbul ignore else */
203
+ for (const key in bind) {
204
+ const value = inspect(bind[key].val);
205
+
206
+ html += `<tr><td>${key}:</td><td>${value}</td></tr>`;
207
+ text += `${key}: ${value}\n`;
208
+ }
209
+ } catch (err) {
210
+ /* istanbul ignore next */
211
+ output.html += err instanceof Error ? err.toString() : 'ERROR';
212
+
213
+ /* istanbul ignore next */
214
+ output.text += err instanceof Error ? err.toString() : 'ERROR';
215
+ /* istanbul ignore next */
216
+ return;
217
+ }
218
+
219
+ html += '</table>';
220
+
221
+ output.html += html;
222
+ output.text += text;
223
+ };
224
+
225
+ /**
226
+ * getHtmlPage
227
+ * @param {string} body - The body.
228
+ * @returns {string} - The html page.
229
+ */
230
+ const getHtmlPage = (body) => `<!DOCTYPE html>
231
+ <html lang="en">
232
+ <head>
233
+ <meta charset="utf-8">
234
+ <title>web_plsql error page</title>
235
+ <style type="text/css">
236
+ html {
237
+ font-family: monospace, sans-serif;
238
+ font-size: 12px;
239
+ }
240
+ h1 {
241
+ font-size: 16px;
242
+ padding: 2px;
243
+ background-color: #cc0000;
244
+ }
245
+ </style>
246
+ </head>
247
+ <body>
248
+ ${body}
249
+ </body>
250
+ </html>
251
+ `;
252
+
253
+ /**
254
+ * Show an error page
255
+ *
256
+ * @param {Request} req - The req object represents the HTTP request.
257
+ * @param {Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
258
+ * @param {configPlSqlHandlerType} options - The configuration options.
259
+ * @param {unknown} error - The error.
260
+ */
261
+ export const errorPage = (req, res, options, error) => {
262
+ let output = {
263
+ html: '',
264
+ text: '',
265
+ };
266
+
267
+ // get the error description
268
+ try {
269
+ output = getError(req, error);
270
+ } catch (err) {
271
+ /* istanbul ignore next */
272
+ const header = 'ERROR';
273
+
274
+ /* istanbul ignore next */
275
+ const message = errorToString(err);
276
+
277
+ /* istanbul ignore next */
278
+ output.html += getHeaderHtml(header) + getHtml(message);
279
+
280
+ /* istanbul ignore next */
281
+ output.text += getHeaderHtml(header) + getHtml(message);
282
+ }
283
+
284
+ // trace to file
285
+ logToFile(output.text);
286
+
287
+ // console
288
+ console.error(output.text);
289
+
290
+ // show page
291
+ if (options.errorStyle === 'basic') {
292
+ res.status(404).send('Page not found');
293
+ } else {
294
+ res.status(404).send(getHtmlPage(output.html));
295
+ }
296
+ };