web_plsql
Version:
The Express Middleware for Oracle PL/SQL
646 lines (645 loc) • 20.9 kB
text/typescript
import z$1, { z } from "zod";
import oracledb, { BindParameter, BindParameters, BindParameters as BindParameters$1, Connection, Connection as Connection$1, DbType, ExecuteOptions, Lob, Pool, Pool as Pool$1, Result, Result as Result$1 } from "oracledb";
import http from "node:http";
import https from "node:https";
import { Express, RequestHandler, Router } from "express";
import { Readable } from "node:stream";
//#region src/backend/util/cache.d.ts
type cacheEntryType<T> = {
hitCount: number;
value: T;
};
/**
* Generic Cache class with LFU (Least Frequently Used) eviction policy.
*/
declare class Cache<T> {
cache: Map<string, cacheEntryType<T>>;
maxSize: number;
hits: number;
misses: number;
/**
* @param maxSize - Maximum number of entries in the cache.
*/
constructor(maxSize?: number);
/**
* Get an entry from the cache.
* @param key - The key.
* @returns The value or undefined if not found.
*/
get(key: string): T | undefined;
/**
* Set an entry in the cache.
* @param key - The key.
* @param value - The value.
*/
set(key: string, value: T): void;
/**
* Delete an entry from the cache.
* @param key - The key.
*/
delete(key: string): void;
/**
* Clear the cache.
*/
clear(): void;
/**
* Prune the cache by removing the least frequently used entries.
* Removes 10% of the cache size.
*/
prune(): void;
/**
* Get the size of the cache.
* @returns The size.
*/
get size(): number;
/**
* Get all keys in the cache.
* @returns The keys.
*/
keys(): string[];
/**
* Get cache statistics.
* @returns The statistics.
*/
getStats(): {
size: number;
maxSize: number;
hits: number;
misses: number;
};
}
//#endregion
//#region src/backend/types.d.ts
/**
* Custom callback signature for manual transaction handling
*/
type transactionCallbackType = (connection: Connection, procedure: string) => void | Promise<void>;
/**
* Defines how transactions are handled after procedure execution
* 'commit': automatically commit
* 'rollback': automatically rollback
* callback: custom function for manual handling
*/
/**
* Authentication callback signature.
* Returns the identity string on success, or null on failure.
* @public
*/
type AuthCallback = (connectionPool: Pool, credentials: {
username: string;
password?: string | undefined;
}) => Promise<string | null>;
/**
* PL/SQL handler behavior configuration
*/
declare const z$configPlSqlHandlerType: z$1.ZodObject<{
/** Default procedure to execute if none specified */defaultPage: z$1.ZodString; /** Virtual path alias for procedures */
pathAlias: z$1.ZodOptional<z$1.ZodString>; /** Procedure name associated with the path alias */
pathAliasProcedure: z$1.ZodOptional<z$1.ZodString>; /** Database table used for file uploads/downloads */
documentTable: z$1.ZodString; /** List of pattern/procedure names excluded from execution */
exclusionList: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>; /** PL/SQL function called to validate requests */
requestValidationFunction: z$1.ZodOptional<z$1.ZodString>; /** Post-execution transaction behavior */
transactionMode: z$1.ZodOptional<z$1.ZodUnion<readonly [z$1.ZodCustom<transactionCallbackType, transactionCallbackType>, z$1.ZodLiteral<"commit">, z$1.ZodLiteral<"rollback">, z$1.ZodUndefined, z$1.ZodNull]>>; /** Error reporting style */
errorStyle: z$1.ZodEnum<{
basic: "basic";
debug: "debug";
}>; /** Static CGI environment variables to be passed to the session */
cgi: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodString>>; /** Authentication settings */
auth: z$1.ZodOptional<z$1.ZodObject<{
/** Authentication type */type: z$1.ZodLiteral<"basic">; /** Callback function to validate credentials */
callback: z$1.ZodCustom<AuthCallback, AuthCallback>; /** Authentication realm */
realm: z$1.ZodOptional<z$1.ZodString>;
}, z$1.core.$strict>>;
}, z$1.core.$strict>;
type configPlSqlHandlerType = z$1.infer<typeof z$configPlSqlHandlerType>;
/**
* Database connection configuration for a PL/SQL route
*/
declare const z$configPlSqlConfigType: z$1.ZodObject<{
/** URL route prefix for this database connection */route: z$1.ZodString; /** Database username */
user: z$1.ZodString; /** Database password */
password: z$1.ZodString; /** Oracle connection string (TNS or EZConnect) */
connectString: z$1.ZodString;
}, z$1.core.$strict>;
type configPlSqlConfigType = z$1.infer<typeof z$configPlSqlConfigType>;
/**
* Complete PL/SQL route configuration combining handler and connection settings
*/
type configPlSqlType = configPlSqlHandlerType & configPlSqlConfigType;
/**
* Root application configuration
*/
declare const z$configType: z$1.ZodObject<{
/** Server listening port */port: z$1.ZodNumber; /** Array of static file routes */
routeStatic: z$1.ZodArray<z$1.ZodObject<{
route: z$1.ZodString;
directoryPath: z$1.ZodString;
spaFallback: z$1.ZodOptional<z$1.ZodBoolean>;
}, z$1.core.$strict>>; /** Array of PL/SQL routes */
routePlSql: z$1.ZodArray<z$1.ZodObject<{
/** URL route prefix for this database connection */route: z$1.ZodString; /** Database username */
user: z$1.ZodString; /** Database password */
password: z$1.ZodString; /** Oracle connection string (TNS or EZConnect) */
connectString: z$1.ZodString; /** Default procedure to execute if none specified */
defaultPage: z$1.ZodString; /** Virtual path alias for procedures */
pathAlias: z$1.ZodOptional<z$1.ZodString>; /** Procedure name associated with the path alias */
pathAliasProcedure: z$1.ZodOptional<z$1.ZodString>; /** Database table used for file uploads/downloads */
documentTable: z$1.ZodString; /** List of pattern/procedure names excluded from execution */
exclusionList: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>; /** PL/SQL function called to validate requests */
requestValidationFunction: z$1.ZodOptional<z$1.ZodString>; /** Post-execution transaction behavior */
transactionMode: z$1.ZodOptional<z$1.ZodUnion<readonly [z$1.ZodCustom<transactionCallbackType, transactionCallbackType>, z$1.ZodLiteral<"commit">, z$1.ZodLiteral<"rollback">, z$1.ZodUndefined, z$1.ZodNull]>>; /** Error reporting style */
errorStyle: z$1.ZodEnum<{
basic: "basic";
debug: "debug";
}>; /** Static CGI environment variables to be passed to the session */
cgi: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodString>>; /** Authentication settings */
auth: z$1.ZodOptional<z$1.ZodObject<{
/** Authentication type */type: z$1.ZodLiteral<"basic">; /** Callback function to validate credentials */
callback: z$1.ZodCustom<AuthCallback, AuthCallback>; /** Authentication realm */
realm: z$1.ZodOptional<z$1.ZodString>;
}, z$1.core.$strict>>;
}, z$1.core.$strict>>; /** Maximum allowed size for file uploads (bytes) */
uploadFileSizeLimit: z$1.ZodOptional<z$1.ZodNumber>; /** Path to the log file */
loggerFilename: z$1.ZodString; /** URL route prefix for the admin console */
adminRoute: z$1.ZodOptional<z$1.ZodString>; /** Username for admin console authentication */
adminUser: z$1.ZodOptional<z$1.ZodString>; /** Password for admin console authentication */
adminPassword: z$1.ZodOptional<z$1.ZodString>; /** Developer mode (skips frontend build check, enables CORS) */
devMode: z$1.ZodOptional<z$1.ZodBoolean>;
}, z$1.core.$strict>;
type configType = z$1.infer<typeof z$configType>;
/**
* Mapping of PL/SQL procedure argument names to their database types
*/
type argsType = Record<string, string>;
//#endregion
//#region src/backend/util/oracledb-mock.d.ts
type ExecuteCallback = (sql: string, binds?: BindParameters) => Promise<Result<unknown>> | Result<unknown>;
/**
* Test utility: Set the callback for execute calls.
* @param cb - The callback
*/
declare const setExecuteCallback: (cb: ExecuteCallback | null) => void;
declare namespace oracledb_provider_d_exports {
export { BIND_IN, BIND_INOUT, BIND_OUT, BLOB, BUFFER, BindParameter, BindParameters$1 as BindParameters, CLOB, CURSOR, Connection$1 as Connection, DATE, DB_TYPE_CLOB, DB_TYPE_DATE, DB_TYPE_NUMBER, DB_TYPE_VARCHAR, DbType, ExecuteCallback, ExecuteOptions, Lob, NUMBER, Pool$1 as Pool, Result$1 as Result, STRING, createPool, setExecuteCallback };
}
/**
* Create a database pool.
* @param config - The pool attributes.
* @returns The pool.
*/
declare function createPool(config: oracledb.PoolAttributes): Promise<oracledb.Pool>;
declare const BIND_IN: number;
declare const BIND_OUT: number;
declare const BIND_INOUT: number;
declare const STRING: oracledb.DbType & {
num: 2001;
name: "DB_TYPE_VARCHAR";
columnTypeName: "VARCHAR2";
oraTypeNum: 1;
bufferSizeFactor: 4;
csfrm: oracledb.CSFRM_IMPLICIT;
};
declare const NUMBER: oracledb.DbType & {
num: 2010;
name: "DB_TYPE_NUMBER";
columnTypeName: "NUMBER";
oraTypeNum: 2;
bufferSizeFactor: 22;
};
declare const DATE: oracledb.DbType & {
num: 2012;
name: "DB_TYPE_TIMESTAMP";
columnTypeName: "TIMESTAMP";
oraTypeNum: 180;
bufferSizeFactor: 11;
};
declare const CURSOR: oracledb.DbType & {
num: 2021;
name: "DB_TYPE_CURSOR";
columnTypeName: "CURSOR";
oraTypeNum: 102;
bufferSizeFactor: 4;
};
declare const BUFFER: oracledb.DbType & {
num: 2006;
name: "DB_TYPE_RAW";
columnTypeName: "RAW";
oraTypeNum: 23;
bufferSizeFactor: 1;
};
declare const CLOB: oracledb.DbType & {
num: 2017;
name: "DB_TYPE_CLOB";
columnTypeName: "CLOB";
oraTypeNum: 112;
bufferSizeFactor: 112;
csfrm: oracledb.CSFRM_IMPLICIT;
};
declare const BLOB: oracledb.DbType & {
num: 2019;
name: "DB_TYPE_BLOB";
columnTypeName: "BLOB";
oraTypeNum: 113;
bufferSizeFactor: 112;
};
declare const DB_TYPE_VARCHAR: oracledb.DbType & {
num: 2001;
name: "DB_TYPE_VARCHAR";
columnTypeName: "VARCHAR2";
oraTypeNum: 1;
bufferSizeFactor: 4;
csfrm: oracledb.CSFRM_IMPLICIT;
};
declare const DB_TYPE_CLOB: oracledb.DbType & {
num: 2017;
name: "DB_TYPE_CLOB";
columnTypeName: "CLOB";
oraTypeNum: 112;
bufferSizeFactor: 112;
csfrm: oracledb.CSFRM_IMPLICIT;
};
declare const DB_TYPE_NUMBER: oracledb.DbType & {
num: 2010;
name: "DB_TYPE_NUMBER";
columnTypeName: "NUMBER";
oraTypeNum: 2;
bufferSizeFactor: 22;
};
declare const DB_TYPE_DATE: oracledb.DbType & {
num: 2011;
name: "DB_TYPE_DATE";
columnTypeName: "DATE";
oraTypeNum: 12;
bufferSizeFactor: 7;
};
//#endregion
//#region src/backend/version.d.ts
declare global {
var __VERSION__: string;
}
/**
* Returns the current library version
* @returns {string} - Version.
*/
declare const getVersion: () => string;
//#endregion
//#region src/backend/server/config.d.ts
/**
* Show configuration.
* @param config - The config.
*/
declare const showConfig: (config: configType) => void;
//#endregion
//#region src/backend/server/server.d.ts
type webServer = {
config: configType;
connectionPools: Pool[];
app: Express;
server: http.Server | https.Server;
adminContext: AdminContext;
shutdown: () => Promise<void>;
};
type sslConfig = {
keyFilename: string;
certFilename: string;
};
/**
* Create HTTPS server.
* @param app - express application
* @param ssl - ssl configuration.
* @returns server
*/
declare const createServer: (app: Express, ssl?: sslConfig) => http.Server | https.Server;
/**
* Start server.
* @param config - The config.
* @param ssl - ssl configuration.
* @returns Promise resolving to the web server object.
*/
declare const startServer: (config: configType, ssl?: sslConfig) => Promise<webServer>;
/**
* Load configuration.
* @param filename - The configuration filename.
* @returns Promise.
*/
declare const loadConfig: (filename?: string) => configType;
/**
* Start server from config file.
* @param filename - The configuration filename.
* @param ssl - ssl configuration.
* @returns Promise resolving to the web server object.
*/
declare const startServerConfig: (filename?: string, ssl?: sslConfig) => Promise<webServer>;
//#endregion
//#region src/backend/util/shutdown.d.ts
/**
* Install a shutdown handler.
* @param handler - Shutdown handler
*/
declare const installShutdown: (handler: () => Promise<void>) => void;
/**
* Force a shutdown.
*/
declare const forceShutdown: () => void;
//#endregion
//#region src/backend/util/statsManager.d.ts
type StatsConfig = {
intervalMs: number;
maxHistoryPoints: number;
sampleSystem: boolean;
samplePools: boolean;
percentilePrecision: number;
};
type CacheStats = {
size: number;
hits: number;
misses: number;
};
type PoolCacheSnapshot = {
procedureName: CacheStats;
argument: CacheStats;
};
type PoolSnapshot = {
name: string;
connectionsInUse: number;
connectionsOpen: number;
cache?: PoolCacheSnapshot;
};
type Bucket = {
timestamp: number;
requests: number;
errors: number;
durationMin: number;
durationMax: number;
durationAvg: number;
durationP95: number;
durationP99: number;
system: {
cpu: number;
heapUsed: number;
heapTotal: number;
rss: number;
external: number;
};
pools: PoolSnapshot[];
};
type CurrentBucket = {
count: number;
errors: number;
durationSum: number;
durationMin: number;
durationMax: number;
durations: number[];
};
type MemoryLifetime = {
heapUsedMax: number;
heapTotalMax: number;
rssMax: number;
externalMax: number;
};
type LifetimeStats = {
totalRequests: number;
totalErrors: number;
minDuration: number;
maxDuration: number;
totalDuration: number;
maxRequestsPerSecond: number;
memory: MemoryLifetime;
cpu: {
max: number;
userMax: number;
systemMax: number;
};
};
type StatsSummary = {
startTime: Date;
totalRequests: number;
totalErrors: number;
avgResponseTime: number;
minResponseTime: number;
maxResponseTime: number;
maxRequestsPerSecond: number;
maxMemory: MemoryLifetime;
cpu: {
max: number;
userMax: number;
systemMax: number;
};
};
/**
* Manager for statistical data collection and temporal bucketing.
*/
declare class StatsManager {
config: StatsConfig;
startTime: Date;
history: Bucket[];
lifetime: LifetimeStats;
_currentBucket: CurrentBucket;
_lastCpuTimes: {
user: number;
nice: number;
sys: number;
idle: number;
irq: number;
total: number;
};
_timer: NodeJS.Timeout | undefined;
/**
* @param config - Configuration.
*/
constructor(config?: Partial<StatsConfig>);
/**
* Reset the current bucket accumulator.
*/
private _resetBucket;
/**
* Record a request event.
* @param duration - Duration in milliseconds.
* @param isError - Whether the request was an error.
*/
recordRequest(duration: number, isError?: boolean): void;
/**
* Get system CPU times.
* @returns System CPU times.
*/
private _getSystemCpuTimes;
/**
* Calculate CPU usage percentage since last call.
* @returns CPU usage percentage (0-100).
*/
private _calculateCpuUsage;
/**
* Rotate the current bucket into history and start a new one.
* @param poolSnapshots - Optional pool snapshots to include.
*/
rotateBucket(poolSnapshots?: PoolSnapshot[]): void;
/**
* Stop the background timer.
*/
stop(): void;
/**
* Get lifetime summary.
* @returns Summary.
*/
getSummary(): StatsSummary;
/**
* Get history buffer.
* @returns The history buffer.
*/
getHistory(): Bucket[];
}
//#endregion
//#region src/backend/server/adminContext.d.ts
type PoolCacheEntry = {
poolName: string;
procedureNameCache: Cache<string>;
argumentCache: Cache<argsType>;
};
/**
* Admin Context Class
*/
declare class AdminContext {
readonly startTime: Date;
readonly config: configType;
readonly pools: Pool[];
readonly caches: PoolCacheEntry[];
readonly statsManager: StatsManager;
private _paused;
constructor(config: configType);
/**
* Register a PL/SQL handler with the admin context.
* @param route - The route for the handler.
* @param pool - The connection pool.
* @param procedureNameCache - The procedure name cache.
* @param argumentCache - The argument cache.
*/
registerHandler(route: string, pool: Pool, procedureNameCache: Cache<string>, argumentCache: Cache<argsType>): void;
get paused(): boolean;
setPaused(value: boolean): void;
}
//#endregion
//#region src/backend/handler/plsql/handlerPlSql.d.ts
type WebPlSqlRequestHandler = RequestHandler & {
procedureNameCache: Cache<string>;
argumentCache: Cache<argsType>;
};
/**
* Express middleware.
*
* @param connectionPool - The connection pool.
* @param config - The configuration options.
* @param adminContext - Optional admin context for self-registration and stats tracking.
* @returns The handler.
*/
declare const handlerWebPlSql: (connectionPool: Pool, config: configPlSqlType, adminContext?: AdminContext) => WebPlSqlRequestHandler & {
procedureNameCache: Cache<string>;
argumentCache: Cache<argsType>;
};
//#endregion
//#region src/backend/handler/handlerLogger.d.ts
/**
* Create the upload middleware.
* @param filename - Output filename.
* @returns Request handler.
*/
declare const handlerLogger: (filename: string) => RequestHandler;
//#endregion
//#region src/backend/handler/handlerUpload.d.ts
/**
* Create the upload middleware.
* @param uploadFileSizeLimit - Maximum size of each uploaded file in bytes or no limit if omitted.
* @returns Request handler.
*/
declare const handlerUpload: (uploadFileSizeLimit?: number) => RequestHandler;
//#endregion
//#region src/backend/handler/handlerAdmin.d.ts
/**
* Create admin API router
* @param adminContext - The admin context
* @returns Express router
*/
declare const createAdminRouter: (adminContext: AdminContext) => Router;
//#endregion
//#region src/backend/handler/handlerAdminConsole.d.ts
type AdminConsoleConfig = {
/** Base route for the admin console (defaults to '/admin') */adminRoute?: string | undefined; /** Path to built admin frontend directory (optional - auto-detects if omitted) */
staticDir?: string | undefined; /** Optional username for basic auth */
user?: string | undefined; /** Optional password for basic auth */
password?: string | undefined; /** Skip static dir validation (for dev mode) */
devMode?: boolean | undefined;
};
/**
* Creates the admin console middleware.
* @param config - The admin console configuration.
* @param adminContext - The admin context.
* @returns The express request handler.
*/
declare const handlerAdminConsole: (config: AdminConsoleConfig, adminContext: AdminContext) => RequestHandler;
//#endregion
//#region src/backend/handler/handlerSpaFallback.d.ts
/**
* Creates middleware that serves index.html for SPA routes.
*
* Handles React Router (createBrowserRouter), Vue Router, Angular Router, etc.
*
* **CRITICAL**: This middleware MUST be mounted AFTER express-static-gzip.
*
* Middleware order:
* 1. express-static-gzip → Serves actual files (CSS, JS, images)
* 2. handlerSpaFallback → Serves index.html for navigation requests
*
* @param directoryPath - Path to the static directory containing index.html
* @param _route - The route prefix (for debugging)
* @returns Express request handler
*
* @example
* ```typescript
* app.use('/app', expressStaticGzip('./build'));
* app.use('/app', createSpaFallback('./build', '/app'));
* ```
*/
declare const createSpaFallback: (directoryPath: string, _route: string) => RequestHandler;
//#endregion
//#region src/backend/util/file.d.ts
/**
* Read file.
*
* @param filePath - File name.
* @returns The string.
*/
declare const readFileSyncUtf8: (filePath: string) => string;
/**
* Read file.
*
* @param filePath - File name.
* @returns The buffer.
*/
declare const readFile: (filePath: string) => Promise<Buffer>;
/**
* Remove file.
*
* @param filePath - File name.
*/
declare const removeFile: (filePath: string) => Promise<void>;
/**
* Load a json file.
*
* @param filePath - File name.
* @returns The json object.
*/
declare const getJsonFile: (filePath: string) => unknown;
/**
* Is this a directory.
* @param directoryPath - Directory name.
* @returns Return true if it is a directory.
*/
declare const isDirectory: (directoryPath: unknown) => Promise<boolean>;
/**
* Is this a file.
* @param filePath - File name.
* @returns Return true if it is a file.
*/
declare const isFile: (filePath: unknown) => Promise<boolean>;
//#endregion
export { type AdminConsoleConfig, AdminContext, type configPlSqlType, type configType, createAdminRouter, createServer, createSpaFallback, forceShutdown, getJsonFile, getVersion, handlerAdminConsole, handlerLogger, handlerUpload, handlerWebPlSql, installShutdown, isDirectory, isFile, loadConfig, oracledb_provider_d_exports as oracledb, readFile, readFileSyncUtf8, removeFile, showConfig, startServer, startServerConfig, z$configType };
//# sourceMappingURL=index.d.mts.map