web_plsql 1.0.0 → 1.3.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 (108) hide show
  1. package/README.md +108 -13
  2. package/dist/chunk-DQk6qfdC.mjs +18 -0
  3. package/dist/frontend/assets/main-0oxRTIkL.js +147 -0
  4. package/dist/frontend/assets/main-0oxRTIkL.js.br +0 -0
  5. package/dist/frontend/assets/main-0oxRTIkL.js.gz +0 -0
  6. package/dist/frontend/assets/main-TYgLak6O.css +1 -0
  7. package/dist/frontend/assets/main-TYgLak6O.css.br +0 -0
  8. package/dist/frontend/assets/main-TYgLak6O.css.gz +0 -0
  9. package/dist/frontend/index.html +516 -0
  10. package/dist/frontend/index.html.br +0 -0
  11. package/dist/frontend/index.html.gz +0 -0
  12. package/dist/index.d.mts +646 -0
  13. package/dist/index.mjs +3548 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/dist/oracledb-mock-Dn8aHtd7.mjs +68 -0
  16. package/dist/oracledb-mock-Dn8aHtd7.mjs.map +1 -0
  17. package/examples/config-apex.js +1 -1
  18. package/examples/config-docker.js +1 -2
  19. package/package.json +45 -32
  20. package/examples/config-native.js +0 -68
  21. package/src/admin/client/charts.ts +0 -299
  22. package/src/admin/client/main.js +0 -3
  23. package/src/admin/client/tailwind.css +0 -41
  24. package/src/admin/index.html +0 -315
  25. package/src/admin/js/api.ts +0 -95
  26. package/src/admin/js/app.ts +0 -306
  27. package/src/admin/js/eslint.config.js +0 -74
  28. package/src/admin/js/schemas.ts +0 -153
  29. package/src/admin/js/templates/config.ts +0 -146
  30. package/src/admin/js/templates/errorRow.ts +0 -18
  31. package/src/admin/js/templates/index.ts +0 -3
  32. package/src/admin/js/templates/poolCard.ts +0 -61
  33. package/src/admin/js/tsconfig.json +0 -24
  34. package/src/admin/js/types.ts +0 -223
  35. package/src/admin/js/ui/theme.ts +0 -93
  36. package/src/admin/js/ui/views.ts +0 -164
  37. package/src/admin/js/util/format.ts +0 -27
  38. package/src/admin/lib/assets/main-zpdhQ1gD.css +0 -1
  39. package/src/admin/lib/chart.bundle.js +0 -139
  40. package/src/admin/style.css +0 -1321
  41. package/src/bin/load-test.js +0 -202
  42. package/src/handler/handlerAdmin.js +0 -198
  43. package/src/handler/handlerLogger.js +0 -21
  44. package/src/handler/handlerMetrics.js +0 -68
  45. package/src/handler/handlerUpload.js +0 -26
  46. package/src/handler/plsql/cgi.js +0 -131
  47. package/src/handler/plsql/errorPage.js +0 -117
  48. package/src/handler/plsql/handlerPlSql.js +0 -90
  49. package/src/handler/plsql/parsePage.js +0 -213
  50. package/src/handler/plsql/procedure.js +0 -356
  51. package/src/handler/plsql/procedureError.js +0 -40
  52. package/src/handler/plsql/procedureNamed.js +0 -268
  53. package/src/handler/plsql/procedureSanitize.js +0 -262
  54. package/src/handler/plsql/procedureVariable.js +0 -54
  55. package/src/handler/plsql/request.js +0 -124
  56. package/src/handler/plsql/requestError.js +0 -23
  57. package/src/handler/plsql/sendResponse.js +0 -136
  58. package/src/handler/plsql/stream.js +0 -28
  59. package/src/handler/plsql/upload.js +0 -109
  60. package/src/index.js +0 -20
  61. package/src/server/config.js +0 -57
  62. package/src/server/connections.js +0 -40
  63. package/src/server/server.js +0 -289
  64. package/src/types.js +0 -150
  65. package/src/util/cache.js +0 -123
  66. package/src/util/errorToString.js +0 -24
  67. package/src/util/file.js +0 -91
  68. package/src/util/html.js +0 -53
  69. package/src/util/jsonLogger.js +0 -47
  70. package/src/util/oracle.js +0 -80
  71. package/src/util/shutdown.js +0 -44
  72. package/src/util/trace.js +0 -325
  73. package/src/util/type.js +0 -6
  74. package/src/util/util.js +0 -66
  75. package/src/version.js +0 -5
  76. package/types/handler/handlerAdmin.d.ts +0 -9
  77. package/types/handler/handlerLogger.d.ts +0 -2
  78. package/types/handler/handlerMetrics.d.ts +0 -25
  79. package/types/handler/handlerUpload.d.ts +0 -7
  80. package/types/handler/plsql/cgi.d.ts +0 -4
  81. package/types/handler/plsql/errorPage.d.ts +0 -11
  82. package/types/handler/plsql/handlerPlSql.d.ts +0 -13
  83. package/types/handler/plsql/parsePage.d.ts +0 -3
  84. package/types/handler/plsql/procedure.d.ts +0 -12
  85. package/types/handler/plsql/procedureError.d.ts +0 -23
  86. package/types/handler/plsql/procedureNamed.d.ts +0 -14
  87. package/types/handler/plsql/procedureSanitize.d.ts +0 -11
  88. package/types/handler/plsql/procedureVariable.d.ts +0 -10
  89. package/types/handler/plsql/request.d.ts +0 -9
  90. package/types/handler/plsql/requestError.d.ts +0 -8
  91. package/types/handler/plsql/sendResponse.d.ts +0 -6
  92. package/types/handler/plsql/upload.d.ts +0 -5
  93. package/types/index.d.ts +0 -11
  94. package/types/server/config.d.ts +0 -2
  95. package/types/server/server.d.ts +0 -74
  96. package/types/types.d.ts +0 -328
  97. package/types/util/cache.d.ts +0 -69
  98. package/types/util/errorToString.d.ts +0 -1
  99. package/types/util/file.d.ts +0 -6
  100. package/types/util/html.d.ts +0 -3
  101. package/types/util/jsonLogger.d.ts +0 -45
  102. package/types/util/oracle.d.ts +0 -5
  103. package/types/util/shutdown.d.ts +0 -2
  104. package/types/util/trace.d.ts +0 -22
  105. package/types/util/type.d.ts +0 -1
  106. package/types/util/util.d.ts +0 -3
  107. package/types/version.d.ts +0 -1
  108. /package/{src/admin/favicon.svg → dist/frontend/assets/favicon-mQAM4tVu.svg} +0 -0
