web_plsql 0.6.0 → 0.8.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 CHANGED
@@ -24,11 +24,15 @@ Please visit the [node-oracledb](https://node-oracledb.readthedocs.io/en/latest/
24
24
  * Create a new npm project (`npm i`)
25
25
  * Install package (`npm i --omit=dev web_plsql`)
26
26
 
27
- # Example
27
+ # Example (native)
28
28
  * 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 the sample server using `node examples/server_sample.js` after having set the ORACLE_SERVER environment variable to the database where you just installed the sample schema.
29
+ * Start server using `node examples/server_sample.js` after having set the WEB_PLSQL_ORACLE_SERVER environment variable to the database where you just installed the sample schema.
30
30
  * Invoke a browser and open the page `http://localhost/sample`.
31
31
 
32
+ # Example (container)
33
+ * Build the image using `npm run image-build`
34
+ * Start the container using `./run_container.sh` after eventually modifying the `run_container.sh` script.
35
+
32
36
  # Running
33
37
  There are 2 main options on how to use the mod_plsql Express middleware:
34
38
 
@@ -1,8 +1,6 @@
1
- #!/usr/bin/env node
1
+ import {startHttpServer} from '../src/index.js';
2
2
 
3
- import {startServer} from '../src/index.js';
4
-
5
- void startServer({
3
+ void startHttpServer({
6
4
  port: 80,
7
5
  routeStatic: [
8
6
  {
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import {startServer} from '../src/index.js';
3
+ import {startHttpServer} from '../src/index.js';
4
4
 
5
- void startServer({
6
- port: 80,
5
+ void startHttpServer({
6
+ port: 8888,
7
7
  routeStatic: [
8
8
  {
9
9
  route: '/static',
@@ -13,9 +13,9 @@ void startServer({
13
13
  routePlSql: [
14
14
  {
15
15
  route: '/sample',
16
- user: 'sample', // PlsqlDatabaseUserName
17
- password: 'sample', // PlsqlDatabasePassword
18
- connectString: process.env.ORACLE_SERVER ?? '', // PlsqlDatabaseConnectString
16
+ user: process.env.WEB_PLSQL_ORACLE_USER ?? 'sample', // PlsqlDatabaseUserName
17
+ password: process.env.WEB_PLSQL_ORACLE_PASSWORD ?? 'sample', // PlsqlDatabasePassword
18
+ connectString: process.env.WEB_PLSQL_ORACLE_SERVER ?? 'localhost:1521/orcl', // PlsqlDatabaseConnectString
19
19
  defaultPage: 'sample_pkg.page_index', // PlsqlDefaultPage
20
20
  documentTable: 'doctable', // PlsqlDocumentTablename
21
21
  exclusionList: ['sample_pkg.page_exclusion_list'], // PlsqlExclusionList
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web_plsql",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "author": "Dieter Oberkofler <dieter.oberkofler@gmail.com>",
5
5
  "license": "MIT",
6
6
  "description": "The Express Middleware for Oracle PL/SQL",
@@ -48,24 +48,26 @@
48
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
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"
52
54
  },
53
55
  "dependencies": {
54
56
  "basic-auth": "2.0.1",
55
- "body-parser": "1.20.3",
56
- "compression": "1.7.5",
57
+ "body-parser": "2.2.0",
58
+ "compression": "1.8.0",
57
59
  "connect-multiparty": "2.2.0",
58
60
  "cookie-parser": "1.4.7",
59
61
  "debug": "4.4.0",
60
62
  "escape-html": "1.0.3",
61
- "express": "4.21.2",
63
+ "express": "5.1.0",
62
64
  "fs-extra": "11.3.0",
63
- "http-parser-js": "0.5.9",
65
+ "http-parser-js": "0.5.10",
64
66
  "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"
67
+ "multer": "1.4.5-lts.2",
68
+ "oracledb": "6.8.0",
69
+ "rotating-file-stream": "3.2.6",
70
+ "zod": "3.24.2"
69
71
  },
70
72
  "devDependencies": {
71
73
  "@types/basic-auth": "1.1.8",
@@ -76,17 +78,17 @@
76
78
  "@types/escape-html": "1.0.4",
77
79
  "@types/fs-extra": "11.0.4",
78
80
  "@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",
81
+ "@types/multer": "1.4.12",
82
+ "@types/node": "22.14.1",
83
+ "@types/oracledb": "6.6.0",
84
+ "@types/supertest": "6.0.3",
85
+ "eslint": "9.24.0",
86
+ "eslint-plugin-jsdoc": "50.6.9",
87
+ "prettier": "3.5.3",
86
88
  "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"
89
+ "shx": "0.4.0",
90
+ "supertest": "7.1.0",
91
+ "typescript": "5.8.3",
92
+ "typescript-eslint": "8.30.1"
91
93
  }
92
94
  }
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
- const stats = await fs.stat(filePath);
75
-
76
- return stats.isFile();
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
@@ -1,5 +1,5 @@
1
1
  // server
2
- export {startServer} from './server.js';
2
+ export {createHttpServer, createHttpsServer, startHttpServer, loadConfig} from './server.js';
3
3
  export * from './shutdown.js';
4
4
 
5
5
  // handler
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,29 +29,83 @@ import {getPackageVersion} from './version.js';
25
29
  */
26
30
 
27
31
  /**
28
- * Start generic server.
29
- * @param {configType} config - The config.
30
- * @returns {Promise<void>} - Promise.
32
+ * Create HTTP server.
33
+ * @param {Express} app - express application
34
+ * @param {number} port - port number
35
+ * @param {Pool[]} connectionPools - database connection
36
+ * @returns {Promise<http.Server>} - server
31
37
  */
32
- export const startServer = async (config) => {
33
- debug('startServer', config);
38
+ export const createHttpServer = (app, port, connectionPools) => {
39
+ return new Promise((resolve) => {
40
+ // Create server
41
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
42
+ const server = http.createServer({}, app);
43
+
44
+ // Install shutdown handler
45
+ installShutdown(async () => {
46
+ // Close database pool.
47
+ await poolsClose(connectionPools);
48
+
49
+ // Close server
50
+ return new Promise((resolve) => server.close(() => resolve()));
51
+ });
52
+
53
+ // Listen on HTTP ports
54
+ server.listen(port, () => {
55
+ resolve(server);
56
+ });
57
+ });
58
+ };
34
59
 
35
- config = z$configType.parse(config);
60
+ /**
61
+ * Create HTTPS server.
62
+ * @param {Express} app - express application
63
+ * @param {string} sslKeyFilename - ssl
64
+ * @param {string} sslCertFilename - ssl
65
+ * @param {number} port - port number
66
+ * @param {Pool[]} connectionPools - database connection
67
+ * @returns {Promise<https.Server>} - server
68
+ */
69
+ export const createHttpsServer = (app, sslKeyFilename, sslCertFilename, port, connectionPools) => {
70
+ return new Promise((resolve) => {
71
+ // Load certificates
72
+ const key = readFileSyncUtf8(sslKeyFilename);
73
+ const cert = readFileSyncUtf8(sslCertFilename);
74
+
75
+ // Create server
76
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
77
+ const server = https.createServer({key, cert}, app);
78
+
79
+ // Install shutdown handler
80
+ installShutdown(async () => {
81
+ // Close database pool.
82
+ await poolsClose(connectionPools);
83
+
84
+ // Close server
85
+ return new Promise((resolve) => server.close(() => resolve()));
86
+ });
87
+
88
+ // Listen on HTTP ports
89
+ server.listen(port, () => {
90
+ resolve(server);
91
+ });
92
+ });
93
+ };
36
94
 
37
- console.log(`WEB_PL/SQL ${getPackageVersion()}`);
95
+ /**
96
+ * Start HTTP server.
97
+ * @param {configType} config - The config.
98
+ * @returns {Promise<void>} - Promise.
99
+ */
100
+ export const startHttpServer = async (config) => {
101
+ debug('startHttpServer', config);
38
102
 
39
- /** @type {Pool[]} */
40
- const pools = [];
103
+ const expressVersion = getExpressVersion();
104
+ const packageVersion = getPackageVersion();
41
105
 
42
- // Install shutdown handler
43
- installShutdown(async () => {
44
- // Close database pools.
45
- await poolsClose(pools);
46
- pools.length = 0;
106
+ config = z$configType.parse(config);
47
107
 
48
- // Close server
49
- return new Promise((resolve) => server.close(() => resolve()));
50
- });
108
+ console.log(`WEB_PL/SQL ${packageVersion} using express ${expressVersion}`);
51
109
 
52
110
  // Create express app
53
111
  const app = express();
@@ -75,13 +133,16 @@ export const startServer = async (config) => {
75
133
  app.use(handlerLogger(config.loggerFilename));
76
134
  }
77
135
 
136
+ /** @type {Pool[]} */
137
+ const connectionPools = [];
138
+
78
139
  // Oracle pl/sql express middleware
79
140
  for (const i of config.routePlSql) {
80
141
  // Allocate the Oracle database pool
81
142
  const pool = await poolCreate(i.user, i.password, i.connectString);
82
- pools.push(pool);
143
+ connectionPools.push(pool);
83
144
 
84
- app.use(`${i.route}/:name?`, handlerWebPlSql(pool, i));
145
+ app.use([`${i.route}/:name`, i.route], handlerWebPlSql(pool, i));
85
146
 
86
147
  console.log(`Application route "http://localhost:${config.port}${i.route}"`);
87
148
  console.log(` Oracle user: ${i.user}`);
@@ -101,6 +162,24 @@ export const startServer = async (config) => {
101
162
  }, 1000);
102
163
  }
103
164
 
104
- // listen on port
105
- const server = app.listen(config.port);
165
+ await createHttpServer(app, config.port, connectionPools);
166
+ };
167
+
168
+ /**
169
+ * Load configuration.
170
+ * @param {string} [filename] - The configuration filename.
171
+ * @returns {configType} - Promise.
172
+ */
173
+ export const loadConfig = (filename) => {
174
+ debug('loadConfig', filename);
175
+
176
+ if (typeof filename !== 'string' || filename.length === 0) {
177
+ filename = 'config.json';
178
+ }
179
+
180
+ const data = getJsonFile(filename);
181
+
182
+ const config = z$configType.parse(data);
183
+
184
+ return config;
106
185
  };
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
@@ -1,3 +1,4 @@
1
+ export function readFileSyncUtf8(filePath: string): string;
1
2
  export function readFile(filePath: string): Promise<Buffer>;
2
3
  export function removeFile(filePath: string): Promise<void>;
3
4
  export function getJsonFile(filePath: string): unknown;
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,4 +1,8 @@
1
- export function startServer(config: configType): Promise<void>;
1
+ export function createHttpServer(app: Express, port: number, connectionPools: Pool[]): Promise<http.Server>;
2
+ export function createHttpsServer(app: Express, sslKeyFilename: string, sslCertFilename: string, port: number, connectionPools: Pool[]): Promise<https.Server>;
3
+ export function startHttpServer(config: configType): Promise<void>;
4
+ export function loadConfig(filename?: string): configType;
5
+ export type Express = import("express").Express;
2
6
  export type Request = import("express").Request;
3
7
  export type Response = import("express").Response;
4
8
  export type NextFunction = import("express").NextFunction;
@@ -1,4 +1,5 @@
1
1
  export function getPackageVersion(): string;
2
+ export function getExpressVersion(): string;
2
3
  export type PackageJSON = {
3
4
  /**
4
5
  * - The package version.