web_plsql 0.6.0 → 0.10.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/README.md +22 -5
- package/examples/{server_apex.js → config-apex.js} +3 -5
- package/examples/config-docker.js +31 -0
- package/examples/config-docker.json +26 -0
- package/examples/{server_sample.js → config-native.js} +4 -4
- package/examples/sql/install.sql +3 -3
- package/package.json +34 -31
- package/src/file.js +21 -3
- package/src/index.js +1 -1
- package/src/procedureSanitize.js +1 -1
- package/src/server.js +155 -32
- package/src/trace.js +1 -1
- package/src/types.js +30 -35
- package/src/version.js +15 -0
- package/types/file.d.ts +1 -0
- package/types/index.d.ts +1 -1
- package/types/server.d.ts +8 -1
- package/types/stream.d.ts +1 -0
- package/types/trace.d.ts +1 -0
- package/types/types.d.ts +68 -6
- package/types/version.d.ts +1 -0
package/README.md
CHANGED
|
@@ -25,16 +25,27 @@ Please visit the [node-oracledb](https://node-oracledb.readthedocs.io/en/latest/
|
|
|
25
25
|
* Install package (`npm i --omit=dev web_plsql`)
|
|
26
26
|
|
|
27
27
|
# Example
|
|
28
|
+
|
|
29
|
+
## Native
|
|
28
30
|
* Change to the `examples/sql` directory, start SQLPLus, connect to the database as SYS specifying the SYSDBA roleInstall and install the sample schema `@examples/sql/install.sql`.
|
|
29
|
-
* Start
|
|
31
|
+
* Start server using `node examples/config-native.js` after having set the WEB_PLSQL_ORACLE_SERVER environment variable to the database where you just installed the sample schema.
|
|
30
32
|
* Invoke a browser and open the page `http://localhost/sample`.
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
## Container
|
|
35
|
+
* Build the image using `npm run image-build`.
|
|
36
|
+
* Adapt the `examples/config-docker.json` configuration file. Typically only the `connectString` property must be changed.
|
|
37
|
+
* Start the container using `docker compose up -d`.
|
|
38
|
+
|
|
39
|
+
# Configuration
|
|
40
|
+
|
|
41
|
+
There are 2 options on how to use the web_plsql express middleware:
|
|
42
|
+
- Use the predefined `startHttpServer` api in `src/server.js` like in the `examples/config-native.js` example
|
|
43
|
+
- Hand craft a new Express server using the `handlerWebPlSql` middleware in `src/handlerPlSql.js`
|
|
44
|
+
|
|
45
|
+
## Use the predefined `startHttpServer`
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
The `startHttpServer` api uses the following configuration object:
|
|
36
48
|
|
|
37
|
-
The the default server implemented in `src/server.js` and has the following configuration options:
|
|
38
49
|
```
|
|
39
50
|
/**
|
|
40
51
|
* @typedef {'basic' | 'debug'} errorStyleType
|
|
@@ -73,6 +84,12 @@ export const z$errorStyleType = z.enum(['basic', 'debug']);
|
|
|
73
84
|
*/
|
|
74
85
|
```
|
|
75
86
|
|
|
87
|
+
## Hand craft a new Express server using the `handlerWebPlSql` middleware
|
|
88
|
+
|
|
89
|
+
WIP
|
|
90
|
+
|
|
91
|
+
# Compare with mod_plsql
|
|
92
|
+
|
|
76
93
|
The following mod_plsql DAD configuration translates to the configuration options as follows:
|
|
77
94
|
|
|
78
95
|
**DAD**
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import {startHttpServer} from '../src/index.js';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
void startServer({
|
|
3
|
+
void startHttpServer({
|
|
6
4
|
port: 80,
|
|
7
5
|
routeStatic: [
|
|
8
6
|
{
|
|
@@ -15,7 +13,7 @@ void startServer({
|
|
|
15
13
|
route: '/apex',
|
|
16
14
|
user: 'APEX_PUBLIC_USER',
|
|
17
15
|
password: 'secret',
|
|
18
|
-
connectString:
|
|
16
|
+
connectString: 'localhost:1521/orcl',
|
|
19
17
|
defaultPage: 'apex',
|
|
20
18
|
pathAlias: 'r',
|
|
21
19
|
pathAliasProcedure: 'wwv_flow.resolve_friendly_url',
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// @ts-expect-error NOTE: the following import would show an error because the path does not exist
|
|
4
|
+
import {startHttpServer} from './src/index.js';
|
|
5
|
+
|
|
6
|
+
void startHttpServer({
|
|
7
|
+
port: 8888,
|
|
8
|
+
routeStatic: [
|
|
9
|
+
{
|
|
10
|
+
route: '/static',
|
|
11
|
+
directoryPath: 'examples/static',
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
routePlSql: [
|
|
15
|
+
{
|
|
16
|
+
route: '/sample',
|
|
17
|
+
user: 'sample', // PlsqlDatabaseUserName
|
|
18
|
+
password: 'sample', // PlsqlDatabasePassword
|
|
19
|
+
connectString: 'host.docker.internal:1521/TEST', // PlsqlDatabaseConnectString
|
|
20
|
+
defaultPage: 'sample_pkg.page_index', // PlsqlDefaultPage
|
|
21
|
+
documentTable: 'doctable', // PlsqlDocumentTablename
|
|
22
|
+
exclusionList: ['sample_pkg.page_exclusion_list'], // PlsqlExclusionList
|
|
23
|
+
requestValidationFunction: 'sample_pkg.request_validation_function', // PlsqlRequestValidationFunction
|
|
24
|
+
pathAlias: 'myalias', // PlsqlPathAlias
|
|
25
|
+
pathAliasProcedure: 'sample_pkg.page_path_alias', // PlsqlPathAliasProcedure
|
|
26
|
+
errorStyle: 'debug', // PlsqlErrorStyle
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
loggerFilename: 'access.log', // PlsqlLogEnable and PlsqlLogDirectory
|
|
30
|
+
monitorConsole: false,
|
|
31
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"port": 8888,
|
|
3
|
+
"routeStatic": [
|
|
4
|
+
{
|
|
5
|
+
"route": "/static",
|
|
6
|
+
"directoryPath": "examples/static"
|
|
7
|
+
}
|
|
8
|
+
],
|
|
9
|
+
"routePlSql": [
|
|
10
|
+
{
|
|
11
|
+
"route": "/sample",
|
|
12
|
+
"user": "sample",
|
|
13
|
+
"password": "sample",
|
|
14
|
+
"connectString": "host.docker.internal:1521/TEST",
|
|
15
|
+
"defaultPage": "sample_pkg.page_index",
|
|
16
|
+
"documentTable": "doctable",
|
|
17
|
+
"exclusionList": ["sample_pkg.page_exclusion_list"],
|
|
18
|
+
"requestValidationFunction": "sample_pkg.request_validation_function",
|
|
19
|
+
"pathAlias": "myalias",
|
|
20
|
+
"pathAliasProcedure": "sample_pkg.page_path_alias",
|
|
21
|
+
"errorStyle": "debug"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"loggerFilename": "access.log",
|
|
25
|
+
"monitorConsole": false
|
|
26
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {startHttpServer} from '../src/index.js';
|
|
4
4
|
|
|
5
|
-
void
|
|
6
|
-
port:
|
|
5
|
+
void startHttpServer({
|
|
6
|
+
port: 8888,
|
|
7
7
|
routeStatic: [
|
|
8
8
|
{
|
|
9
9
|
route: '/static',
|
|
@@ -15,7 +15,7 @@ void startServer({
|
|
|
15
15
|
route: '/sample',
|
|
16
16
|
user: 'sample', // PlsqlDatabaseUserName
|
|
17
17
|
password: 'sample', // PlsqlDatabasePassword
|
|
18
|
-
connectString: process.env.
|
|
18
|
+
connectString: process.env.WEB_PLSQL_ORACLE_SERVER ?? 'localhost:1521/TEST', // PlsqlDatabaseConnectString
|
|
19
19
|
defaultPage: 'sample_pkg.page_index', // PlsqlDefaultPage
|
|
20
20
|
documentTable: 'doctable', // PlsqlDocumentTablename
|
|
21
21
|
exclusionList: ['sample_pkg.page_exclusion_list'], // PlsqlExclusionList
|
package/examples/sql/install.sql
CHANGED
|
@@ -19,10 +19,10 @@ GRANT execute on dbms_lob TO &&SAMPLE_USER;
|
|
|
19
19
|
ALTER SESSION SET CURRENT_SCHEMA=&&SAMPLE_USER;
|
|
20
20
|
|
|
21
21
|
-- install document table
|
|
22
|
-
|
|
22
|
+
@@doctable.sql
|
|
23
23
|
|
|
24
24
|
-- install package
|
|
25
|
-
|
|
25
|
+
@@sample_package.sql
|
|
26
26
|
show errors
|
|
27
|
-
|
|
27
|
+
@@sample_package_body.sql
|
|
28
28
|
show errors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "web_plsql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"author": "Dieter Oberkofler <dieter.oberkofler@gmail.com>",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "The Express Middleware for Oracle PL/SQL",
|
|
@@ -43,50 +43,53 @@
|
|
|
43
43
|
"types": "./types/index.d.ts",
|
|
44
44
|
"type": "module",
|
|
45
45
|
"scripts": {
|
|
46
|
-
"lint": "prettier --check . && eslint . && tsc --noEmit",
|
|
46
|
+
"lint": "prettier --check --experimental-cli . && eslint . && tsc --noEmit",
|
|
47
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",
|
|
48
|
+
"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
49
|
"clean": "shx rm -f *.tgz && shx rm -f *.log",
|
|
50
50
|
"ci": "npm run clean && npm run lint && npm run test",
|
|
51
|
-
"create-package": "shx rm -f *.tgz && npm pack"
|
|
51
|
+
"create-package": "shx rm -f *.tgz && npm pack",
|
|
52
|
+
"image-build": "docker build --no-cache --progress=plain --tag=web_plsql .",
|
|
53
|
+
"image-save": "docker save web_plsql | gzip > web_plsql.tar.gz"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"oracledb": "6.9.0"
|
|
52
57
|
},
|
|
53
58
|
"dependencies": {
|
|
54
59
|
"basic-auth": "2.0.1",
|
|
55
|
-
"body-parser": "
|
|
56
|
-
"compression": "1.
|
|
57
|
-
"connect-multiparty": "2.2.0",
|
|
60
|
+
"body-parser": "2.2.0",
|
|
61
|
+
"compression": "1.8.1",
|
|
58
62
|
"cookie-parser": "1.4.7",
|
|
59
|
-
"debug": "4.4.
|
|
63
|
+
"debug": "4.4.1",
|
|
60
64
|
"escape-html": "1.0.3",
|
|
61
|
-
"express": "
|
|
62
|
-
"fs-extra": "11.3.
|
|
63
|
-
"http-parser-js": "0.5.
|
|
64
|
-
"morgan": "1.10.
|
|
65
|
-
"multer": "
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"zod": "3.24.1"
|
|
65
|
+
"express": "5.1.0",
|
|
66
|
+
"fs-extra": "11.3.1",
|
|
67
|
+
"http-parser-js": "0.5.10",
|
|
68
|
+
"morgan": "1.10.1",
|
|
69
|
+
"multer": "2.0.2",
|
|
70
|
+
"rotating-file-stream": "3.2.6",
|
|
71
|
+
"zod": "4.0.17"
|
|
69
72
|
},
|
|
70
73
|
"devDependencies": {
|
|
71
74
|
"@types/basic-auth": "1.1.8",
|
|
72
|
-
"@types/body-parser": "1.19.
|
|
73
|
-
"@types/compression": "1.
|
|
74
|
-
"@types/cookie-parser": "1.4.
|
|
75
|
+
"@types/body-parser": "1.19.6",
|
|
76
|
+
"@types/compression": "1.8.1",
|
|
77
|
+
"@types/cookie-parser": "1.4.9",
|
|
75
78
|
"@types/debug": "4.1.12",
|
|
76
79
|
"@types/escape-html": "1.0.4",
|
|
77
80
|
"@types/fs-extra": "11.0.4",
|
|
78
|
-
"@types/morgan": "1.9.
|
|
79
|
-
"@types/multer": "
|
|
80
|
-
"@types/node": "
|
|
81
|
-
"@types/oracledb": "6.
|
|
82
|
-
"@types/supertest": "6.0.
|
|
83
|
-
"eslint": "9.
|
|
84
|
-
"eslint-plugin-jsdoc": "
|
|
85
|
-
"prettier": "3.
|
|
81
|
+
"@types/morgan": "1.9.10",
|
|
82
|
+
"@types/multer": "2.0.0",
|
|
83
|
+
"@types/node": "24.3.0",
|
|
84
|
+
"@types/oracledb": "6.9.1",
|
|
85
|
+
"@types/supertest": "6.0.3",
|
|
86
|
+
"eslint": "9.33.0",
|
|
87
|
+
"eslint-plugin-jsdoc": "54.1.0",
|
|
88
|
+
"prettier": "3.6.2",
|
|
86
89
|
"rimraf": "6.0.1",
|
|
87
|
-
"shx": "0.
|
|
88
|
-
"supertest": "7.
|
|
89
|
-
"typescript": "5.
|
|
90
|
-
"typescript-eslint": "8.
|
|
90
|
+
"shx": "0.4.0",
|
|
91
|
+
"supertest": "7.1.4",
|
|
92
|
+
"typescript": "5.9.2",
|
|
93
|
+
"typescript-eslint": "8.39.1"
|
|
91
94
|
}
|
|
92
95
|
}
|
package/src/file.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import {promises as fs, readFileSync} from 'node:fs';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Read file.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} filePath - File name.
|
|
7
|
+
* @returns {string} The string.
|
|
8
|
+
*/
|
|
9
|
+
export const readFileSyncUtf8 = (filePath) => {
|
|
10
|
+
try {
|
|
11
|
+
return readFileSync(filePath, 'utf8');
|
|
12
|
+
} catch (err) {
|
|
13
|
+
/* istanbul ignore next */
|
|
14
|
+
throw new Error(`Unable to read file "${filePath}"`);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
3
18
|
/**
|
|
4
19
|
* Read file.
|
|
5
20
|
*
|
|
@@ -71,7 +86,10 @@ export const isFile = async (filePath) => {
|
|
|
71
86
|
return false;
|
|
72
87
|
}
|
|
73
88
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
try {
|
|
90
|
+
const stats = await fs.stat(filePath);
|
|
91
|
+
return stats.isFile();
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
77
95
|
};
|
package/src/index.js
CHANGED
package/src/procedureSanitize.js
CHANGED
|
@@ -135,7 +135,7 @@ const loadRequestValid = async (procName, requestValidationFunction, databaseCon
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
try {
|
|
138
|
-
const data = z.
|
|
138
|
+
const data = z.strictObject({valid: z.number()}).parse(result.outBinds);
|
|
139
139
|
return data.valid === 1;
|
|
140
140
|
} catch (err) {
|
|
141
141
|
debug('result', result.outBinds);
|
package/src/server.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import debugModule from 'debug';
|
|
2
2
|
const debug = debugModule('webplsql:server');
|
|
3
3
|
|
|
4
|
+
import http from 'node:http';
|
|
5
|
+
import https from 'node:https';
|
|
4
6
|
import express from 'express';
|
|
5
7
|
import bodyParser from 'body-parser';
|
|
6
8
|
import cookieParser from 'cookie-parser';
|
|
@@ -13,9 +15,11 @@ import {handlerUpload} from './handlerUpload.js';
|
|
|
13
15
|
import {handlerLogger} from './handlerLogger.js';
|
|
14
16
|
import {initMetrics, handlerMetrics} from './handlerMetrics.js';
|
|
15
17
|
import {handlerWebPlSql} from './handlerPlSql.js';
|
|
16
|
-
import {getPackageVersion} from './version.js';
|
|
18
|
+
import {getPackageVersion, getExpressVersion} from './version.js';
|
|
19
|
+
import {readFileSyncUtf8, getJsonFile} from './file.js';
|
|
17
20
|
|
|
18
21
|
/**
|
|
22
|
+
* @typedef {import('express').Express} Express
|
|
19
23
|
* @typedef {import('express').Request} Request
|
|
20
24
|
* @typedef {import('express').Response} Response
|
|
21
25
|
* @typedef {import('express').NextFunction} NextFunction
|
|
@@ -25,41 +29,150 @@ import {getPackageVersion} from './version.js';
|
|
|
25
29
|
*/
|
|
26
30
|
|
|
27
31
|
/**
|
|
28
|
-
*
|
|
32
|
+
* Show configuration.
|
|
29
33
|
* @param {configType} config - The config.
|
|
30
|
-
* @returns {
|
|
34
|
+
* @returns {void}
|
|
31
35
|
*/
|
|
32
|
-
export const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
export const showConfig = (config) => {
|
|
37
|
+
const expressVersion = getExpressVersion();
|
|
38
|
+
const packageVersion = getPackageVersion();
|
|
39
|
+
|
|
40
|
+
console.log('-'.repeat(80));
|
|
41
|
+
console.log('NODE PL/SQL SERVER');
|
|
42
|
+
console.log('-'.repeat(80));
|
|
43
|
+
|
|
44
|
+
console.log(`Application version: ${packageVersion}`);
|
|
45
|
+
console.log(`Express version: ${expressVersion}`);
|
|
46
|
+
console.log(`Server port: ${config.port}`);
|
|
47
|
+
console.log(`Access log: ${config.loggerFilename.length > 0 ? config.loggerFilename : ''}`);
|
|
48
|
+
console.log(`Monitor console: ${config.monitorConsole ? 'on' : 'off'}`);
|
|
49
|
+
|
|
50
|
+
if (config.routeStatic.length > 0) {
|
|
51
|
+
console.log('');
|
|
52
|
+
config.routeStatic.forEach((e, i) => {
|
|
53
|
+
console.log(`Static route #${i + 1}`);
|
|
54
|
+
console.log(` Route: "${e.route}"`);
|
|
55
|
+
console.log(` Directory path: "${e.directoryPath}"`);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
36
58
|
|
|
37
|
-
|
|
59
|
+
if (config.routePlSql.length > 0) {
|
|
60
|
+
console.log('');
|
|
61
|
+
config.routePlSql.forEach((e, i) => {
|
|
62
|
+
console.log(`Application route #${i + 1}`);
|
|
63
|
+
console.log(` Route: "http://localhost:${config.port}${e.route}"`);
|
|
64
|
+
console.log(` Oracle user: "${e.user}"`);
|
|
65
|
+
console.log(` Oracle server: "${e.connectString}"`);
|
|
66
|
+
console.log(` Oracle document table: "${e.documentTable}"`);
|
|
67
|
+
console.log(` Default page: "${e.defaultPage}"`);
|
|
68
|
+
console.log(` Path alias: "${e.pathAlias}"`);
|
|
69
|
+
console.log(` Path alias procedure: "${e.pathAliasProcedure}"`);
|
|
70
|
+
console.log(` Exclution list: "${e.exclusionList?.join(', ')}"`);
|
|
71
|
+
console.log(` Request validation function: "${e.requestValidationFunction}"`);
|
|
72
|
+
console.log(` Error style: "${e.errorStyle}"`);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
38
75
|
|
|
39
|
-
|
|
40
|
-
|
|
76
|
+
console.log('-'.repeat(80));
|
|
77
|
+
};
|
|
41
78
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Create HTTP server.
|
|
81
|
+
* @param {Express} app - express application
|
|
82
|
+
* @param {number} port - port number
|
|
83
|
+
* @param {Pool[]} connectionPools - database connection
|
|
84
|
+
* @returns {Promise<http.Server>} - server
|
|
85
|
+
*/
|
|
86
|
+
export const createHttpServer = (app, port, connectionPools) => {
|
|
87
|
+
return new Promise((resolve) => {
|
|
88
|
+
// Create server
|
|
89
|
+
const server = http.createServer({}, app);
|
|
90
|
+
|
|
91
|
+
// Install shutdown handler
|
|
92
|
+
installShutdown(async () => {
|
|
93
|
+
// Close database pool.
|
|
94
|
+
await poolsClose(connectionPools);
|
|
95
|
+
|
|
96
|
+
// Close server
|
|
97
|
+
return new Promise((resolve) => server.close(() => resolve()));
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Listen on HTTP ports
|
|
101
|
+
server.listen(port, () => {
|
|
102
|
+
resolve(server);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
};
|
|
47
106
|
|
|
48
|
-
|
|
49
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Create HTTPS server.
|
|
109
|
+
* @param {Express} app - express application
|
|
110
|
+
* @param {string} sslKeyFilename - ssl
|
|
111
|
+
* @param {string} sslCertFilename - ssl
|
|
112
|
+
* @param {number} port - port number
|
|
113
|
+
* @param {Pool[]} connectionPools - database connection
|
|
114
|
+
* @returns {Promise<https.Server>} - server
|
|
115
|
+
*/
|
|
116
|
+
export const createHttpsServer = (app, sslKeyFilename, sslCertFilename, port, connectionPools) => {
|
|
117
|
+
return new Promise((resolve) => {
|
|
118
|
+
// Load certificates
|
|
119
|
+
const key = readFileSyncUtf8(sslKeyFilename);
|
|
120
|
+
const cert = readFileSyncUtf8(sslCertFilename);
|
|
121
|
+
|
|
122
|
+
// Create server
|
|
123
|
+
const server = https.createServer({key, cert}, app);
|
|
124
|
+
|
|
125
|
+
// Install shutdown handler
|
|
126
|
+
installShutdown(async () => {
|
|
127
|
+
// Close database pool.
|
|
128
|
+
await poolsClose(connectionPools);
|
|
129
|
+
|
|
130
|
+
// Close server
|
|
131
|
+
return new Promise((resolve) => server.close(() => resolve()));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Listen on HTTP ports
|
|
135
|
+
server.listen(port, () => {
|
|
136
|
+
resolve(server);
|
|
137
|
+
});
|
|
50
138
|
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Start HTTP server.
|
|
143
|
+
* @param {configType} config - The config.
|
|
144
|
+
* @returns {Promise<void>} - Promise.
|
|
145
|
+
*/
|
|
146
|
+
export const startHttpServer = async (config) => {
|
|
147
|
+
debug('startHttpServer', config);
|
|
148
|
+
|
|
149
|
+
config = z$configType.parse(config);
|
|
150
|
+
|
|
151
|
+
showConfig(config);
|
|
51
152
|
|
|
52
153
|
// Create express app
|
|
53
154
|
const app = express();
|
|
54
155
|
|
|
156
|
+
// Debug requests
|
|
157
|
+
if (debug.enabled) {
|
|
158
|
+
app.use((req, res, next) => {
|
|
159
|
+
console.log(`Request: "${req.method}" "${req.url}"`);
|
|
160
|
+
next();
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
55
164
|
// Metrics
|
|
56
165
|
const metrics = initMetrics();
|
|
57
166
|
app.use(handlerMetrics(metrics));
|
|
58
167
|
|
|
168
|
+
// Access log
|
|
169
|
+
if (config.loggerFilename.length > 0) {
|
|
170
|
+
app.use(handlerLogger(config.loggerFilename));
|
|
171
|
+
}
|
|
172
|
+
|
|
59
173
|
// Serving static files
|
|
60
174
|
for (const i of config.routeStatic) {
|
|
61
175
|
app.use(i.route, express.static(i.directoryPath));
|
|
62
|
-
console.log(`Static resources on "${i.route}" from directory ${i.directoryPath}`);
|
|
63
176
|
}
|
|
64
177
|
|
|
65
178
|
// Default middleware
|
|
@@ -69,24 +182,16 @@ export const startServer = async (config) => {
|
|
|
69
182
|
app.use(cookieParser());
|
|
70
183
|
app.use(compression());
|
|
71
184
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
console.log(`Access log in "${config.loggerFilename}"`);
|
|
75
|
-
app.use(handlerLogger(config.loggerFilename));
|
|
76
|
-
}
|
|
185
|
+
/** @type {Pool[]} */
|
|
186
|
+
const connectionPools = [];
|
|
77
187
|
|
|
78
188
|
// Oracle pl/sql express middleware
|
|
79
189
|
for (const i of config.routePlSql) {
|
|
80
190
|
// Allocate the Oracle database pool
|
|
81
191
|
const pool = await poolCreate(i.user, i.password, i.connectString);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
app.use(`${i.route}/:name?`, handlerWebPlSql(pool, i));
|
|
192
|
+
connectionPools.push(pool);
|
|
85
193
|
|
|
86
|
-
|
|
87
|
-
console.log(` Oracle user: ${i.user}`);
|
|
88
|
-
console.log(` Oracle server: ${i.connectString}`);
|
|
89
|
-
console.log(` Oracle document table: ${i.documentTable}`);
|
|
194
|
+
app.use([`${i.route}/:name`, i.route], handlerWebPlSql(pool, i));
|
|
90
195
|
}
|
|
91
196
|
|
|
92
197
|
// Update metrics every second
|
|
@@ -101,6 +206,24 @@ export const startServer = async (config) => {
|
|
|
101
206
|
}, 1000);
|
|
102
207
|
}
|
|
103
208
|
|
|
104
|
-
|
|
105
|
-
|
|
209
|
+
await createHttpServer(app, config.port, connectionPools);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Load configuration.
|
|
214
|
+
* @param {string} [filename] - The configuration filename.
|
|
215
|
+
* @returns {configType} - Promise.
|
|
216
|
+
*/
|
|
217
|
+
export const loadConfig = (filename) => {
|
|
218
|
+
debug('loadConfig', filename);
|
|
219
|
+
|
|
220
|
+
if (typeof filename !== 'string' || filename.length === 0) {
|
|
221
|
+
filename = 'config.json';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const data = getJsonFile(filename);
|
|
225
|
+
|
|
226
|
+
const config = z$configType.parse(data);
|
|
227
|
+
|
|
228
|
+
return config;
|
|
106
229
|
};
|
package/src/trace.js
CHANGED
|
@@ -10,7 +10,7 @@ import util from 'node:util';
|
|
|
10
10
|
* Return a string representation of the value.
|
|
11
11
|
*
|
|
12
12
|
* @param {unknown} value - Any value.
|
|
13
|
-
* @param {number | null} depth - Specifies the number of times to recurse while formatting object
|
|
13
|
+
* @param {number | null} depth - Specifies the number of times to recurse while formatting object.
|
|
14
14
|
* @returns {string} - The string representation.
|
|
15
15
|
*/
|
|
16
16
|
export const inspect = (value, depth = null) => util.inspect(value, {showHidden: false, depth, colors: false});
|
package/src/types.js
CHANGED
|
@@ -14,12 +14,10 @@ export const z$errorStyleType = z.enum(['basic', 'debug']);
|
|
|
14
14
|
* @property {string} route - The Static route path.
|
|
15
15
|
* @property {string} directoryPath - The Static directory.
|
|
16
16
|
*/
|
|
17
|
-
export const z$configStaticType = z
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
})
|
|
22
|
-
.strict();
|
|
17
|
+
export const z$configStaticType = z.strictObject({
|
|
18
|
+
route: z.string(),
|
|
19
|
+
directoryPath: z.string(),
|
|
20
|
+
});
|
|
23
21
|
|
|
24
22
|
/**
|
|
25
23
|
* @typedef {object} configPlSqlHandlerType
|
|
@@ -32,17 +30,15 @@ export const z$configStaticType = z
|
|
|
32
30
|
* @property {Record<string, string>} [cgi] - The additional CGI.
|
|
33
31
|
* @property {errorStyleType} errorStyle - The error style.
|
|
34
32
|
*/
|
|
35
|
-
export const z$configPlSqlHandlerType = z
|
|
36
|
-
.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
})
|
|
45
|
-
.strict();
|
|
33
|
+
export const z$configPlSqlHandlerType = z.strictObject({
|
|
34
|
+
defaultPage: z.string(),
|
|
35
|
+
pathAlias: z.string().optional(),
|
|
36
|
+
pathAliasProcedure: z.string().optional(),
|
|
37
|
+
documentTable: z.string(),
|
|
38
|
+
exclusionList: z.array(z.string()).optional(),
|
|
39
|
+
requestValidationFunction: z.string().optional(),
|
|
40
|
+
errorStyle: z$errorStyleType,
|
|
41
|
+
});
|
|
46
42
|
|
|
47
43
|
/**
|
|
48
44
|
* @typedef {object} configPlSqlConfigType
|
|
@@ -51,19 +47,20 @@ export const z$configPlSqlHandlerType = z
|
|
|
51
47
|
* @property {string} password - The Oracle password.
|
|
52
48
|
* @property {string} connectString - The Oracle connect string.
|
|
53
49
|
*/
|
|
54
|
-
export const z$configPlSqlConfigType = z
|
|
55
|
-
.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
})
|
|
61
|
-
.strict();
|
|
50
|
+
export const z$configPlSqlConfigType = z.strictObject({
|
|
51
|
+
route: z.string(),
|
|
52
|
+
user: z.string(),
|
|
53
|
+
password: z.string(),
|
|
54
|
+
connectString: z.string(),
|
|
55
|
+
});
|
|
62
56
|
|
|
63
57
|
/**
|
|
64
58
|
* @typedef {configPlSqlHandlerType & configPlSqlConfigType} configPlSqlType
|
|
65
59
|
*/
|
|
66
|
-
export const z$configPlSqlType = z
|
|
60
|
+
export const z$configPlSqlType = z.strictObject({
|
|
61
|
+
...z$configPlSqlHandlerType.shape,
|
|
62
|
+
...z$configPlSqlConfigType.shape,
|
|
63
|
+
});
|
|
67
64
|
|
|
68
65
|
/**
|
|
69
66
|
* @typedef {object} configType
|
|
@@ -73,15 +70,13 @@ export const z$configPlSqlType = z$configPlSqlHandlerType.merge(z$configPlSqlCon
|
|
|
73
70
|
* @property {string} loggerFilename - name of the request logger filename or '' if not required.
|
|
74
71
|
* @property {boolean} monitorConsole - Enable console status monitor.
|
|
75
72
|
*/
|
|
76
|
-
export const z$configType = z
|
|
77
|
-
.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
})
|
|
84
|
-
.strict();
|
|
73
|
+
export const z$configType = z.strictObject({
|
|
74
|
+
port: z.number(),
|
|
75
|
+
routeStatic: z.array(z$configStaticType),
|
|
76
|
+
routePlSql: z.array(z$configPlSqlType),
|
|
77
|
+
loggerFilename: z.string(),
|
|
78
|
+
monitorConsole: z.boolean(),
|
|
79
|
+
});
|
|
85
80
|
|
|
86
81
|
/**
|
|
87
82
|
* Environment variables as string key-value pairs
|
package/src/version.js
CHANGED
|
@@ -21,3 +21,18 @@ export const getPackageVersion = () => {
|
|
|
21
21
|
|
|
22
22
|
return typeof pkg.version === 'string' ? pkg.version : '';
|
|
23
23
|
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Retrieves the express version from package.json.
|
|
27
|
+
*
|
|
28
|
+
* @returns {string} The version number of the package.
|
|
29
|
+
*/
|
|
30
|
+
export const getExpressVersion = () => {
|
|
31
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
32
|
+
const __dirname = dirname(__filename);
|
|
33
|
+
const packageJsonPath = join(__dirname, '../node_modules/express/package.json');
|
|
34
|
+
|
|
35
|
+
const pkg = /** @type {PackageJSON} */ (getJsonFile(packageJsonPath));
|
|
36
|
+
|
|
37
|
+
return typeof pkg.version === 'string' ? pkg.version : '';
|
|
38
|
+
};
|
package/types/file.d.ts
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { startServer } from "./server.js";
|
|
2
1
|
export * from "./shutdown.js";
|
|
3
2
|
export * from "./oracle.js";
|
|
4
3
|
export * from "./file.js";
|
|
@@ -7,4 +6,5 @@ export * from "./version.js";
|
|
|
7
6
|
export { handlerWebPlSql } from "./handlerPlSql.js";
|
|
8
7
|
export { handlerLogger } from "./handlerLogger.js";
|
|
9
8
|
export { handlerUpload } from "./handlerUpload.js";
|
|
9
|
+
export { createHttpServer, createHttpsServer, startHttpServer, loadConfig } from "./server.js";
|
|
10
10
|
export { initMetrics, handlerMetrics } from "./handlerMetrics.js";
|
package/types/server.d.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function showConfig(config: configType): void;
|
|
2
|
+
export function createHttpServer(app: Express, port: number, connectionPools: Pool[]): Promise<http.Server>;
|
|
3
|
+
export function createHttpsServer(app: Express, sslKeyFilename: string, sslCertFilename: string, port: number, connectionPools: Pool[]): Promise<https.Server>;
|
|
4
|
+
export function startHttpServer(config: configType): Promise<void>;
|
|
5
|
+
export function loadConfig(filename?: string): configType;
|
|
6
|
+
export type Express = import("express").Express;
|
|
2
7
|
export type Request = import("express").Request;
|
|
3
8
|
export type Response = import("express").Response;
|
|
4
9
|
export type NextFunction = import("express").NextFunction;
|
|
5
10
|
export type Pool = import("oracledb").Pool;
|
|
6
11
|
export type environmentType = import("./types.js").environmentType;
|
|
7
12
|
export type configType = import("./types.js").configType;
|
|
13
|
+
import http from 'node:http';
|
|
14
|
+
import https from 'node:https';
|
package/types/stream.d.ts
CHANGED
package/types/trace.d.ts
CHANGED
package/types/types.d.ts
CHANGED
|
@@ -4,13 +4,19 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* @typedef {'basic' | 'debug'} errorStyleType
|
|
6
6
|
*/
|
|
7
|
-
export const z$errorStyleType:
|
|
7
|
+
export const z$errorStyleType: z.ZodEnum<{
|
|
8
|
+
basic: "basic";
|
|
9
|
+
debug: "debug";
|
|
10
|
+
}>;
|
|
8
11
|
/**
|
|
9
12
|
* @typedef {object} configStaticType
|
|
10
13
|
* @property {string} route - The Static route path.
|
|
11
14
|
* @property {string} directoryPath - The Static directory.
|
|
12
15
|
*/
|
|
13
|
-
export const z$configStaticType:
|
|
16
|
+
export const z$configStaticType: z.ZodObject<{
|
|
17
|
+
route: z.ZodString;
|
|
18
|
+
directoryPath: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
14
20
|
/**
|
|
15
21
|
* @typedef {object} configPlSqlHandlerType
|
|
16
22
|
* @property {string} defaultPage - The default page.
|
|
@@ -22,7 +28,18 @@ export const z$configStaticType: any;
|
|
|
22
28
|
* @property {Record<string, string>} [cgi] - The additional CGI.
|
|
23
29
|
* @property {errorStyleType} errorStyle - The error style.
|
|
24
30
|
*/
|
|
25
|
-
export const z$configPlSqlHandlerType:
|
|
31
|
+
export const z$configPlSqlHandlerType: z.ZodObject<{
|
|
32
|
+
defaultPage: z.ZodString;
|
|
33
|
+
pathAlias: z.ZodOptional<z.ZodString>;
|
|
34
|
+
pathAliasProcedure: z.ZodOptional<z.ZodString>;
|
|
35
|
+
documentTable: z.ZodString;
|
|
36
|
+
exclusionList: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
37
|
+
requestValidationFunction: z.ZodOptional<z.ZodString>;
|
|
38
|
+
errorStyle: z.ZodEnum<{
|
|
39
|
+
basic: "basic";
|
|
40
|
+
debug: "debug";
|
|
41
|
+
}>;
|
|
42
|
+
}, z.core.$strict>;
|
|
26
43
|
/**
|
|
27
44
|
* @typedef {object} configPlSqlConfigType
|
|
28
45
|
* @property {string} route - The PL/SQL route path.
|
|
@@ -30,11 +47,31 @@ export const z$configPlSqlHandlerType: any;
|
|
|
30
47
|
* @property {string} password - The Oracle password.
|
|
31
48
|
* @property {string} connectString - The Oracle connect string.
|
|
32
49
|
*/
|
|
33
|
-
export const z$configPlSqlConfigType:
|
|
50
|
+
export const z$configPlSqlConfigType: z.ZodObject<{
|
|
51
|
+
route: z.ZodString;
|
|
52
|
+
user: z.ZodString;
|
|
53
|
+
password: z.ZodString;
|
|
54
|
+
connectString: z.ZodString;
|
|
55
|
+
}, z.core.$strict>;
|
|
34
56
|
/**
|
|
35
57
|
* @typedef {configPlSqlHandlerType & configPlSqlConfigType} configPlSqlType
|
|
36
58
|
*/
|
|
37
|
-
export const z$configPlSqlType:
|
|
59
|
+
export const z$configPlSqlType: z.ZodObject<{
|
|
60
|
+
route: z.ZodString;
|
|
61
|
+
user: z.ZodString;
|
|
62
|
+
password: z.ZodString;
|
|
63
|
+
connectString: z.ZodString;
|
|
64
|
+
defaultPage: z.ZodString;
|
|
65
|
+
pathAlias: z.ZodOptional<z.ZodString>;
|
|
66
|
+
pathAliasProcedure: z.ZodOptional<z.ZodString>;
|
|
67
|
+
documentTable: z.ZodString;
|
|
68
|
+
exclusionList: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
69
|
+
requestValidationFunction: z.ZodOptional<z.ZodString>;
|
|
70
|
+
errorStyle: z.ZodEnum<{
|
|
71
|
+
basic: "basic";
|
|
72
|
+
debug: "debug";
|
|
73
|
+
}>;
|
|
74
|
+
}, z.core.$strict>;
|
|
38
75
|
/**
|
|
39
76
|
* @typedef {object} configType
|
|
40
77
|
* @property {number} port - The server port number.
|
|
@@ -43,7 +80,31 @@ export const z$configPlSqlType: any;
|
|
|
43
80
|
* @property {string} loggerFilename - name of the request logger filename or '' if not required.
|
|
44
81
|
* @property {boolean} monitorConsole - Enable console status monitor.
|
|
45
82
|
*/
|
|
46
|
-
export const z$configType:
|
|
83
|
+
export const z$configType: z.ZodObject<{
|
|
84
|
+
port: z.ZodNumber;
|
|
85
|
+
routeStatic: z.ZodArray<z.ZodObject<{
|
|
86
|
+
route: z.ZodString;
|
|
87
|
+
directoryPath: z.ZodString;
|
|
88
|
+
}, z.core.$strict>>;
|
|
89
|
+
routePlSql: z.ZodArray<z.ZodObject<{
|
|
90
|
+
route: z.ZodString;
|
|
91
|
+
user: z.ZodString;
|
|
92
|
+
password: z.ZodString;
|
|
93
|
+
connectString: z.ZodString;
|
|
94
|
+
defaultPage: z.ZodString;
|
|
95
|
+
pathAlias: z.ZodOptional<z.ZodString>;
|
|
96
|
+
pathAliasProcedure: z.ZodOptional<z.ZodString>;
|
|
97
|
+
documentTable: z.ZodString;
|
|
98
|
+
exclusionList: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
99
|
+
requestValidationFunction: z.ZodOptional<z.ZodString>;
|
|
100
|
+
errorStyle: z.ZodEnum<{
|
|
101
|
+
basic: "basic";
|
|
102
|
+
debug: "debug";
|
|
103
|
+
}>;
|
|
104
|
+
}, z.core.$strict>>;
|
|
105
|
+
loggerFilename: z.ZodString;
|
|
106
|
+
monitorConsole: z.ZodBoolean;
|
|
107
|
+
}, z.core.$strict>;
|
|
47
108
|
export type BindParameter = import("oracledb").BindParameter;
|
|
48
109
|
export type errorStyleType = "basic" | "debug";
|
|
49
110
|
export type configStaticType = {
|
|
@@ -249,3 +310,4 @@ export type metricsType = {
|
|
|
249
310
|
*/
|
|
250
311
|
requestsInLastInterval: number;
|
|
251
312
|
};
|
|
313
|
+
import z from 'zod';
|