@@ -1,117 +0,0 @@
1
- /*
2
- * Error handling
3
- */
4
-
5
- import {ProcedureError} from './procedureError.js';
6
- import {RequestError} from './requestError.js';
7
- import {getFormattedMessage, logToFile} from '../../util/trace.js';
8
- import {errorToString} from '../../util/errorToString.js';
9
- import {getHtmlPage} from '../../util/html.js';
10
- import {jsonLogger} from '../../util/jsonLogger.js';
11
- import {AdminContext} from '../../server/server.js';
12
-
13
- /**
14
- * @typedef {import('express').Request} Request
15
- * @typedef {import('express').Response} Response
16
- * @typedef {import('../../types.js').BindParameterConfig} BindParameterConfig
17
- * @typedef {import('../../types.js').environmentType} environmentType
18
- * @typedef {import('../../types.js').configPlSqlHandlerType} configPlSqlHandlerType
19
- * @typedef {{html: string; text: string}} outputType
20
- * @typedef {import('../../util/trace.js').messageType} messageType
21
- */
22
-
23
- /**
24
- * Get error data
25
- * @param {Request} req - The req object represents the HTTP request.
26
- * @param {unknown} error - The error.
27
- * @returns {messageType} - The output.
28
- */
29
- const getErrorData = (req, error) => {
30
- let timestamp = new Date();
31
- let message = '';
32
- /** @type {environmentType | null} */
33
- let environment = null;
34
- /** @type {string | null} */
35
- let sql = null;
36
- /** @type {BindParameterConfig | null} */
37
- let bind = null;
38
-
39
- // what type of Error did we receive
40
- if (error instanceof ProcedureError) {
41
- timestamp = error.timestamp;
42
- message = error.stack ?? '';
43
- environment = error.environment;
44
- sql = error.sql;
45
- bind = error.bind;
46
- } else if (error instanceof RequestError) {
47
- timestamp = error.timestamp;
48
- message = error.stack ?? '';
49
- } else if (error instanceof Error) {
50
- message = errorToString(error);
51
- } else {
52
- if (typeof error === 'string') {
53
- message = `${error}\n`;
54
- }
55
- /* v8 ignore start - unreachable code: creating Error without throwing */
56
- try {
57
- new Error();
58
- } catch (err) {
59
- message += errorToString(err);
60
- }
61
- /* v8 ignore stop */
62
- }
63
-
64
- return {type: 'error', timestamp, message, req, environment, sql, bind};
65
- };
66
-
67
- /**
68
- * Show an error page
69
- *
70
- * @param {Request} req - The req object represents the HTTP request.
71
- * @param {Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
72
- * @param {configPlSqlHandlerType} options - The configuration options.
73
- * @param {unknown} error - The error.
74
- */
75
- export const errorPage = (req, res, options, error) => {
76
- // get error data
77
- const errorData = getErrorData(req, error);
78
-
79
- // Update metrics
80
- AdminContext.metrics.errorCount++;
81
-
82
- // get formatted message
83
- const {html, text} = getFormattedMessage(errorData);
84
-
85
- // trace to file
86
- logToFile(text);
87
-
88
- // json log
89
- const firstLine = errorData.message.split('\n')[0];
90
- jsonLogger.log({
91
- timestamp: errorData.timestamp?.toISOString() ?? new Date().toISOString(),
92
- type: 'error',
93
- message: firstLine ?? '',
94
- req: {
95
- method: req.method,
96
- url: req.originalUrl,
97
- ip: req.ip ?? '',
98
- userAgent: req.get('user-agent') ?? '',
99
- },
100
- details: {
101
- fullMessage: errorData.message,
102
- sql: errorData.sql,
103
- bind: errorData.bind,
104
- environment: errorData.environment,
105
- },
106
- });
107
-
108
- // console
109
- console.error(text);
110
-
111
- // show page
112
- if (options.errorStyle === 'basic') {
113
- res.status(404).send('Page not found');
114
- } else {
115
- res.status(404).send(getHtmlPage(html));
116
- }
117
- };
@@ -1,90 +0,0 @@
1
- /*
2
- * Express middleware for Oracle PL/SQL
3
- */
4
-
5
- import debugModule from 'debug';
6
- const debug = debugModule('webplsql:handlerPlSql');
7
-
8
- import url from 'node:url';
9
- import {processRequest} from './request.js';
10
- import {RequestError} from './requestError.js';
11
- import {errorPage} from './errorPage.js';
12
- import {Cache} from '../../util/cache.js';
13
-
14
- /**
15
- * @typedef {import('express').RequestHandler} RequestHandler
16
- * @typedef {import('express').Request} Request
17
- * @typedef {import('express').Response} Response
18
- * @typedef {import('express').NextFunction} NextFunction
19
- * @typedef {import('oracledb').Pool} Pool
20
- * @typedef {import('../../types.js').environmentType} environmentType
21
- * @typedef {import('../../types.js').configPlSqlHandlerType} configPlSqlHandlerType
22
- */
23
-
24
- /**
25
- * express.Request handler
26
- * @param {Request} req - The req object represents the HTTP request.
27
- * @param {Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
28
- * @param {NextFunction} _next - The next function.
29
- * @param {Pool} connectionPool - The connection pool.
30
- * @param {configPlSqlHandlerType} options - the options for the middleware.
31
- * @param {Cache<string>} procedureNameCache - The procedure name cache.
32
- * @param {Cache<import('./procedureNamed.js').argsType>} argumentCache - The argument cache.
33
- */
34
- const requestHandler = async (req, res, _next, connectionPool, options, procedureNameCache, argumentCache) => {
35
- try {
36
- // should we switch to the default page if there is one defined
37
- if (typeof req.params.name !== 'string' || req.params.name.length === 0) {
38
- if (typeof options.defaultPage === 'string' && options.defaultPage.length > 0) {
39
- const newUrl = url.resolve(`${req.originalUrl}/${options.defaultPage}`, '');
40
- debug(`Redirect to the url "${newUrl}"`);
41
- res.redirect(newUrl);
42
- } else {
43
- errorPage(req, res, options, new RequestError('No procedure name given and no default page has been specified'));
44
- }
45
- } else {
46
- // request handler
47
- await processRequest(req, res, options, connectionPool, procedureNameCache, argumentCache);
48
- }
49
- } catch (err) {
50
- errorPage(req, res, options, err);
51
- }
52
- };
53
-
54
- /**
55
- * @typedef {import('express').RequestHandler & {
56
- * procedureNameCache: Cache<string>;
57
- * argumentCache: Cache<import('./procedureNamed.js').argsType>;
58
- * }} WebPlSqlRequestHandler
59
- */
60
-
61
- /**
62
- * Express middleware.
63
- *
64
- * @param {Pool} connectionPool - The connection pool.
65
- * @param {configPlSqlHandlerType} config - The configuration options.
66
- * @returns {WebPlSqlRequestHandler} - The handler.
67
- */
68
- export const handlerWebPlSql = (connectionPool, config) => {
69
- debug('options', config);
70
-
71
- /** @type {Cache<string>} */
72
- const procedureNameCache = new Cache();
73
- /** @type {Cache<import('./procedureNamed.js').argsType>} */
74
- const argumentCache = new Cache();
75
-
76
- /**
77
- * @param {Request} req - The request.
78
- * @param {Response} res - The response.
79
- * @param {NextFunction} next - The next function.
80
- */
81
- const handler = (req, res, next) => {
82
- void requestHandler(req, res, next, connectionPool, config, procedureNameCache, argumentCache);
83
- };
84
-
85
- // Expose caches for Admin Console
86
- handler.procedureNameCache = procedureNameCache;
87
- handler.argumentCache = argumentCache;
88
-
89
- return handler;
90
- };
@@ -1,213 +0,0 @@
1
- import debugModule from 'debug';
2
- const debug = debugModule('webplsql:parsePage');
3
-
4
- /**
5
- * @typedef {import('../../types.js').pageType} pageType
6
- * @typedef {import('../../types.js').cookieType} cookieType
7
- */
8
-
9
- /**
10
- * Parse the header and split it up into the individual components
11
- *
12
- * @param {string} text - The text returned from the PL/SQL procedure.
13
- * @returns {pageType} - The parsed page.
14
- */
15
- export const parsePage = (text) => {
16
- /** @type {pageType} */
17
- const page = {
18
- body: '',
19
- head: {
20
- cookies: [],
21
- otherHeaders: {},
22
- },
23
- file: {
24
- fileType: null,
25
- fileSize: null,
26
- fileBlob: null,
27
- },
28
- };
29
-
30
- //
31
- // 1) Split up the text in header and body
32
- //
33
-
34
- // Find the end of the header identified by \n\n
35
- let head = '';
36
- const headerEndPosition = text.indexOf('\n\n');
37
- if (headerEndPosition === -1) {
38
- head = text;
39
- } else {
40
- head = text.substring(0, headerEndPosition + 2);
41
- page.body = text.substring(headerEndPosition + 2);
42
- }
43
-
44
- //
45
- // 2) parse the headers
46
- //
47
-
48
- debug('parsing the headers received from PL/SQL');
49
- head.split('\n').forEach((line) => {
50
- const header = getHeader(line);
51
-
52
- if (header) {
53
- switch (header.name.toLowerCase()) {
54
- case 'set-cookie':
55
- {
56
- const cookie = parseCookie(header.value);
57
- debug(`oracle header "set-cookie" with value "${header.value}" was received has been parsed to ${JSON.stringify(cookie)}`);
58
- /* v8 ignore else - parseCookie validation ensures non-null */
59
- if (cookie !== null) {
60
- page.head.cookies.push(cookie);
61
- } else {
62
- throw new Error(`Unable to parse header "set-cookie" with value "${header.value}" received from PL/SQL`);
63
- }
64
- }
65
- break;
66
-
67
- case 'content-type':
68
- page.head.contentType = header.value;
69
- debug(`oracle header "content-type" with value "${page.head.contentType}" was parsed`);
70
- break;
71
-
72
- case 'x-db-content-length':
73
- {
74
- const contentLength = parseInt(header.value, 10);
75
- /* v8 ignore else - parseInt validation */
76
- if (!Number.isNaN(contentLength)) {
77
- page.head.contentLength = contentLength;
78
- debug(`oracle header "x-db-content-length" with value "${page.head.contentLength}" was parsed`);
79
- } else {
80
- throw new Error(`Unable to parse header "x-db-content-length" with value "${header.value}" received from PL/SQL`);
81
- }
82
- }
83
- break;
84
-
85
- case 'status':
86
- {
87
- const statusCode = parseInt(header.value, 10);
88
- /* v8 ignore else - parseInt validation */
89
- if (!Number.isNaN(statusCode)) {
90
- page.head.statusCode = statusCode;
91
- debug(`oracle header "status" with value "${page.head.statusCode}" was parsed`);
92
- const index = header.value.indexOf(' ');
93
- /* v8 ignore else - status code may not have description */
94
- if (index !== -1) {
95
- page.head.statusDescription = header.value.substring(index + 1);
96
- }
97
- } else {
98
- throw new Error(`Unable to parse header "status" with value "${header.value}" received from PL/SQL`);
99
- }
100
- }
101
- break;
102
-
103
- case 'location':
104
- page.head.redirectLocation = header.value;
105
- debug(`oracle header "location" with value "${page.head.statusCode}" was parsed`);
106
- break;
107
-
108
- case 'x-oracle-ignore':
109
- break;
110
-
111
- default:
112
- page.head.otherHeaders[header.name] = header.value;
113
- break;
114
- }
115
- }
116
- });
117
-
118
- return page;
119
- };
120
-
121
- /**
122
- * Get a header line
123
- * @param {string} line - The line
124
- * @returns {{name: string, value: string} | null} - The header.
125
- */
126
- const getHeader = (line) => {
127
- const index = line.indexOf(':');
128
-
129
- if (index !== -1) {
130
- return {
131
- name: line.substring(0, index).trim(),
132
- value: line.substring(index + 1).trim(),
133
- };
134
- }
135
-
136
- return null;
137
- };
138
-
139
- /**
140
- * Parses a cookie string
141
- * @param {string} text - The cookie string.
142
- * @returns {cookieType | null} - The parsed cookie.
143
- */
144
- const parseCookie = (text) => {
145
- // validate
146
- /* v8 ignore next - input validation */
147
- if (typeof text !== 'string' || text.trim().length === 0) {
148
- return null;
149
- }
150
-
151
- // split the cookie into it's parts
152
- let cookieElements = text.split(';');
153
-
154
- // trim cookie elements
155
- cookieElements = cookieElements.map((element) => element.trim());
156
-
157
- // get name and value
158
- const firstElement = cookieElements[0];
159
- if (!firstElement) {
160
- return null;
161
- }
162
- const index = firstElement.indexOf('=');
163
- /* v8 ignore next - cookie format validation */
164
- if (index <= 0) {
165
- // if the index is -1, there is no equal sign and if it's 0 the name is empty
166
- return null;
167
- }
168
-
169
- /** @type {cookieType} */
170
- const cookie = {
171
- name: firstElement.substring(0, index).trim(),
172
- value: firstElement.substring(index + 1).trim(),
173
- options: {},
174
- };
175
-
176
- // remove the first element
177
- cookieElements.shift();
178
-
179
- // get the other options
180
- cookieElements.forEach((element) => {
181
- if (element.startsWith('path=')) {
182
- cookie.options.path = element.substring(5);
183
- } else if (element.toLowerCase().startsWith('domain=')) {
184
- cookie.options.domain = element.substring(7);
185
- } else if (element.toLowerCase().startsWith('secure=')) {
186
- /* v8 ignore next - secure cookie attribute */
187
- cookie.options.secure = true;
188
- } else if (element.toLowerCase().startsWith('expires=')) {
189
- const date = tryDecodeDate(element.substring(8));
190
- if (date) {
191
- cookie.options.expires = date;
192
- }
193
- } else if (element.toLowerCase().startsWith('httponly')) {
194
- cookie.options.httpOnly = true;
195
- }
196
- });
197
-
198
- return cookie;
199
- };
200
-
201
- /**
202
- * Try to decode a date
203
- * @param {string} value - The value to decode.
204
- * @returns {Date | null} - The decoded date or null.
205
- */
206
- const tryDecodeDate = (value) => {
207
- try {
208
- return new Date(value);
209
- } catch (err) {
210
- /* v8 ignore next - invalid date format */
211
- return null;
212
- }
213
- };