web_plsql 1.8.6 → 1.8.8
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/dist/frontend/assets/{main-rZ2yileN.js → main-B-LqjcmS.js} +1 -1
- package/dist/frontend/assets/main-B-LqjcmS.js.br +0 -0
- package/dist/frontend/assets/main-B-LqjcmS.js.gz +0 -0
- package/dist/frontend/assets/{main-CBxeWHJN.css → main-k8GNR9Ye.css} +1 -1
- package/dist/frontend/assets/main-k8GNR9Ye.css.br +0 -0
- package/dist/frontend/assets/main-k8GNR9Ye.css.gz +0 -0
- package/dist/frontend/index.html +2 -2
- package/dist/frontend/index.html.br +0 -0
- package/dist/frontend/index.html.gz +0 -0
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
- package/dist/frontend/assets/main-CBxeWHJN.css.br +0 -0
- package/dist/frontend/assets/main-CBxeWHJN.css.gz +0 -0
- package/dist/frontend/assets/main-rZ2yileN.js.br +0 -0
- package/dist/frontend/assets/main-rZ2yileN.js.gz +0 -0
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["z","z","createPool","debug","oracledb.createPool","debug","debug","fs","debug","debug","debug","debug","debug","debug","debug","debug","debug","URL","debug","debug","z","process"],"sources":["../src/common/configStaticSchema.ts","../src/common/procedureTraceEntry.ts","../src/common/logEntrySchema.ts","../src/backend/types.ts","../src/backend/util/oracledb-mock.ts","../src/backend/util/oracledb-provider.ts","../src/backend/version.ts","../src/backend/server/printBanner.ts","../src/backend/server/server.ts","../src/backend/util/shutdown.ts","../src/common/constants.ts","../src/backend/util/statsManager.ts","../src/backend/server/adminContext.ts","../src/backend/util/file.ts","../src/backend/util/html.ts","../src/backend/util/trace.ts","../src/backend/util/errorToString.ts","../src/backend/handler/plsql/upload.ts","../src/backend/handler/plsql/procedureVariable.ts","../src/backend/handler/plsql/requestError.ts","../src/backend/util/util.ts","../src/backend/handler/plsql/procedureNamed.ts","../src/backend/handler/plsql/parsePage.ts","../src/backend/handler/plsql/sendResponse.ts","../src/backend/handler/plsql/procedureError.ts","../src/backend/util/cache.ts","../src/backend/handler/plsql/procedureSanitize.ts","../src/backend/handler/plsql/owaPageStream.ts","../src/backend/util/traceManager.ts","../src/backend/handler/plsql/procedure.ts","../src/backend/handler/plsql/cgi.ts","../src/backend/util/type.ts","../src/backend/handler/plsql/request.ts","../src/backend/util/jsonLogger.ts","../src/backend/handler/plsql/errorPage.ts","../src/backend/handler/plsql/handlerPlSql.ts","../src/backend/handler/handlerLogger.ts","../src/backend/handler/handlerUpload.ts","../src/backend/handler/handlerAdmin.ts","../src/backend/handler/handlerAdminConsole.ts","../src/backend/handler/handlerSpaFallback.ts","../src/backend/util/printError.ts","../src/backend/util/logError.ts"],"sourcesContent":["import z from 'zod';\n\n/**\n * Configuration for serving static files\n */\nexport const configStaticSchema = z.strictObject({\n\t/** URL route prefix for static assets */\n\troute: z.string(),\n\t/** Local filesystem path to the static assets directory */\n\tdirectoryPath: z.string(),\n\t/**\n\t * Enable SPA fallback mode.\n\t * When true, serves index.html for unmatched routes (for React Router, Vue Router, etc.)\n\t * Requires: Application uses HTML5 History Mode routing\n\t * Default: false\n\t */\n\tspaFallback: z.boolean().optional(),\n});\nexport type configStaticType = z.infer<typeof configStaticSchema>;","import {z} from 'zod';\n\nexport const procedureTraceEntrySchema = z.strictObject({\n\tid: z.string(),\n\ttimestamp: z.string(),\n\tsource: z.string(),\n\turl: z.string(),\n\tmethod: z.string(),\n\tstatus: z.string(),\n\tduration: z.number(),\n\tprocedure: z.string().optional(),\n\tparameters: z.union([z.record(z.string(), z.unknown()), z.array(z.unknown())]).optional(),\n\tuploads: z\n\t\t.array(\n\t\t\tz.strictObject({\n\t\t\t\toriginalname: z.string(),\n\t\t\t\tmimetype: z.string(),\n\t\t\t\tsize: z.number(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n\tdownloads: z\n\t\t.strictObject({\n\t\t\tfileType: z.string(),\n\t\t\tfileSize: z.number(),\n\t\t})\n\t\t.optional(),\n\thtml: z.string().optional(),\n\tcookies: z.record(z.string(), z.string()).optional(),\n\theaders: z.record(z.string(), z.string()).optional(),\n\tcgi: z.record(z.string(), z.string()).optional(),\n\terror: z.string().optional(),\n});\n\nexport type procedureTraceEntry = z.infer<typeof procedureTraceEntrySchema>;","import {z} from 'zod';\n\n/**\n * Error log entry schema.\n */\nconst logEntryTypeSchema = z.union([z.literal('error'), z.literal('info'), z.literal('warning')]);\nexport const logEntrySchema = z.strictObject({\n\ttimestamp: z.string(),\n\ttype: logEntryTypeSchema,\n\tmessage: z.string(),\n\treq: z\n\t\t.strictObject({\n\t\t\tmethod: z.string().optional(),\n\t\t\turl: z.string().optional(),\n\t\t\tip: z.string().optional(),\n\t\t\tuserAgent: z.string().optional(),\n\t\t})\n\t\t.optional(),\n\tdetails: z\n\t\t.strictObject({\n\t\t\tfullMessage: z.string().optional(),\n\t\t\tsql: z.string().optional(),\n\t\t\tbind: z.unknown().optional(),\n\t\t\tenvironment: z.record(z.string(), z.string()).optional(),\n\t\t})\n\t\t.optional(),\n});\nexport type logEntryType = z.infer<typeof logEntrySchema>;","import z from 'zod';\nimport {configStaticSchema} from '../common/configStaticSchema.ts';\nimport type {Connection, Pool} from 'oracledb';\nimport type {CookieOptions, Express, Request} from 'express';\nimport type {Readable} from 'node:stream';\nimport type {Cache} from './util/cache.ts';\n\nexport {procedureTraceEntrySchema, type procedureTraceEntry} from '../common/procedureTraceEntry.ts';\nexport {logEntrySchema, type logEntryType} from '../common/logEntrySchema.ts';\n\n/**\n * Defines the style of error reporting\n * 'basic': standard error messages\n * 'debug': detailed error messages including database context\n */\nconst z$errorStyleType = z.enum(['basic', 'debug']);\n\n/**\n * Custom callback signature for manual transaction handling\n */\ntype transactionCallbackType = (connection: Connection, procedure: string) => void | Promise<void>;\n\n/**\n * Defines how transactions are handled after procedure execution\n * 'commit': automatically commit\n * 'rollback': automatically rollback\n * callback: custom function for manual handling\n */\nconst transactionModeSchema = z.union([\n\tz.custom<transactionCallbackType>((val) => typeof val === 'function', {\n\t\tmessage: 'Invalid transaction callback',\n\t}),\n\tz.literal('commit'),\n\tz.literal('rollback'),\n\tz.undefined(),\n\tz.null(),\n]);\nexport type transactionModeType = z.infer<typeof transactionModeSchema>;\n\n/**\n * Basic authentication callback signature.\n * Returns the identity string on success, or null on failure.\n * @public\n */\nexport type BasicAuthCallback = (credentials: {username: string; password?: string | undefined}, connectionPool: Pool) => Promise<string | null>;\n\n/**\n * Custom authentication callback signature.\n * Returns the identity string on success, or null on failure.\n * @public\n */\nexport type CustomAuthCallback = (req: Request, connectionPool: Pool) => Promise<string | null>;\n\n/**\n * Authentication configuration for a PL/SQL route\n */\nconst z$authSchema = z.union([\n\tz.strictObject({\n\t\t/** Authentication type */\n\t\ttype: z.literal('basic'),\n\t\t/** Callback function to validate credentials */\n\t\tcallback: z.custom<BasicAuthCallback>((val) => typeof val === 'function', {\n\t\t\tmessage: 'Invalid auth callback',\n\t\t}),\n\t\t/** Authentication realm */\n\t\trealm: z.string().optional(),\n\t}),\n\tz.strictObject({\n\t\t/** Authentication type */\n\t\ttype: z.literal('custom'),\n\t\t/** Callback function to validate request */\n\t\tcallback: z.custom<CustomAuthCallback>((val) => typeof val === 'function', {\n\t\t\tmessage: 'Invalid auth callback',\n\t\t}),\n\t}),\n]);\n\n/**\n * PL/SQL handler behavior configuration\n */\nexport const z$configPlSqlHandlerType = z.strictObject({\n\t/** Default procedure to execute if none specified */\n\tdefaultPage: z.string(),\n\t/** Virtual path alias for procedures */\n\tpathAlias: z.string().optional(),\n\t/** Procedure name associated with the path alias */\n\tpathAliasProcedure: z.string().optional(),\n\t/** Database table used for file uploads/downloads */\n\tdocumentTable: z.string(),\n\t/** List of pattern/procedure names excluded from execution */\n\texclusionList: z.array(z.string()).optional(),\n\t/** PL/SQL function called to validate requests */\n\trequestValidationFunction: z.string().optional(),\n\t/** Post-execution transaction behavior */\n\ttransactionMode: transactionModeSchema.optional(),\n\t/** Error reporting style */\n\terrorStyle: z$errorStyleType,\n\t/** Static CGI environment variables to be passed to the session */\n\tcgi: z.record(z.string(), z.string()).optional(),\n\t/** Authentication settings */\n\tauth: z$authSchema.optional(),\n});\nexport type configPlSqlHandlerType = z.infer<typeof z$configPlSqlHandlerType>;\n\n/**\n * Database connection configuration for a PL/SQL route\n */\nconst z$configPlSqlConfigType = z.strictObject({\n\t/** URL route prefix for this database connection */\n\troute: z.string(),\n\t/** Database username */\n\tuser: z.string(),\n\t/** Database password */\n\tpassword: z.string(),\n\t/** Oracle connection string (TNS or EZConnect) */\n\tconnectString: z.string(),\n});\ntype configPlSqlConfigType = z.infer<typeof z$configPlSqlConfigType>;\n\n/**\n * Complete PL/SQL route configuration combining handler and connection settings\n */\nexport type configPlSqlType = configPlSqlHandlerType & configPlSqlConfigType;\nconst z$configPlSqlType = z.strictObject({\n\t...z$configPlSqlHandlerType.shape,\n\t...z$configPlSqlConfigType.shape,\n});\n\n/**\n * Root application configuration\n */\nexport const z$configType = z.strictObject({\n\t/** Server listening port */\n\tport: z.number(),\n\t/** Array of static file routes */\n\trouteStatic: z.array(configStaticSchema),\n\t/** Array of PL/SQL routes */\n\troutePlSql: z.array(z$configPlSqlType),\n\t/** Maximum allowed size for file uploads (bytes) */\n\tuploadFileSizeLimit: z.number().optional(),\n\t/** Path to the log file */\n\tloggerFilename: z.string(),\n\t/** URL route prefix for the admin console */\n\tadminRoute: z.string().optional(),\n\t/** Username for admin console authentication */\n\tadminUser: z.string().optional(),\n\t/** Password for admin console authentication */\n\tadminPassword: z.string().optional(),\n\t/** Developer mode (skips frontend build check, enables CORS) */\n\tdevMode: z.boolean().optional(),\n\t/** Callback function to setup custom Express extensions */\n\tsetupExtensions: z\n\t\t.custom<(app: Express, pools: Pool[]) => void | Promise<void>>((val) => typeof val === 'function', {\n\t\t\tmessage: 'Invalid setupExtensions callback',\n\t\t})\n\t\t.optional(),\n\toracle: z\n\t\t.strictObject({\n\t\t\tpoolMin: z.int().min(10).default(10),\n\t\t\tpoolMax: z.int().min(10).default(100),\n\t\t\tpoolIncrement: z.int().min(1).default(10),\n\t\t})\n\t\t.optional()\n\t\t.default({\n\t\t\tpoolMin: 10,\n\t\t\tpoolMax: 100,\n\t\t\tpoolIncrement: 10,\n\t\t}),\n});\nexport type configInputType = z.input<typeof z$configType>;\nexport type configType = z.output<typeof z$configType>;\n\n/**\n * Environment variables as string key-value pairs\n */\nexport type environmentType = Record<string, string>;\n\n/**\n * HTTP arguments mapping with support for multi-value parameters\n */\nexport type argObjType = Record<string, string | string[]>;\n\n/**\n * Mapping of PL/SQL procedure argument names to their database types\n */\nexport type argsType = Record<string, string>;\n\n/**\n * Metadata for uploaded files\n */\nexport type fileUploadType = {\n\t/** HTML form field name */\n\tfieldname: string;\n\t/** Original filename as uploaded by the client */\n\toriginalname: string;\n\t/** Content encoding */\n\tencoding: string;\n\t/** MIME type */\n\tmimetype: string;\n\t/** Local temporary filename */\n\tfilename: string;\n\t/** Absolute path to the temporary file */\n\tpath: string;\n\t/** File size in bytes */\n\tsize: number;\n};\n\n/**\n * HTTP cookie definition\n */\nexport type cookieType = {\n\t/** Cookie name */\n\tname: string;\n\t/** Cookie value */\n\tvalue: string;\n\t/** Express cookie options (domain, path, expires, etc.) */\n\toptions: CookieOptions;\n};\n\n/**\n * Internal representation of a generated web page or file response\n */\nexport type pageType = {\n\t/** Response body content as string or stream */\n\tbody: string | Readable;\n\t/** HTTP response headers and status */\n\thead: {\n\t\t/** Array of cookies to be set */\n\t\tcookies: cookieType[];\n\t\t/** Content-Type header value */\n\t\tcontentType?: string;\n\t\t/** Content-Length header value */\n\t\tcontentLength?: number;\n\t\t/** HTTP status code */\n\t\tstatusCode?: number;\n\t\t/** HTTP status reason phrase */\n\t\tstatusDescription?: string;\n\t\t/** Location header for redirects */\n\t\tredirectLocation?: string;\n\t\t/** Additional custom HTTP headers */\n\t\totherHeaders: Record<string, string>;\n\t\t/** Server header value */\n\t\tserver?: string;\n\t};\n\t/** Metadata for file downloads if applicable */\n\tfile: {\n\t\t/** MIME type of the file */\n\t\tfileType: string | null;\n\t\t/** Size of the file in bytes */\n\t\tfileSize: number | null;\n\t\t/** File content as stream or buffer */\n\t\tfileBlob: Readable | Buffer | null;\n\t};\n};\n\nexport type ProcedureNameCache = Cache<string>;\nexport type ArgumentCache = Cache<argsType>;","import type {Connection, Pool, Lob, Result, BindParameters, ExecuteOptions, DbType} from 'oracledb';\n\n// Mock implementation\nexport type ExecuteCallback = (sql: string, binds?: BindParameters) => Promise<Result<unknown>> | Result<unknown>;\nlet executeCallback: ExecuteCallback | null = null;\n\n/**\n * Test utility: Set the callback for execute calls.\n * @param cb - The callback\n */\nexport const setExecuteCallback = (cb: ExecuteCallback | null) => {\n\texecuteCallback = cb;\n};\n\n/**\n * Mock LOB class.\n */\nclass MockLob {\n\ttype: DbType | number;\n\tconstructor(type: DbType | number) {\n\t\tthis.type = type;\n\t}\n\t// oxlint-disable-next-line typescript/no-empty-function\n\tdestroy(): void {}\n}\n\n/**\n * Mock Connection class.\n */\nclass MockConnection {\n\tasync execute<T = unknown>(sql: string, bindParams?: BindParameters, _options?: ExecuteOptions): Promise<Result<T>> {\n\t\tif (executeCallback) {\n\t\t\treturn (await executeCallback(sql, bindParams)) as Result<T>;\n\t\t}\n\t\treturn {rows: []} as Result<T>;\n\t}\n\n\t// oxlint-disable-next-line typescript/require-await\n\tasync createLob(type: DbType | number): Promise<Lob> {\n\t\treturn new MockLob(type) as unknown as Lob;\n\t}\n\n\tasync commit(): Promise<void> {\n\t\t// empty\n\t}\n\tasync rollback(): Promise<void> {\n\t\t// empty\n\t}\n\tasync release(): Promise<void> {\n\t\t// empty\n\t}\n}\n\n/**\n * Mock Pool class.\n */\nclass MockPool {\n\tconnectionsOpen = 0;\n\tconnectionsInUse = 0;\n\n\t// oxlint-disable-next-line typescript/require-await\n\tasync getConnection(): Promise<Connection> {\n\t\tthis.connectionsInUse++;\n\t\tthis.connectionsOpen = Math.max(this.connectionsOpen, this.connectionsInUse);\n\t\treturn new MockConnection() as unknown as Connection;\n\t}\n\n\t// oxlint-disable-next-line typescript/require-await\n\tasync close(_drainTime?: number): Promise<void> {\n\t\tthis.connectionsOpen = 0;\n\t\tthis.connectionsInUse = 0;\n\t}\n}\n\n/**\n * Mock createPool function.\n * @param _config - The configuration\n * @returns The pool\n */\n// oxlint-disable-next-line typescript/require-await\nexport async function createPool(_config: unknown): Promise<Pool> {\n\treturn new MockPool() as unknown as Pool;\n}\n\n// Default export mimics oracledb module structure for test mocking\nexport default {\n\t// Constants will be merged from actual oracledb by vi.importActual in test_setup.ts\n\tcreatePool,\n\tsetExecuteCallback,\n};","import oracledb from 'oracledb';\n\nconst USE_MOCK = process.env.MOCK_ORACLE === 'true';\n\n/**\n * Create a database pool.\n * @param config - The pool attributes.\n * @returns The pool.\n */\n// Runtime switch for createPool\nexport async function createPool(config: oracledb.PoolAttributes): Promise<oracledb.Pool> {\n\tif (USE_MOCK) {\n\t\tconst mock = await import('./oracledb-mock.ts');\n\t\treturn mock.createPool(config);\n\t}\n\treturn await oracledb.createPool(config);\n}\n\n// Always export real oracledb constants (they're identical in mock)\nexport const BIND_IN = oracledb.BIND_IN;\nexport const BIND_OUT = oracledb.BIND_OUT;\nexport const BIND_INOUT = oracledb.BIND_INOUT;\nexport const STRING = oracledb.STRING;\nexport const NUMBER = oracledb.NUMBER;\nexport const DATE = oracledb.DATE;\nexport const CURSOR = oracledb.CURSOR;\nexport const BUFFER = oracledb.BUFFER;\nexport const CLOB = oracledb.CLOB;\nexport const BLOB = oracledb.BLOB;\nexport const DB_TYPE_VARCHAR = oracledb.DB_TYPE_VARCHAR;\nexport const DB_TYPE_CLOB = oracledb.DB_TYPE_CLOB;\nexport const DB_TYPE_NUMBER = oracledb.DB_TYPE_NUMBER;\nexport const DB_TYPE_DATE = oracledb.DB_TYPE_DATE;\n\n// Re-export types from real oracledb for convenience\nexport type {Connection, Pool, Lob, Result, BindParameter, BindParameters, ExecuteOptions, DbType} from 'oracledb';\n\n// Export mock-specific utilities\nexport {setExecuteCallback, type ExecuteCallback} from './oracledb-mock.ts';","declare global {\n\tvar __VERSION__: string;\n}\n\nglobalThis.__VERSION__ ??= '**development**';\n\ndeclare const __VERSION__: string;\n\n/**\n * Returns the current library version\n * @returns {string} - Version.\n */\nexport const getVersion = () => __VERSION__;","import chalk from 'chalk';\nimport stringWidth from 'string-width';\nimport sliceAnsi from 'slice-ansi';\nimport {getVersion} from '../version.ts';\nimport type {configType} from '../types.ts';\n\n// ── TTY\nconst IS_TTY = process.stdout.isTTY === true;\n\n// ── Icons\n// Authoritative form is the hex escape; emoji in comments are for readability only.\n// ICON_GEAR uses U+2699 without VS-16 (U+FE0F) intentionally — the variation selector\n// forces emoji presentation and makes string-width report width=2. Without it the\n// character is \"ambiguous\" and resolves to width=1 via the ambiguousIsNarrow option below.\nconst ICON_GLOBE = '\\u{1F310}'; // 🌐\nconst ICON_KEY = '\\u{1F511}'; // 🔑\nconst ICON_DOC = '\\u{1F4C4}'; // 📄\nconst ICON_PACKAGE = '\\u{1F4E6}'; // 📦\nconst ICON_LINK = '\\u{1F517}'; // 🔗\nconst ICON_FOLDER = '\\u{1F4C1}'; // 📁\nconst ICON_GEAR = '\\u{1F527}'; // 🔧\nconst ICON_HOME = '\\u{1F3E0}'; // 🏠\n\n// ── Layout\n// Each row: │(1) space(1) label(35) sep(1) value(40) space(1) │(1) = 80\nconst W = 80;\nconst LABEL_W = 35;\nconst VALUE_W = W - LABEL_W - 5; // 5 = left-border + left-space + separator + right-space + right-border\n\nconst BOX = {\n\th: '─',\n\tv: '│',\n\ttl: '╭',\n\ttr: '╮',\n\tbl: '╰',\n\tbr: '╯',\n\tml: '├',\n\tmr: '┤',\n} as const;\n\n/* Returns the visible terminal column-width of `s`. */\nconst displayWidth = (s: string): number => stringWidth(s, {ambiguousIsNarrow: true});\n\n/* Pads `s` with trailing spaces to `w` visible columns. Returns `s` unchanged if already ≥ `w`. */\nconst padTo = (s: string, w: number): string => {\n\tconst delta = w - displayWidth(s);\n\treturn delta > 0 ? s + ' '.repeat(delta) : s;\n};\n\n/* Truncates `s` to at most `w` visible columns. */\nconst truncateTo = (s: string, w: number): string => (w > 0 ? sliceAnsi(s, 0, w) : '');\n\n/* Mid-box horizontal divider. */\nconst divider = (): string => (IS_TTY ? chalk.dim(BOX.ml + BOX.h.repeat(W - 2) + BOX.mr) : '-'.repeat(W));\n\n/* Opening border. */\nconst borderOpen = (): string => (IS_TTY ? chalk.dim(BOX.tl + BOX.h.repeat(W - 2) + BOX.tr) : divider());\n\n/* Closing border. */\nconst borderClose = (): string => (IS_TTY ? chalk.dim(BOX.bl + BOX.h.repeat(W - 2) + BOX.br) : divider());\n\n/**\n * Single key/value row.\n * @param key - Label text.\n * @param value - Display value; null/undefined/empty renders as a dim dash.\n * @param icon - Optional leading icon (must be a single-cell or double-cell glyph).\n * @returns Formatted string.\n */\nconst row = (key: string, value: string | number | null | undefined, icon?: string): string => {\n\tconst left = IS_TTY ? (icon ? `${icon} ${key}` : ` ${key}`) : `${key}`;\n\tconst label = padTo(left, LABEL_W);\n\tconst hasValue = value !== null && value !== undefined && value !== '';\n\tconst valueText = hasValue ? String(value) : '—';\n\tconst colorFn = hasValue ? chalk.white : chalk.dim;\n\tconst valueCell = padTo(truncateTo(valueText, VALUE_W), VALUE_W);\n\n\treturn IS_TTY ? chalk.dim(BOX.v) + ' ' + chalk.dim(label) + ' ' + colorFn(valueCell) + ' ' + chalk.dim(BOX.v) : label + ' ' + valueCell;\n};\n\n/**\n * Renders the server startup banner to stdout.\n * @param cfg - Server configuration.\n */\nexport const printBanner = (cfg: configType): void => {\n\tconst adminRoute = cfg.adminRoute ?? '/admin';\n\tconst baseUrl = `http://localhost:${cfg.port}`;\n\tconst lines: string[] = [];\n\n\t// ── top border\n\tlines.push(borderOpen());\n\n\t// ── title\n\tconst title = `NODE PL/SQL SERVER ${getVersion()}`;\n\tconst pad = W - 2 - displayWidth(title);\n\tlines.push(IS_TTY ? chalk.dim(BOX.v) + ' '.repeat(Math.floor(pad / 2)) + chalk.bold.cyan(title) + ' '.repeat(Math.ceil(pad / 2)) + chalk.dim(BOX.v) : title);\n\tlines.push(divider());\n\n\t// ── server\n\tlines.push(row('Port', cfg.port, ICON_GLOBE));\n\tlines.push(row('Admin route', `${adminRoute}${cfg.adminUser ? ' (authenticated)' : ''}`, ICON_KEY));\n\tlines.push(row('Access log', cfg.loggerFilename, ICON_DOC));\n\tlines.push(row('Upload limit', typeof cfg.uploadFileSizeLimit === 'number' ? `${cfg.uploadFileSizeLimit} bytes` : null, ICON_PACKAGE));\n\tlines.push(divider());\n\n\t// ── connection pool\n\tlines.push(row('Oracle pool min', cfg.oracle.poolMin, ICON_LINK));\n\tlines.push(row('Oracle pool max', cfg.oracle.poolMax, ICON_LINK));\n\tlines.push(row('Oracle pool increment', cfg.oracle.poolIncrement, ICON_LINK));\n\n\t// ── static routes\n\tif (cfg.routeStatic.length > 0) {\n\t\tlines.push(divider());\n\t\tcfg.routeStatic.forEach((r, i) => {\n\t\t\tlines.push(row(`Static route #${i + 1} route`, r.route, ICON_FOLDER));\n\t\t\tlines.push(row(`Static route #${i + 1} path`, r.directoryPath));\n\t\t});\n\t}\n\n\t// ── PL/SQL routes\n\tif (cfg.routePlSql.length > 0) {\n\t\tlines.push(divider());\n\t\tcfg.routePlSql.forEach((r, i) => {\n\t\t\tconst txMode = typeof r.transactionMode === 'string' ? r.transactionMode : r.transactionMode ? 'custom' : '';\n\t\t\tconst n = `PL/SQL route #${i + 1}`;\n\n\t\t\tlines.push(row(`${n} route`, r.route, ICON_GEAR));\n\t\t\tlines.push(row(`${n} Oracle user`, r.user));\n\t\t\tlines.push(row(`${n} Oracle server`, r.connectString));\n\t\t\tlines.push(row(`${n} document table`, r.documentTable));\n\t\t\tlines.push(row(`${n} default page`, r.defaultPage));\n\t\t\tlines.push(row(`${n} path alias`, r.pathAlias ?? ''));\n\t\t\tlines.push(row(`${n} path alias proc`, r.pathAliasProcedure ?? ''));\n\t\t\tlines.push(row(`${n} exclusion list`, r.exclusionList?.join(', ') ?? ''));\n\t\t\tlines.push(row(`${n} validation fn`, r.requestValidationFunction ?? ''));\n\t\t\tlines.push(row(`${n} session mode`, txMode));\n\t\t\tlines.push(row(`${n} auth`, typeof r.auth === 'string' ? r.auth : ''));\n\t\t\tlines.push(row(`${n} error style`, r.errorStyle));\n\t\t});\n\t}\n\n\t// ── footer: quick-access URLs\n\tlines.push(divider());\n\tlines.push(row('Admin console', `${baseUrl}${adminRoute}`, ICON_HOME));\n\tcfg.routePlSql.forEach((r) => {\n\t\tlines.push(row(r.route, `${baseUrl}${r.route}`, ICON_GEAR));\n\t});\n\tlines.push(borderClose());\n\n\tconsole.log(lines.join('\\n'));\n};","import debugModule from 'debug';\nconst debug = debugModule('webplsql:server');\n\nimport http from 'node:http';\nimport https from 'node:https';\nimport type {Socket} from 'node:net';\n\nimport express, {type Express, type Request, type Response, type NextFunction} from 'express';\nimport type {Pool} from 'oracledb';\nimport cors from 'cors';\nimport cookieParser from 'cookie-parser';\nimport compression from 'compression';\nimport expressStaticGzip from 'express-static-gzip';\n\n// NOTE: it is only allowed to import from the API './index.ts'\nimport {\n\thandlerWebPlSql,\n\thandlerAdminConsole,\n\thandlerUpload,\n\thandlerLogger,\n\tAdminContext,\n\tprintBanner,\n\treadFileSyncUtf8,\n\tgetJsonFile,\n\tinstallShutdown,\n\tz$configType,\n\ttype configInputType,\n\ttype configType,\n\ttype configPlSqlType,\n\toracledb,\n\tcreateSpaFallback,\n} from '../index.ts';\n\n/**\n * Close multiple pools.\n * @param pools - The pools to close.\n */\nexport const poolsClose = async (pools: Pool[]): Promise<void> => {\n\tawait Promise.all(pools.map((pool) => pool.close(0)));\n};\n\nexport type webServer = {\n\tconfig: configType;\n\tconnectionPools: Pool[];\n\tapp: Express;\n\tserver: http.Server | https.Server;\n\tadminContext: AdminContext;\n\tshutdown: () => Promise<void>;\n};\n\nexport type sslConfig = {\n\tkeyFilename: string;\n\tcertFilename: string;\n};\n\n/**\n * Create HTTPS server.\n * @param app - express application\n * @param ssl - ssl configuration.\n * @returns server\n */\nexport const createServer = (app: Express, ssl?: sslConfig): http.Server | https.Server => {\n\tif (ssl) {\n\t\tconst key = readFileSyncUtf8(ssl.keyFilename);\n\t\tconst cert = readFileSyncUtf8(ssl.certFilename);\n\n\t\treturn https.createServer({key, cert}, app);\n\t} else {\n\t\treturn http.createServer(app);\n\t}\n};\n\n/**\n * Start server.\n * @param config - The config.\n * @param ssl - ssl configuration.\n * @returns Promise resolving to the web server object.\n */\nexport const startServer = async (config: configInputType, ssl?: sslConfig): Promise<webServer> => {\n\tdebug('startServer: BEGIN', config, ssl);\n\n\tconst internalConfig = z$configType.parse(config);\n\n\tprintBanner(internalConfig);\n\n\t// Create express app\n\tconst app = express();\n\n\t// Default middleware\n\tif (internalConfig.devMode) {\n\t\tapp.use(\n\t\t\tcors({\n\t\t\t\torigin: 'http://localhost:5173',\n\t\t\t\tcredentials: true,\n\t\t\t}),\n\t\t);\n\t}\n\tapp.use(handlerUpload(internalConfig.uploadFileSizeLimit));\n\tapp.use(express.json({limit: '50mb'}));\n\tapp.use(express.urlencoded({limit: '50mb', extended: true}));\n\tapp.use(cookieParser());\n\tapp.use(compression());\n\n\t// Create AdminContext\n\tconst adminContext = new AdminContext(internalConfig);\n\n\t// Mount Admin Console (includes Pause middleware)\n\tapp.use(\n\t\thandlerAdminConsole(\n\t\t\t{\n\t\t\t\tadminRoute: internalConfig.adminRoute,\n\t\t\t\tuser: internalConfig.adminUser,\n\t\t\t\tpassword: internalConfig.adminPassword,\n\t\t\t\tdevMode: internalConfig.devMode,\n\t\t\t},\n\t\t\tadminContext,\n\t\t),\n\t);\n\n\t// Oracle pl/sql express middleware\n\tfor (const i of internalConfig.routePlSql) {\n\t\t// Allocate the Oracle database pool\n\t\tconst pool = await oracledb.createPool({\n\t\t\tuser: i.user,\n\t\t\tpassword: i.password,\n\t\t\tconnectString: i.connectString,\n\t\t\tpoolMin: internalConfig.oracle.poolMin,\n\t\t\tpoolMax: internalConfig.oracle.poolMax,\n\t\t\tpoolIncrement: internalConfig.oracle.poolIncrement,\n\t\t});\n\n\t\tconst handler = handlerWebPlSql(pool, i as configPlSqlType, adminContext);\n\n\t\tapp.use([`${i.route}/:name`, i.route], (req: Request, res: Response, next: NextFunction) => {\n\t\t\tconst start = process.hrtime();\n\t\t\tres.on('finish', () => {\n\t\t\t\tconst diff = process.hrtime(start);\n\t\t\t\tconst duration = diff[0] * 1000 + diff[1] / 1_000_000;\n\t\t\t\tadminContext.statsManager.recordRequest(duration, res.statusCode >= 400);\n\t\t\t});\n\t\t\thandler(req, res, next);\n\t\t});\n\t}\n\n\t// Access log\n\tif (internalConfig.loggerFilename.length > 0) {\n\t\tapp.use(handlerLogger(internalConfig.loggerFilename));\n\t}\n\n\t// Execute custom extensions before static/SPA routes capture the request\n\tif (internalConfig.setupExtensions) {\n\t\tawait internalConfig.setupExtensions(app, adminContext.pools);\n\t}\n\n\t// Serving static files\n\tfor (const i of internalConfig.routeStatic) {\n\t\tapp.use(\n\t\t\ti.route,\n\t\t\texpressStaticGzip(i.directoryPath, {\n\t\t\t\tenableBrotli: true,\n\t\t\t\torderPreference: ['br'],\n\t\t\t}),\n\t\t);\n\n\t\t// Mount SPA fallback (serves index.html for unmatched routes)\n\t\t// IMPORTANT: Must come AFTER expressStaticGzip\n\t\tif (i.spaFallback) {\n\t\t\tapp.use(i.route, createSpaFallback(i.directoryPath, i.route));\n\t\t}\n\t}\n\n\t// Mount PL/SQL handlers with stats tracking\n\t// (already mounted in the loop above)\n\n\t// create server\n\tdebug('startServer: createServer');\n\tconst server = createServer(app, ssl);\n\n\t// Track open connections\n\tconst connections = new Set<Socket>();\n\tserver.on('connection', (socket: Socket) => {\n\t\tconnections.add(socket);\n\t\tsocket.on('close', () => {\n\t\t\tconnections.delete(socket);\n\t\t});\n\t});\n\n\tconst closeAllConnections = () => {\n\t\tfor (const socket of connections) {\n\t\t\tsocket.destroy(); // forcibly closes the connection\n\t\t\tconnections.delete(socket);\n\t\t}\n\t};\n\n\tconst shutdown = async () => {\n\t\tdebug('startServer: onShutdown');\n\n\t\tadminContext.statsManager.stop();\n\n\t\tawait poolsClose(adminContext.pools);\n\n\t\tserver.close(() => {\n\t\t\tconsole.log('Server has closed');\n\t\t\tprocess.exit(0);\n\t\t});\n\n\t\tcloseAllConnections();\n\t};\n\n\t// Install shutdown handler\n\tinstallShutdown(shutdown);\n\n\t// Listen\n\tdebug('startServer: start listener');\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver\n\t\t\t.listen(internalConfig.port)\n\t\t\t.on('listening', () => {\n\t\t\t\tdebug('startServer: listener running');\n\t\t\t\tresolve();\n\t\t\t})\n\t\t\t.on('error', (err: NodeJS.ErrnoException) => {\n\t\t\t\tif ('code' in err) {\n\t\t\t\t\tif (err.code === 'EADDRINUSE') {\n\t\t\t\t\t\terr.message = `Port ${internalConfig.port} is already in use`;\n\t\t\t\t\t} else if (err.code === 'EACCES') {\n\t\t\t\t\t\terr.message = `Port ${internalConfig.port} requires elevated privileges`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treject(err);\n\t\t\t});\n\t});\n\n\tdebug('startServer: END');\n\n\treturn {\n\t\tconfig: internalConfig,\n\t\tconnectionPools: adminContext.pools,\n\t\tapp,\n\t\tserver,\n\t\tadminContext,\n\t\tshutdown,\n\t};\n};\n\n/**\n * Load configuration.\n * @param filename - The configuration filename.\n * @returns Promise.\n */\nexport const loadConfig = (filename = 'config.json'): configType => z$configType.parse(getJsonFile(filename));\n\n/**\n * Start server from config file.\n * @param filename - The configuration filename.\n * @param ssl - ssl configuration.\n * @returns Promise resolving to the web server object.\n */\nexport const startServerConfig = async (filename = 'config.json', ssl?: sslConfig): Promise<webServer> => startServer(loadConfig(filename), ssl);","import debugModule from 'debug';\nconst debug = debugModule('webplsql:shutdown');\n\n/**\n * Install a shutdown handler.\n * @param handler - Shutdown handler\n */\nexport const installShutdown = (handler: () => Promise<void>): void => {\n\tdebug('installShutdown');\n\n\tlet isShuttingDown = false;\n\n\t/*\n\t *\tThe 'unhandledRejection' event is emitted whenever a Promise is rejected and no error handler is attached to the promise within a turn of the event loop.\n\t */\n\tprocess.on('unhandledRejection', (reason) => {\n\t\tif (isShuttingDown) {\n\t\t\treturn;\n\t\t}\n\t\tisShuttingDown = true;\n\n\t\tif (reason instanceof Error) {\n\t\t\tconsole.error(`\\n${reason.message}. Graceful shutdown...`);\n\t\t} else {\n\t\t\tconsole.error('\\nUnhandled promise rejection. Graceful shutdown...', reason);\n\t\t}\n\t\tvoid handler().catch((err: unknown) => {\n\t\t\tconsole.error('Error during shutdown:', err);\n\t\t\tprocess.exit(1);\n\t\t});\n\t});\n\n\t// install signal event handler\n\tprocess.on('SIGTERM', function sigterm() {\n\t\tif (isShuttingDown) {\n\t\t\treturn;\n\t\t}\n\t\tisShuttingDown = true;\n\n\t\tconsole.log('\\nGot SIGTERM (aka docker container stop). Graceful shutdown...');\n\t\tvoid handler().catch((err: unknown) => {\n\t\t\tconsole.error('Error during shutdown:', err);\n\t\t\tprocess.exit(1);\n\t\t});\n\t});\n\n\tprocess.on('SIGINT', function sigint() {\n\t\tif (isShuttingDown) {\n\t\t\treturn;\n\t\t}\n\t\tisShuttingDown = true;\n\n\t\tconsole.log('\\nGot SIGINT (aka ctrl-c in docker). Graceful shutdown...');\n\t\tvoid handler().catch((err: unknown) => {\n\t\t\tconsole.error('Error during shutdown:', err);\n\t\t\tprocess.exit(1);\n\t\t});\n\t});\n};\n\n/**\n * Force a shutdown.\n */\nexport const forceShutdown = (): void => {\n\tdebug('forceShutdown');\n\n\tprocess.kill(process.pid, 'SIGTERM');\n};","/**\n * Web PL/SQL Gateway - Common Shared Constants\n *\n * This file centralizes all hardcoded numeric and string constants used throughout\n * the application. Constants are organized by functional category.\n */\n\n// =============================================================================\n// CACHE CONFIGURATION\n// =============================================================================\n\n/**\n * DEFAULT_CACHE_MAX_SIZE = 10000\n *\n * Purpose: Maximum number of entries in the generic LFU (Least Frequently Used) cache.\n *\n * Used By:\n * - procedureNameCache: Caches resolved Oracle procedure names (e.g., \"HR.EMPLOYEES\")\n * - argumentCache: Caches procedure argument introspection results from all_arguments view\n *\n * Related Values:\n * - CACHE_PRUNE_PERCENT (0.1): When cache is full, removes 10% = 1000 entries\n * - Cache instantiation in src/handler/plsql/handlerPlSql.js creates new Cache() without params\n *\n * Implications:\n * - Memory footprint: ~1-2MB at max capacity (strings + hitCount metadata)\n * - Pruning: Removes least-frequently-used entries when full\n * - Higher values = better cache hit rates but more memory\n */\nexport const DEFAULT_CACHE_MAX_SIZE = 10_000;\n\n/**\n * CACHE_PRUNE_PERCENT = 0.1\n *\n * Purpose: Fraction of cache entries to remove during pruning (10%).\n *\n * Used By: Cache.prune() method only\n *\n * Related Values:\n * - DEFAULT_CACHE_MAX_SIZE (10000): Applied to this value to calculate removeCount = 1000\n *\n * Implications:\n * - Balances between removing too few entries (frequent pruning) vs too many (evicting useful data)\n * - 10% is a common pattern for cache eviction\n */\nexport const CACHE_PRUNE_PERCENT = 0.1;\n\n// =============================================================================\n// ORACLE LIMITS\n// =============================================================================\n\n/**\n * MAX_PROCEDURE_PARAMETERS = 1000\n *\n * Purpose: Maximum number of procedure arguments that can be introspected from Oracle's\n * all_arguments view using BULK COLLECT with dbms_utility.name_resolve.\n *\n * Used By:\n * - src/handler/plsql/procedureNamed.js\n * bind.names = {maxArraySize: MAX_PARAMETER_NUMBER}\n * bind.types = {maxArraySize: MAX_PARAMETER_NUMBER}\n *\n * Related Values:\n * - Procedure introspection SQL: SQL_GET_ARGUMENT block at procedureNamed.js:27-43\n * - oracledb.BIND_OUT direction for array fetches\n *\n * Implications:\n * - This is an Oracle driver limitation for array binding, not an arbitrary choice\n * - Procedures with >1000 arguments will have introspection truncated\n * - No error handling exists for this edge case\n * - Practical limit: most procedures have <50 arguments\n */\nexport const MAX_PROCEDURE_PARAMETERS = 1000;\n\n/**\n * OWA_STREAM_CHUNK_SIZE = 1000\n *\n * Purpose: Number of lines fetched per Oracle OWA call when streaming page content.\n *\n * Used By:\n * - owaPageStream.js: maxArraySize for :lines bind variable\n * - owaPageStream.js: :irows INOUT parameter value\n * - owaPageStream.js: Determines when streaming is complete (lines.length < chunkSize)\n *\n * Related Values:\n * - OWA_GET_PAGE_SQL: 'BEGIN owa.get_page(thepage=>:lines, irows=>:irows); END;'\n * - OWAPageStream class constructor at line 20\n *\n * Implications:\n * - Controls round-trip frequency to Oracle database\n * - Higher = fewer round-trips but larger memory buffers per fetch\n * - Lower = more responsive streaming but more database calls\n * - Each line is a PL/SQL varchar2; total data per chunk depends on htp.htbuf_len (63 chars)\n * - Estimated max data per chunk: 1000 lines × 63 chars = 63KB\n */\nexport const OWA_STREAM_CHUNK_SIZE = 1000;\n\n// =============================================================================\n// STREAMING\n// =============================================================================\n\n/**\n * OWA_STREAM_BUFFER_SIZE = 16384\n *\n * Purpose: Node.js Readable stream highWaterMark in bytes (16KB).\n *\n * Used By: OWAPageStream class extends Readable stream\n *\n * Related Values:\n * - OWA_STREAM_CHUNK_SIZE (1000): Lines per fetch\n * - Default Node.js highWaterMark is 64KB (Readable stream default)\n * - OWAPageStream.push() converts lines to string buffer\n *\n * Implications:\n * - Smaller than default (64KB) = more frequent _read() callbacks\n * - Reduces memory footprint for large responses\n * - Improves backpressure handling responsiveness\n * - Trade-off: More CPU for _read() calls vs memory efficiency\n */\nexport const OWA_STREAM_BUFFER_SIZE = 16_384;\n\n/**\n * OWA_RESOLVED_NAME_MAX_LEN = 400\n *\n * Purpose: Maximum string length for resolved Oracle procedure canonical names.\n * Canonical format: SCHEMA.PACKAGE.PROCEDURE or SCHEMA.PROCEDURE.\n *\n * Used By:\n * - resolveProcedureName() function for dbms_utility.name_resolve output\n * - Procedure name resolution SQL at procedureSanitize.js:46-76\n *\n * Related Values:\n * - dbms_utility.name_resolve context = 1 (procedure/function resolution)\n * - Oracle identifier limits: Schema (128) + Package (128) + Procedure (128) + 2 dots = ~386\n * - 400 provides comfortable headroom\n *\n * Implications:\n * - Oracle object names: 30 bytes for most, extended to 128 in some contexts\n * - Canonical name: schema.package.procedure (max ~128+1+128+1+128 = 386)\n * - 400 is safe upper bound with margin\n */\nexport const OWA_RESOLVED_NAME_MAX_LEN = 400;\n\n// =============================================================================\n// STATS COLLECTION\n// =============================================================================\n\n/**\n * STATS_INTERVAL_MS = 5000\n *\n * Purpose: Duration of each statistical bucket in milliseconds.\n *\n * Used By:\n * - src/util/statsManager.js:165: setInterval(this.rotateBucket, this.config.intervalMs)\n * - src/handler/handlerAdmin.js:123: Exposed as intervalMs in /api/status response\n * - src/frontend/main.ts\n * - src/frontend/charts.ts\n *\n * Related Values:\n * - MAX_HISTORY_BUCKETS (1000): At 5s per bucket = ~83 minutes of history\n * - MAX_PERCENTILE_SAMPLES (1000): Samples per bucket for P95/P99\n *\n * Implications:\n * - Bucket aggregation: request counts, durations, errors, system metrics\n * - Affects granularity of performance monitoring\n * - Lower values = more granular but more history entries\n * - Higher values = smoother averages but less detail\n */\nexport const STATS_INTERVAL_MS = 5000;\n\n/**\n * MAX_HISTORY_BUCKETS = 1000\n *\n * Purpose: Maximum number of statistical buckets retained in StatsManager ring buffer.\n *\n * Used By:\n * - src/util/statsManager.js: Ring buffer limit check\n * if (this.history.length > this.config.maxHistoryPoints) { this.history.shift(); }\n * - Exposed via /api/stats/history endpoint\n *\n * Related Values:\n * - STATS_INTERVAL_MS (5000): 5s per bucket = ~83 minutes total history\n * - Each bucket contains: timestamp, requestCount, errors, durations, system metrics\n * - Bucket memory estimate: ~100 bytes × 1000 = ~100KB\n *\n * Implications:\n * - Ring buffer: oldest bucket is removed when new one exceeds limit\n * - Affects admin console chart history display\n * - Higher = more historical context but more memory\n */\nexport const MAX_HISTORY_BUCKETS = 1000;\n\n/**\n * MAX_PERCENTILE_SAMPLES = 1000\n *\n * Purpose: Maximum number of request duration samples collected per bucket\n * for calculating P95/P99 percentiles.\n *\n * Used By:\n * - src/util/statsManager.js: Array length check\n * if (b.durations.length < this.config.percentilePrecision)\n * - src/util/statsManager.js: P95/P99 calculation\n *\n * Related Values:\n * - Percentile calculation: floor(length × 0.95) and floor(length × 0.99)\n * - FIFO replacement: When exceeded, new samples replace oldest\n *\n * Implications:\n * - With 1000 samples, P95/P99 are statistically meaningful\n * - Higher = more accurate percentiles but more memory per bucket\n * - With STATS_INTERVAL_MS = 5000, 1000 samples ≈ 5 req/sec sustained\n * - Under heavy load, older samples are discarded (FIFO)\n */\nexport const MAX_PERCENTILE_SAMPLES = 1000;\n\n// =============================================================================\n// SHUTDOWN\n// =============================================================================\n\n/**\n * SHUTDOWN_GRACE_DELAY_MS = 100\n *\n * Purpose: Delay between initiating server shutdown and forced termination.\n *\n * Used By: POST /api/server/stop handler only\n *\n * Related Values:\n * - forceShutdown() at src/util/shutdown.js\n * - SIGTERM/SIGINT handlers at shutdown.js\n *\n * Implications:\n * - Allows graceful completion of in-flight requests\n * - Gives Express middleware time to send final responses\n * - 100ms is short; may be insufficient under heavy load\n * - Consider making configurable for high-traffic deployments\n */\nexport const SHUTDOWN_GRACE_DELAY_MS = 100;\n\n// =============================================================================\n// LOG ROTATION - TRACE\n// =============================================================================\n\n/**\n * TRACE_LOG_ROTATION_SIZE = '10M'\n *\n * Purpose: Log file size threshold triggering trace log rotation (10 Megabytes).\n *\n * Used By: rotating-file-stream library for 'trace.log'\n *\n * Related Values:\n * - TRACE_LOG_ROTATION_INTERVAL ('1d'): Also triggers rotation\n * - TRACE_LOG_MAX_ROTATED_FILES (10): Maximum retained files\n *\n * Implications:\n * - When either size OR time threshold is reached, rotation occurs\n * - Combined with daily rotation: ~10MB/day minimum\n * - gzip compression reduces rotated file size by ~70-90%\n */\nexport const TRACE_LOG_ROTATION_SIZE = '10M';\n\n/**\n * TRACE_LOG_ROTATION_INTERVAL = '1d'\n *\n * Purpose: Time-based trace log rotation trigger (daily).\n *\n * Used By: rotating-file-stream library for 'trace.log'\n *\n * Implications:\n * - Guarantees at least one rotation per day\n * - Midnight-based or 24h from first write\n */\nexport const TRACE_LOG_ROTATION_INTERVAL = '1d';\n\n/**\n * TRACE_LOG_MAX_ROTATED_FILES = 10\n *\n * Purpose: Maximum number of rotated trace log files to retain.\n *\n * Used By: rotating-file-stream library for 'trace.log'\n *\n * Implications:\n * - When exceeded, oldest rotated file is deleted\n * - Maximum: ~10 files × 10MB = ~100MB (compressed: ~10-30MB)\n */\nexport const TRACE_LOG_MAX_ROTATED_FILES = 10;\n\n// =============================================================================\n// LOG ROTATION - JSON\n// =============================================================================\n\n/**\n * JSON_LOG_ROTATION_SIZE = '10M'\n *\n * Purpose: Log file size threshold triggering JSON error log rotation (10 Megabytes).\n *\n * Used By: rotating-file-stream library for 'error.json.log'\n *\n * Related Values:\n * - JSON_LOG_ROTATION_INTERVAL ('1d'): Also triggers rotation\n * - JSON_LOG_MAX_ROTATED_FILES (10): Maximum retained files\n *\n * Implications:\n * - When either size OR time threshold is reached, rotation occurs\n * - Combined with daily rotation: ~10MB/day minimum\n * - gzip compression reduces rotated file size by ~70-90%\n */\nexport const JSON_LOG_ROTATION_SIZE = '10M';\n\n/**\n * JSON_LOG_ROTATION_INTERVAL = '1d'\n *\n * Purpose: Time-based JSON error log rotation trigger (daily).\n *\n * Used By: rotating-file-stream library for 'error.json.log'\n *\n * Implications:\n * - Guarantees at least one rotation per day\n * - Midnight-based or 24h from first write\n */\nexport const JSON_LOG_ROTATION_INTERVAL = '1d';\n\n/**\n * JSON_LOG_MAX_ROTATED_FILES = 10\n *\n * Purpose: Maximum number of rotated JSON error log files to retain.\n *\n * Used By: rotating-file-stream library for 'error.json.log'\n *\n * Implications:\n * - When exceeded, oldest rotated file is deleted\n * - Maximum: ~10 files × 10MB = ~100MB (compressed: ~10-30MB)\n */\nexport const JSON_LOG_MAX_ROTATED_FILES = 10;","import debugModule from 'debug';\nimport os from 'node:os';\nimport {STATS_INTERVAL_MS, MAX_HISTORY_BUCKETS, MAX_PERCENTILE_SAMPLES} from '../../common/constants.ts';\n\nconst debug = debugModule('webplsql:statsManager');\n\ntype StatsConfig = {\n\tintervalMs: number;\n\tmaxHistoryPoints: number;\n\tsampleSystem: boolean;\n\tsamplePools: boolean;\n\tpercentilePrecision: number;\n};\n\ntype CacheStats = {\n\tsize: number;\n\thits: number;\n\tmisses: number;\n};\n\ntype PoolCacheSnapshot = {\n\tprocedureName: CacheStats;\n\targument: CacheStats;\n};\n\nexport type PoolSnapshot = {\n\tname: string;\n\tconnectionsInUse: number;\n\tconnectionsOpen: number;\n\tcache?: PoolCacheSnapshot;\n};\n\ntype Bucket = {\n\ttimestamp: number;\n\trequests: number;\n\terrors: number;\n\tdurationMin: number;\n\tdurationMax: number;\n\tdurationAvg: number;\n\tdurationP95: number;\n\tdurationP99: number;\n\tsystem: {\n\t\tcpu: number;\n\t\theapUsed: number;\n\t\theapTotal: number;\n\t\trss: number;\n\t\texternal: number;\n\t};\n\tpools: PoolSnapshot[];\n};\n\ntype CurrentBucket = {\n\tcount: number;\n\terrors: number;\n\tdurationSum: number;\n\tdurationMin: number;\n\tdurationMax: number;\n\tdurations: number[];\n};\n\ntype MemoryLifetime = {\n\theapUsedMax: number;\n\theapTotalMax: number;\n\trssMax: number;\n\texternalMax: number;\n};\n\ntype LifetimeStats = {\n\ttotalRequests: number;\n\ttotalErrors: number;\n\tminDuration: number;\n\tmaxDuration: number;\n\ttotalDuration: number;\n\tmaxRequestsPerSecond: number;\n\tmemory: MemoryLifetime;\n\tcpu: {\n\t\tmax: number;\n\t\tuserMax: number;\n\t\tsystemMax: number;\n\t};\n};\n\ntype StatsSummary = {\n\tstartTime: Date;\n\ttotalRequests: number;\n\ttotalErrors: number;\n\tavgResponseTime: number;\n\tminResponseTime: number;\n\tmaxResponseTime: number;\n\tmaxRequestsPerSecond: number;\n\tmaxMemory: MemoryLifetime;\n\tcpu: {\n\t\tmax: number;\n\t\tuserMax: number;\n\t\tsystemMax: number;\n\t};\n};\n\n/**\n * Manager for statistical data collection and temporal bucketing.\n */\nexport class StatsManager {\n\tconfig: StatsConfig;\n\tstartTime: Date;\n\thistory: Bucket[];\n\tlifetime: LifetimeStats;\n\t_currentBucket: CurrentBucket;\n\t_lastCpuTimes: {user: number; nice: number; sys: number; idle: number; irq: number; total: number};\n\t_timer: NodeJS.Timeout | undefined;\n\n\t/**\n\t * @param config - Configuration.\n\t */\n\tconstructor(config: Partial<StatsConfig> = {}) {\n\t\tthis.config = {\n\t\t\tintervalMs: STATS_INTERVAL_MS,\n\t\t\tmaxHistoryPoints: MAX_HISTORY_BUCKETS,\n\t\t\tsampleSystem: true,\n\t\t\tsamplePools: true,\n\t\t\tpercentilePrecision: MAX_PERCENTILE_SAMPLES,\n\t\t\t...config,\n\t\t};\n\n\t\tthis.startTime = new Date();\n\t\tthis.history = [];\n\n\t\tthis.lifetime = {\n\t\t\ttotalRequests: 0,\n\t\t\ttotalErrors: 0,\n\t\t\tminDuration: -1,\n\t\t\tmaxDuration: -1,\n\t\t\ttotalDuration: 0,\n\t\t\tmaxRequestsPerSecond: 0,\n\t\t\tmemory: {\n\t\t\t\theapUsedMax: 0,\n\t\t\t\theapTotalMax: 0,\n\t\t\t\trssMax: 0,\n\t\t\t\texternalMax: 0,\n\t\t\t},\n\t\t\tcpu: {\n\t\t\t\tmax: 0,\n\t\t\t\tuserMax: 0,\n\t\t\t\tsystemMax: 0,\n\t\t\t},\n\t\t};\n\n\t\tthis._currentBucket = {\n\t\t\tcount: 0,\n\t\t\terrors: 0,\n\t\t\tdurations: [],\n\t\t\tdurationSum: 0,\n\t\t\tdurationMin: -1,\n\t\t\tdurationMax: -1,\n\t\t};\n\n\t\tthis._lastCpuTimes = this._getSystemCpuTimes();\n\n\t\tthis._timer = undefined;\n\t\tif (this.config.sampleSystem) {\n\t\t\tthis._timer = setInterval(() => {\n\t\t\t\tthis.rotateBucket();\n\t\t\t}, this.config.intervalMs);\n\t\t\tif (this._timer && typeof this._timer.unref === 'function') {\n\t\t\t\tthis._timer.unref();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Reset the current bucket accumulator.\n\t */\n\tprivate _resetBucket(): void {\n\t\tthis._currentBucket = {\n\t\t\tcount: 0,\n\t\t\terrors: 0,\n\t\t\tdurations: [],\n\t\t\tdurationSum: 0,\n\t\t\tdurationMin: -1,\n\t\t\tdurationMax: -1,\n\t\t};\n\t}\n\n\t/**\n\t * Record a request event.\n\t * @param duration - Duration in milliseconds.\n\t * @param isError - Whether the request was an error.\n\t */\n\trecordRequest(duration: number, isError = false): void {\n\t\tthis.lifetime.totalRequests++;\n\t\tif (isError) {\n\t\t\tthis.lifetime.totalErrors++;\n\t\t}\n\n\t\tthis.lifetime.totalDuration += duration;\n\t\tif (this.lifetime.minDuration < 0 || duration < this.lifetime.minDuration) {\n\t\t\tthis.lifetime.minDuration = duration;\n\t\t}\n\t\tif (this.lifetime.maxDuration < 0 || duration > this.lifetime.maxDuration) {\n\t\t\tthis.lifetime.maxDuration = duration;\n\t\t}\n\n\t\tconst b = this._currentBucket;\n\t\tb.count++;\n\t\tif (isError) {\n\t\t\tb.errors++;\n\t\t}\n\n\t\tb.durationSum += duration;\n\t\tif (b.durationMin < 0 || duration < b.durationMin) {\n\t\t\tb.durationMin = duration;\n\t\t}\n\t\tif (b.durationMax < 0 || duration > b.durationMax) {\n\t\t\tb.durationMax = duration;\n\t\t}\n\n\t\tif (b.durations.length < this.config.percentilePrecision) {\n\t\t\tb.durations.push(duration);\n\t\t}\n\t}\n\n\t/**\n\t * Get system CPU times.\n\t * @returns System CPU times.\n\t */\n\tprivate _getSystemCpuTimes(): {user: number; nice: number; sys: number; idle: number; irq: number; total: number} {\n\t\tconst cpus = os.cpus();\n\t\tlet user = 0;\n\t\tlet nice = 0;\n\t\tlet sys = 0;\n\t\tlet idle = 0;\n\t\tlet irq = 0;\n\n\t\tfor (const cpu of cpus) {\n\t\t\tuser += cpu.times.user;\n\t\t\tnice += cpu.times.nice;\n\t\t\tsys += cpu.times.sys;\n\t\t\tidle += cpu.times.idle;\n\t\t\tirq += cpu.times.irq;\n\t\t}\n\n\t\tconst total = user + nice + sys + idle + irq;\n\t\treturn {user, nice, sys, idle, irq, total};\n\t}\n\n\t/**\n\t * Calculate CPU usage percentage since last call.\n\t * @returns CPU usage percentage (0-100).\n\t */\n\tprivate _calculateCpuUsage(): number {\n\t\tconst current = this._getSystemCpuTimes();\n\t\tconst last = this._lastCpuTimes || {user: 0, nice: 0, sys: 0, idle: 0, irq: 0, total: 0};\n\n\t\tconst deltaTotal = current.total - last.total;\n\t\tconst deltaIdle = current.idle - last.idle;\n\n\t\tthis._lastCpuTimes = current;\n\n\t\tif (deltaTotal <= 0) return 0;\n\n\t\tconst percent = ((deltaTotal - deltaIdle) / deltaTotal) * 100;\n\t\treturn Math.min(100, Math.max(0, percent));\n\t}\n\n\t/**\n\t * Rotate the current bucket into history and start a new one.\n\t * @param poolSnapshots - Optional pool snapshots to include.\n\t */\n\trotateBucket(poolSnapshots: PoolSnapshot[] = []): void {\n\t\tconst b = this._currentBucket;\n\t\tconst memUsage = process.memoryUsage();\n\t\tconst systemMemoryUsed = os.totalmem() - os.freemem();\n\t\tconst cpuUsage = process.cpuUsage();\n\t\tconst cpu = this._calculateCpuUsage();\n\n\t\t// Update lifetime extremes\n\t\tconst reqPerSec = b.count / (this.config.intervalMs / 1000);\n\t\tthis.lifetime.maxRequestsPerSecond = Math.max(this.lifetime.maxRequestsPerSecond, reqPerSec);\n\t\tthis.lifetime.memory.heapUsedMax = Math.max(this.lifetime.memory.heapUsedMax, memUsage.heapUsed);\n\t\tthis.lifetime.memory.heapTotalMax = Math.max(this.lifetime.memory.heapTotalMax, memUsage.heapTotal);\n\t\tthis.lifetime.memory.rssMax = Math.max(this.lifetime.memory.rssMax, systemMemoryUsed);\n\t\tthis.lifetime.memory.externalMax = Math.max(this.lifetime.memory.externalMax, memUsage.external);\n\t\tthis.lifetime.cpu.max = Math.max(this.lifetime.cpu.max, cpu);\n\t\tthis.lifetime.cpu.userMax = Math.max(this.lifetime.cpu.userMax, cpuUsage.user);\n\t\tthis.lifetime.cpu.systemMax = Math.max(this.lifetime.cpu.systemMax, cpuUsage.system);\n\n\t\tlet p95 = 0;\n\t\tlet p99 = 0;\n\t\tif (b.durations.length > 0) {\n\t\t\tconst sorted = b.durations.toSorted((x, y) => x - y);\n\t\t\tconst p95Idx = Math.floor(sorted.length * 0.95);\n\t\t\tconst p99Idx = Math.floor(sorted.length * 0.99);\n\t\t\tconst lastIdx = sorted.length - 1;\n\n\t\t\tp95 = sorted[p95Idx] ?? sorted[lastIdx] ?? 0;\n\t\t\tp99 = sorted[p99Idx] ?? sorted[lastIdx] ?? 0;\n\t\t}\n\n\t\tconst bucket: Bucket = {\n\t\t\ttimestamp: Date.now(),\n\t\t\trequests: b.count,\n\t\t\terrors: b.errors,\n\t\t\tdurationMin: Math.max(b.durationMin, 0),\n\t\t\tdurationMax: Math.max(b.durationMax, 0),\n\t\t\tdurationAvg: b.count > 0 ? b.durationSum / b.count : 0,\n\t\t\tdurationP95: p95,\n\t\t\tdurationP99: p99,\n\t\t\tsystem: {\n\t\t\t\tcpu,\n\t\t\t\theapUsed: memUsage.heapUsed,\n\t\t\t\theapTotal: memUsage.heapTotal,\n\t\t\t\trss: systemMemoryUsed,\n\t\t\t\texternal: memUsage.external,\n\t\t\t},\n\t\t\tpools: poolSnapshots,\n\t\t};\n\n\t\tthis.history.push(bucket);\n\t\tif (this.history.length > this.config.maxHistoryPoints) {\n\t\t\tthis.history.shift();\n\t\t}\n\n\t\tthis._resetBucket();\n\t\tdebug('Bucket rotated: %j', bucket);\n\t}\n\n\t/**\n\t * Stop the background timer.\n\t */\n\tstop(): void {\n\t\tif (this._timer) {\n\t\t\tclearInterval(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Get lifetime summary.\n\t * @returns Summary.\n\t */\n\tgetSummary(): StatsSummary {\n\t\treturn {\n\t\t\tstartTime: this.startTime,\n\t\t\ttotalRequests: this.lifetime.totalRequests,\n\t\t\ttotalErrors: this.lifetime.totalErrors,\n\t\t\tavgResponseTime: this.lifetime.totalRequests > 0 ? this.lifetime.totalDuration / this.lifetime.totalRequests : 0,\n\t\t\tminResponseTime: this.lifetime.minDuration,\n\t\t\tmaxResponseTime: this.lifetime.maxDuration,\n\t\t\tmaxRequestsPerSecond: this.lifetime.maxRequestsPerSecond,\n\t\t\tmaxMemory: this.lifetime.memory,\n\t\t\tcpu: this.lifetime.cpu,\n\t\t};\n\t}\n\n\t/**\n\t * Get history buffer.\n\t * @returns The history buffer.\n\t */\n\tgetHistory(): Bucket[] {\n\t\treturn this.history;\n\t}\n}","import {StatsManager} from '../util/statsManager.ts';\nimport type {Pool} from 'oracledb';\nimport type {configType, argsType} from '../types.ts';\nimport type {Cache} from '../util/cache.ts';\n\ntype PoolCacheEntry = {\n\tpoolName: string;\n\tprocedureNameCache: Cache<string>;\n\targumentCache: Cache<argsType>;\n};\n\n/**\n * Admin Context Class\n */\nexport class AdminContext {\n\treadonly startTime: Date;\n\treadonly config: configType;\n\treadonly pools: Pool[];\n\treadonly caches: PoolCacheEntry[];\n\treadonly statsManager: StatsManager;\n\tprivate _paused: boolean;\n\n\tconstructor(config: configType) {\n\t\tthis.startTime = new Date();\n\t\tthis.config = config;\n\t\tthis.pools = [];\n\t\tthis.caches = [];\n\t\tthis.statsManager = new StatsManager();\n\t\tthis._paused = false;\n\t}\n\n\t/**\n\t * Register a PL/SQL handler with the admin context.\n\t * @param route - The route for the handler.\n\t * @param pool - The connection pool.\n\t * @param procedureNameCache - The procedure name cache.\n\t * @param argumentCache - The argument cache.\n\t */\n\tregisterHandler(route: string, pool: Pool, procedureNameCache: Cache<string>, argumentCache: Cache<argsType>): void {\n\t\tthis.pools.push(pool);\n\t\tthis.caches.push({\n\t\t\tpoolName: route,\n\t\t\tprocedureNameCache,\n\t\t\targumentCache,\n\t\t});\n\t}\n\n\tget paused(): boolean {\n\t\treturn this._paused;\n\t}\n\n\tsetPaused(value: boolean): void {\n\t\tthis._paused = value;\n\t}\n}","import {promises as fs, readFileSync} from 'node:fs';\n\n/**\n * Read file.\n *\n * @param filePath - File name.\n * @returns The string.\n */\nexport const readFileSyncUtf8 = (filePath: string): string => {\n\ttry {\n\t\treturn readFileSync(filePath, 'utf8');\n\t} catch {\n\t\tthrow new Error(`Unable to read file \"${filePath}\"`);\n\t}\n};\n\n/**\n * Read file.\n *\n * @param filePath - File name.\n * @returns The buffer.\n */\nexport const readFile = async (filePath: string): Promise<Buffer> => {\n\ttry {\n\t\treturn await fs.readFile(filePath);\n\t} catch {\n\t\tthrow new Error(`Unable to read file \"${filePath}\"`);\n\t}\n};\n\n/**\n * Remove file.\n *\n * @param filePath - File name.\n */\nexport const removeFile = async (filePath: string): Promise<void> => {\n\ttry {\n\t\tawait fs.unlink(filePath);\n\t} catch {\n\t\tthrow new Error(`Unable to remove file \"${filePath}\"`);\n\t}\n};\n\n/**\n * Load a json file.\n *\n * @param filePath - File name.\n * @returns The json object.\n */\nexport const getJsonFile = (filePath: string): unknown => {\n\ttry {\n\t\tconst fileContent = readFileSync(filePath, 'utf8');\n\t\treturn JSON.parse(fileContent);\n\t} catch {\n\t\tthrow new Error(`Unable to load file \"${filePath}\"`);\n\t}\n};\n\n/**\n * Is this a directory.\n * @param directoryPath - Directory name.\n * @returns Return true if it is a directory.\n */\nexport const isDirectory = async (directoryPath: unknown): Promise<boolean> => {\n\tif (typeof directoryPath !== 'string') {\n\t\treturn false;\n\t}\n\n\tconst stats = await fs.stat(directoryPath);\n\n\treturn stats.isDirectory();\n};\n\n/**\n * Is this a file.\n * @param filePath - File name.\n * @returns Return true if it is a file.\n */\nexport const isFile = async (filePath: unknown): Promise<boolean> => {\n\tif (typeof filePath !== 'string') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst stats = await fs.stat(filePath);\n\t\treturn stats.isFile();\n\t} catch {\n\t\treturn false;\n\t}\n};","/*\n *\tHtml utilities\n */\n\n/**\n * Escape html string.\n *\n * @param value - The value.\n * @returns The escaped value.\n */\nexport const escapeHtml = (value: string): string =>\n\tvalue.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('\"', '"').replaceAll(\"'\", ''');\n\n/**\n *\tConvert LF and/or CR to <br>\n *\t@param text - The text to convert.\n *\t@returns The converted text.\n */\nexport const convertAsciiToHtml = (text: string): string => {\n\tlet html = escapeHtml(text);\n\n\thtml = html.replaceAll(/\\r\\n|\\r|\\n/gu, '<br />');\n\thtml = html.replaceAll('\\t', ' ');\n\n\treturn html;\n};\n\n/**\n *\tget a minimal html page.\n *\t@param body - The body.\n *\t@returns The html page.\n */\nexport const getHtmlPage = (body: string): string => `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>web_plsql error page</title>\n<style type=\"text/css\">\nhtml {\n\tfont-family: monospace, sans-serif;\n\tfont-size: 12px;\n}\nh1 {\n\tfont-size: 16px;\n\tpadding: 2px;\n\tbackground-color: #cc0000;\n}\n</style>\n</head>\n<body>\n${body}\n</body>\n</html>\n`;","/*\n *\tTrace utilities\n */\n\nimport * as rotatingFileStream from 'rotating-file-stream';\nimport type {Request} from 'express';\nimport util from 'node:util';\nimport oracledb from 'oracledb';\nimport {escapeHtml, convertAsciiToHtml} from './html.ts';\nimport {errorToString} from './errorToString.ts';\nimport {TRACE_LOG_ROTATION_SIZE, TRACE_LOG_ROTATION_INTERVAL, TRACE_LOG_MAX_ROTATED_FILES} from '../../common/constants.ts';\nimport type {environmentType} from '../types.ts';\nimport type {BindParameter, BindParameters} from 'oracledb';\n\n/**\n * Type guard for BindParameter\n * @param row - The row to check\n * @returns True if row is a BindParameter\n */\nconst isBindParameter = (row: unknown): row is BindParameter => {\n\tif (typeof row !== 'object' || row === null) {\n\t\treturn false;\n\t}\n\treturn 'dir' in row || 'type' in row || 'val' in row || 'maxSize' in row || 'maxArraySize' in row;\n};\n\ntype outputType = {\n\thtml: string;\n\ttext: string;\n};\n\nexport type messageType = {\n\ttype: 'error' | 'warning' | 'trace';\n\tmessage: string;\n\ttimestamp?: Date | null;\n\treq?: Request | null;\n\tenvironment?: environmentType | null;\n\tsql?: string | null;\n\tbind?: BindParameters | null;\n};\n\nconst SEPARATOR_H1 = '='.repeat(100);\nconst SEPARATOR_H2 = '-'.repeat(30);\n\n/**\n * Return a string representation of the value.\n *\n * @param value - Any value.\n * @param depth - Specifies the number of times to recurse while formatting object.\n * @returns The string representation.\n */\nexport const inspect = (value: unknown, depth: number | null = null): string => {\n\ttry {\n\t\treturn util.inspect(value, {showHidden: false, depth, colors: false});\n\t} catch {\n\t\t/* empty */\n\t}\n\n\ttry {\n\t\treturn JSON.stringify(value);\n\t} catch {\n\t\t/* empty */\n\t}\n\n\treturn 'Unable to convert value to string';\n};\n\n// Build text representation\n/**\n *\t@param cell - The string\n *\t@param width - The width\n *\t@returns The result\n */\nconst padCell = (cell: string, width: number) => cell.padEnd(width, ' ');\n\n/**\n * Return a tabular representation of the values.\n *\n * @param head - The header values.\n * @param body - The row values.\n * @returns The output.\n */\nexport const toTable = (head: string[], body: string[][]): outputType => {\n\tif (head.length === 0) {\n\t\tthrow new Error('head cannot be empty');\n\t}\n\n\t// Calculate column widths\n\tconst widths = head.map((h, i) => {\n\t\tconst bodyMax = Math.max(0, ...body.map((row) => (row[i] ?? '').length));\n\t\treturn Math.max(h.length, bodyMax);\n\t});\n\n\t/**\n\t *\t@param i - The index\n\t *\t@returns The width\n\t */\n\tconst getWidth = (i: number): number => widths[i] ?? 0;\n\tconst textHeader = head.map((h, i) => padCell(h, getWidth(i))).join(' | ');\n\tconst textSeparator = widths.map((w) => '-'.repeat(w ?? 0)).join('-+-');\n\tconst textRows = body.map((row) => head.map((_, i) => padCell(row[i] ?? '', getWidth(i))).join(' | '));\n\tconst text = [textHeader, textSeparator, ...textRows].join('\\n');\n\n\tconst htmlHead = head.map((h) => `<th>${escapeHtml(h)}</th>`).join('');\n\tconst htmlBody = body.map((row) => `<tr>${head.map((_, i) => `<td>${escapeHtml(row[i] ?? '')}</td>`).join('')}</tr>`).join('');\n\tconst html = `<table><thead><tr>${htmlHead}</tr></thead><tbody>${htmlBody}</tbody></table>`;\n\n\treturn {text, html};\n};\n\n/**\n * Log text to the console and to a file.\n *\n * @param text - Text to log.\n */\nexport const logToFile = (text: string): void => {\n\tconst fs = rotatingFileStream.createStream('trace.log', {\n\t\tsize: TRACE_LOG_ROTATION_SIZE, // rotate every 10 MegaBytes written\n\t\tinterval: TRACE_LOG_ROTATION_INTERVAL, // rotate daily\n\t\tmaxFiles: TRACE_LOG_MAX_ROTATED_FILES, // maximum number of rotated files to keep\n\t\tcompress: 'gzip', // compress rotated files\n\t});\n\n\tfs.write(text);\n\tfs.end();\n};\n\n/**\n * Return a string representation of the request.\n *\n * @param req - express.Request.\n * @returns The string representation.\n */\nconst inspectRequest = (req: Request): string => {\n\tconst requestData: Record<string, unknown> = {};\n\n\tObject.keys(req)\n\t\t.filter((prop) => ['originalUrl', 'params', 'query', 'url', 'method', 'body', 'files', 'secret', 'cookies'].includes(prop))\n\t\t.forEach((prop) => {\n\t\t\trequestData[prop] = req[prop as keyof Request];\n\t\t});\n\n\treturn inspect(requestData);\n};\n\n/**\n *\tReturn a string representation of the bind parameter.\n *\t@param dir - The direction.\n *\t@returns The string.\n */\nconst dirToString = (dir: number | undefined): string => {\n\tswitch (dir) {\n\t\tcase oracledb.BIND_IN:\n\t\t\treturn 'IN';\n\t\tcase oracledb.BIND_OUT:\n\t\t\treturn 'OUT';\n\t\tcase oracledb.BIND_INOUT:\n\t\t\treturn 'INOUT';\n\t\tdefault:\n\t\t\treturn '';\n\t}\n};\n\n/**\n *\tReturn a string representation of the bind type.\n *\t@param type - The type.\n *\t@returns The string.\n */\nconst bindTypeToString = (type: unknown): string => {\n\tif (typeof type === 'object' && type !== null && 'name' in type) {\n\t\treturn (type as {name: string}).name;\n\t}\n\n\tif (typeof type === 'string') {\n\t\treturn type;\n\t}\n\n\tif (typeof type === 'number') {\n\t\treturn type.toString();\n\t}\n\n\treturn '';\n};\n\n/**\n *\tReturn a string representation of the bind parameter.\n *\t@param output - The output.\n *\t@param bind - The bind parameters.\n */\nconst inspectBindParameter = (output: outputType, bind: BindParameters): void => {\n\tconst rows = Object.entries(bind);\n\n\tif (rows.length === 0) {\n\t\treturn;\n\t}\n\n\tconst body = rows.map(([id, row]) => {\n\t\tlet dir = '';\n\t\tlet maxArraySize = '';\n\t\tlet maxSize = '';\n\t\tlet bindType = '';\n\t\tlet value = '';\n\t\tlet valueType = '';\n\n\t\tif (isBindParameter(row)) {\n\t\t\tdir = dirToString(row.dir);\n\t\t\tmaxArraySize = row.maxArraySize ? row.maxArraySize.toString() : '';\n\t\t\tmaxSize = row.maxSize ? row.maxSize.toString() : '';\n\t\t\tbindType = bindTypeToString(row.type);\n\t\t\tvalue = inspect(row.val);\n\t\t\tvalueType = typeof row.val;\n\t\t} else {\n\t\t\tvalue = inspect(row);\n\t\t\tvalueType = typeof row;\n\t\t}\n\n\t\treturn [id, dir, maxArraySize, maxSize, bindType, value, valueType];\n\t});\n\n\tconst {html, text} = toTable(['id', 'dir', 'maxArraySize', 'maxSize', 'bind type', 'value', 'value type'], body);\n\n\toutput.html += html;\n\toutput.text += text;\n};\n\n/**\n * Add environment\n *\t@param output - The output.\n *\t@param environment - The environment.\n */\nconst inspectEnvironment = (output: outputType, environment: environmentType): void => {\n\tconst rows = Object.entries(environment);\n\n\tif (rows.length === 0) {\n\t\treturn;\n\t}\n\n\tconst {html, text} = toTable(['key', 'value'], rows);\n\n\toutput.html += html;\n\toutput.text += text;\n};\n\n/**\n *\tGet a block.\n *\t@param title - The name.\n *\t@param body - The name.\n *\t@returns The text.\n */\nexport const getBlock = (title: string, body: string): string => `\\n${SEPARATOR_H2}${title.toUpperCase()}${SEPARATOR_H2}\\n${body}`;\n\n/**\n *\tGet line html\n *\t@param text - The text.\n *\t@returns The line.\n */\nconst getLineHtml = (text: string): string => `<p>${convertAsciiToHtml(text)}</p>`;\n\n/**\n *\tGet line text\n *\t@param text - The text.\n *\t@returns The line.\n */\nconst getLineText = (text: string): string => `${text}\\n`;\n\n/**\n *\tAdd line\n *\t@param output - The output.\n *\t@param text - The text to convert.\n */\nconst addLine = (output: outputType, text: string): void => {\n\toutput.html += getLineHtml(text);\n\toutput.text += getLineText(text);\n};\n\n/**\n *\tAdd header\n *\t@param output - The output.\n *\t@param text - The text to convert.\n */\nconst addHeader = (output: outputType, text: string): void => {\n\toutput.html += `<h2>${text}</h2>`;\n\toutput.text += `\\n${text}\\n${'-'.repeat(text.length)}\\n`;\n};\n\n/**\n *\tAdd procedure\n *\t@param output - The output.\n *\t@param sql - The SQL to execute.\n *\t@param bind - The bind parameters.\n */\nconst addProcedure = (output: outputType, sql: string, bind: BindParameters): void => {\n\toutput.html += `${sql}<br><br>`;\n\toutput.text += `${sql}\\n\\n`;\n\n\ttry {\n\t\tinspectBindParameter(output, bind);\n\t} catch (err) {\n\t\taddLine(output, `Unable to inspect bind parameter: ${errorToString(err)}`);\n\t}\n\n\toutput.html += `<br>`;\n\toutput.text += `\\n`;\n};\n\n/**\n *\tGet a formatted message.\n *\t@param para - The req object represents the HTTP request.\n *\t@returns The output.\n */\nexport const getFormattedMessage = (para: messageType): outputType => {\n\tconst timestamp = para.timestamp ?? new Date();\n\n\t// header\n\tconst url = typeof para.req?.originalUrl === 'string' && para.req.originalUrl.length > 0 ? ` on ${para.req.originalUrl}` : '';\n\tconst type = (para.type ?? 'trace').toUpperCase();\n\tconst header = `${type} at ${timestamp.toUTCString()}${url}`;\n\tconst output: outputType = {\n\t\thtml: `<h1>${header}</h1>`,\n\t\ttext: `\\n\\n${SEPARATOR_H1}\\n== ${header}\\n${SEPARATOR_H1}\\n`,\n\t};\n\n\t// error\n\taddHeader(output, 'ERROR');\n\taddLine(output, para.message);\n\n\t// request\n\tif (para.req) {\n\t\taddHeader(output, 'REQUEST');\n\t\taddLine(output, inspectRequest(para.req));\n\t}\n\n\t// parameters\n\tif (para.sql && para.bind) {\n\t\taddHeader(output, 'PROCEDURE');\n\t\taddProcedure(output, para.sql, para.bind);\n\t}\n\n\t// environment\n\tif (para.environment) {\n\t\taddHeader(output, 'ENVIRONMENT');\n\t\tinspectEnvironment(output, para.environment);\n\t}\n\n\treturn output;\n};\n\n/**\n *\tLog a warning message.\n *\t@param para - The req object represents the HTTP request.\n */\nexport const warningMessage = (para: messageType): void => {\n\tconst {text} = getFormattedMessage(para);\n\n\t// trace to file\n\tlogToFile(text);\n\n\t// console\n\tconsole.warn(text);\n};","import {inspect} from './trace.ts';\n\n/**\n * Convert Error to a string.\n *\n * @param error - The error.\n * @returns The string representation.\n */\nexport const errorToString = (error: unknown): string => {\n\tif (typeof error === 'string') {\n\t\treturn error;\n\t} else if (error instanceof Error) {\n\t\tconst parts = [error.name];\n\t\tif (typeof error.message === 'string' && error.message.length > 0) {\n\t\t\tparts.push(error.message);\n\t\t}\n\t\tif (typeof error.stack === 'string' && error.stack.length > 0) {\n\t\t\tparts.push(error.stack);\n\t\t}\n\t\treturn parts.join('\\n');\n\t} else {\n\t\treturn inspect(error);\n\t}\n};","/*\n *\tProcess file uploads\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:fileUpload');\n\nimport {BUFFER} from '../../util/oracledb-provider.ts';\nimport {readFile, removeFile} from '../../util/file.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport type {Connection} from 'oracledb';\nimport z from 'zod';\nimport type {Request} from 'express';\nimport type {fileUploadType} from '../../types.ts';\n\nconst z$reqFiles = z.array(\n\tz.strictObject({\n\t\tfieldname: z.string(),\n\t\toriginalname: z.string(),\n\t\tencoding: z.string(),\n\t\tmimetype: z.string(),\n\t\tdestination: z.string(),\n\t\tfilename: z.string(),\n\t\tpath: z.string(),\n\t\tsize: z.number(),\n\t}),\n);\n\n/**\n * Get the files\n *\n * @param req - The req object represents the HTTP request.\n * @returns Promise that resolves with an array of files to be uploaded.\n */\nexport const getFiles = (req: Request): fileUploadType[] => {\n\tif (!('files' in req)) {\n\t\tdebug('getFiles: no files');\n\t\treturn [];\n\t}\n\n\tif (typeof req.files === 'object' && req.files !== null && Object.keys(req.files as object).length === 0) {\n\t\tdebug('getFiles: no files');\n\t\treturn [];\n\t}\n\n\tconst files = z$reqFiles.parse(req.files) as fileUploadType[];\n\n\tfor (const file of files) {\n\t\tfile.filename += `/${file.originalname}`;\n\t}\n\n\tdebug('getFiles', files);\n\n\treturn files;\n};\n\n/**\n * Upload the given file and return a promise.\n *\n * @param file - The file to upload.\n * @param doctable - The file to upload.\n * @param databaseConnection - The file to upload.\n * @returns Promise that resolves when uploaded.\n */\nexport const uploadFile = async (file: fileUploadType, doctable: string, databaseConnection: Connection): Promise<void> => {\n\tdebug(`uploadFile`, file, doctable);\n\n\t/* v8 ignore next - defensive validation */\n\tif (typeof doctable !== 'string' || doctable.length === 0) {\n\t\tthrow new Error(`Unable to upload file \"${file.filename}\" because the option \"\"doctable\" has not been defined`);\n\t}\n\n\t// read file\n\tlet blobContent;\n\ttry {\n\t\tblobContent = await readFile(file.path);\n\t} catch (err) {\n\t\tthrow new Error(`Unable to load file \"${file.path}\".\\n${errorToString(err)}`);\n\t}\n\n\t// insert file in document table\n\tconst sql = `INSERT INTO ${doctable} (name, mime_type, doc_size, dad_charset, last_updated, content_type, blob_content) VALUES (:name, :mime_type, :doc_size, 'ascii', SYSDATE, 'BLOB', :blob_content)`;\n\tconst bind = {\n\t\tname: file.filename,\n\t\tmime_type: file.mimetype,\n\t\tdoc_size: file.size,\n\t\tblob_content: {\n\t\t\tval: blobContent,\n\t\t\ttype: BUFFER,\n\t\t},\n\t};\n\ttry {\n\t\tawait databaseConnection.execute(sql, bind, {autoCommit: true});\n\t} catch (err) {\n\t\tthrow new Error(`Unable to insert file \"${file.filename}\".\\n${errorToString(err)}`);\n\t}\n\n\t// remove the file\n\ttry {\n\t\tawait removeFile(file.path);\n\t} catch (err) {\n\t\tthrow new Error(`Unable to remove file \"${file.filename}\".\\n${errorToString(err)}`);\n\t}\n};","/*\n *\tInvoke the Oracle procedure and return the raw content of the page\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:procedureVariable');\n\nimport {BIND_IN, STRING} from '../../util/oracledb-provider.ts';\nimport type {Request} from 'express';\nimport type {argObjType} from '../../types.ts';\nimport type {BindParameters} from 'oracledb';\n\n/**\n *\tGet the sql statement and bindings for the procedure to execute for a variable number of arguments\n *\t@param _req - The req object represents the HTTP request. (only used for debugging)\n *\t@param procName - The procedure to execute\n *\t@param argObj - The arguments to pass to the procedure\n *\t@returns The SQL statement and bindings for the procedure to execute\n */\nexport const getProcedureVariable = (_req: Request, procName: string, argObj: argObjType): {sql: string; bind: BindParameters} => {\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tdebug(`getProcedureVariable: ${procName} arguments=`, argObj);\n\t}\n\t/* v8 ignore stop */\n\n\tconst names: string[] = [];\n\tconst values: string[] = [];\n\n\tfor (const key in argObj) {\n\t\tconst value = argObj[key];\n\t\tif (typeof value === 'string') {\n\t\t\tnames.push(key);\n\t\t\tvalues.push(value);\n\t\t} else if (Array.isArray(value)) {\n\t\t\tvalue.forEach((item) => {\n\t\t\t\tnames.push(key);\n\t\t\t\tvalues.push(item);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn {\n\t\tsql: `${procName}(:argnames, :argvalues)`,\n\t\tbind: {\n\t\t\targnames: {dir: BIND_IN, type: STRING, val: names},\n\t\t\targvalues: {dir: BIND_IN, type: STRING, val: values},\n\t\t},\n\t};\n};","/*\n *\tRequestError\n */\n\nexport class RequestError extends Error {\n\ttimestamp: Date;\n\n\t/**\n\t * @param message - The error message.\n\t */\n\tconstructor(message: string) {\n\t\tsuper(message);\n\n\t\t// Maintains proper stack trace for where our error was thrown (only available on V8)\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, RequestError);\n\t\t}\n\n\t\t// Custom debugging information\n\t\tthis.timestamp = new Date();\n\t}\n}","/**\n * Get duration as human readable string.\n * @param duration - Milliseconds.\n * @returns String.\n */\nexport const humanDuration = (duration: number): string => {\n\tif (!Number.isFinite(duration)) return 'invalid';\n\n\tconst ms = Math.floor(duration % 1000);\n\tconst s = Math.floor((duration / 1000) % 60);\n\tconst m = Math.floor((duration / (1000 * 60)) % 60);\n\tconst h = Math.floor((duration / (1000 * 60 * 60)) % 24);\n\tconst d = Math.floor(duration / (1000 * 60 * 60 * 24));\n\n\tconst parts = [];\n\tif (d) parts.push(`${d}d`);\n\tif (h) parts.push(`${h}h`);\n\tif (m) parts.push(`${m}m`);\n\tif (s) parts.push(`${s}s`);\n\tif (ms || parts.length === 0) parts.push(`${ms}ms`);\n\n\treturn parts.join(' ');\n};\n\n/**\n * Convert a string to a number\n *\n * @param value - The string to convert\n * @returns The number or null if the string could not be converted\n */\nexport const stringToNumber = (value: unknown): number | null => {\n\t// is the value already of type number?\n\tif (typeof value === 'number') {\n\t\treturn !Number.isNaN(value) && Number.isFinite(value) ? value : null;\n\t}\n\n\t// Test for invalid characters\n\t// oxlint-disable-next-line unicorn/better-regex\n\tif (typeof value !== 'string' || !/^[+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:E[+-]?\\d+)?$/iu.test(value)) {\n\t\treturn null;\n\t}\n\n\t// Convert value to a number\n\treturn Number(value);\n};\n\n/**\n * Convert a string to a integer\n *\n * @param value - The value to convert\n * @returns The integer or null if the string could not be converted\n */\nexport const stringToInteger = (value: unknown): number | null => {\n\t// is the value already a \"real\" integer, we just return the value\n\tif (typeof value === 'number' && Number.isInteger(value)) {\n\t\treturn value;\n\t}\n\n\t// try to convert value to a number\n\tconst num = stringToNumber(value);\n\tif (num === null || !Number.isInteger(num)) {\n\t\treturn null;\n\t}\n\n\treturn num;\n};\n\n/**\n * Centers text within a fixed width by padding both sides with spaces.\n * If padding is odd, the extra space goes to the right.\n *\n * @param text - The string to center\n * @param width - Total output width in characters\n * @returns Padded string of exactly `width` characters\n * @throws {RangeError} If `width` is less than `text.length`\n */\nexport const centerText = (text: string, width: number, padding = ' '): string => {\n\tif (width < text.length) {\n\t\tthrow new RangeError(`width (${width}) < text.length (${text.length})`);\n\t}\n\n\tconst total = width - text.length;\n\tconst left = Math.floor(total / 2);\n\tconst right = total - left;\n\n\treturn padding.repeat(left) + text + padding.repeat(right);\n};","/*\n *\tInvoke the Oracle procedure and return the raw content of the page\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:procedureNamed');\n\nimport {BIND_IN, BIND_OUT, STRING, DB_TYPE_VARCHAR, DB_TYPE_CLOB, DB_TYPE_NUMBER, DB_TYPE_DATE} from '../../util/oracledb-provider.ts';\nimport z from 'zod';\nimport {RequestError} from './requestError.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {stringToNumber} from '../../util/util.ts';\nimport {toTable, warningMessage, inspect} from '../../util/trace.ts';\nimport {MAX_PROCEDURE_PARAMETERS} from '../../../common/constants.ts';\nimport type {Request} from 'express';\nimport type {Connection, Result, BindParameter, BindParameters} from 'oracledb';\nimport type {argObjType, argsType, ArgumentCache} from '../../types.ts';\n\nconst SQL_GET_ARGUMENT = [\n\t'DECLARE',\n\t'\tschemaName\t\tVARCHAR2(32767);',\n\t'\tpart1\t\t\tVARCHAR2(32767);',\n\t'\tpart2\t\t\tVARCHAR2(32767);',\n\t'\tdblink\t\t\tVARCHAR2(32767);',\n\t'\tobjectType\t\tNUMBER;',\n\t'\tobjectID\t\tNUMBER;',\n\t'BEGIN',\n\t'\tdbms_utility.name_resolve(name=>UPPER(:name), context=>1, schema=>schemaName, part1=>part1, part2=>part2, dblink=>dblink, part1_type=>objectType, object_number=>objectID);',\n\t'\tIF (part1 IS NOT NULL) THEN',\n\t'\t\tSELECT argument_name, data_type BULK COLLECT INTO :names, :types FROM all_arguments WHERE owner = schemaName AND package_name = part1 AND object_name = part2 AND argument_name IS NOT NULL ORDER BY overload, sequence;',\n\t'\tELSE',\n\t'\t\tSELECT argument_name, data_type BULK COLLECT INTO :names, :types FROM all_arguments WHERE owner = schemaName AND package_name IS NULL AND object_name = part2 AND argument_name IS NOT NULL ORDER BY overload, sequence;',\n\t'\tEND IF;',\n\t'END;',\n].join('\\n');\n\nconst DATA_TYPES = Object.freeze({\n\tVARCHAR2: 'VARCHAR2',\n\tCHAR: 'CHAR',\n\tBINARY_INTEGER: 'BINARY_INTEGER',\n\tNUMBER: 'NUMBER',\n\tDATE: 'DATE',\n\tCLOB: 'CLOB',\n\tPL_SQL_TABLE: 'PL/SQL TABLE',\n\t//\tPL/SQL BOOLEAN\n\t//\tPL/SQL RECORD\n\t//\tOBJECT\n\t//\tTABLE\n\t//\tBLOB\n\t//\tRAW\n\t//\tVARRAY\n\t//\tREF CURSOR\n});\n\n/**\n *\tRetrieve the argument types for a given procedure to be executed.\n *\tThis is important because if the procedure is defined to take a PL/SQL indexed table,\n *\twe must provise a table, even if there is only one argument to be submitted.\n *\t@param procedure - The procedure\n *\t@param databaseConnection - The database connection\n *\t@returns The argument types\n */\nconst loadArguments = async (procedure: string, databaseConnection: Connection): Promise<argsType> => {\n\tconst bind: BindParameters = {\n\t\tname: {dir: BIND_IN, type: STRING, val: procedure},\n\t\tnames: {dir: BIND_OUT, type: STRING, maxSize: 60, maxArraySize: MAX_PROCEDURE_PARAMETERS},\n\t\ttypes: {dir: BIND_OUT, type: STRING, maxSize: 60, maxArraySize: MAX_PROCEDURE_PARAMETERS},\n\t};\n\n\tlet result: Result<unknown> = {};\n\ttry {\n\t\tresult = await databaseConnection.execute(SQL_GET_ARGUMENT, bind);\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug('result', result);\n\t\t/* v8 ignore stop */\n\n\t\tconst message = `Error when retrieving arguments\\n${SQL_GET_ARGUMENT}\\n${errorToString(err)}`;\n\t\tthrow new RequestError(message);\n\t}\n\n\tlet data: {names: (string | null)[]; types: (string | null)[]};\n\ttry {\n\t\tdata = z\n\t\t\t.object({\n\t\t\t\tnames: z.array(z.string().nullable()),\n\t\t\t\ttypes: z.array(z.string().nullable()),\n\t\t\t})\n\t\t\t.parse(result.outBinds);\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug('result.outBinds', result.outBinds);\n\t\t/* v8 ignore stop */\n\n\t\tconst message = `Error when decoding arguments\\n${SQL_GET_ARGUMENT}\\n${errorToString(err)}`;\n\t\tthrow new RequestError(message);\n\t}\n\n\tif (data.names.length !== data.types.length) {\n\t\tthrow new RequestError('Error when decoding arguments. The number of names and types does not match');\n\t}\n\n\tconst argTypes: argsType = {};\n\tfor (let i = 0; i < data.names.length; i++) {\n\t\tconst name = data.names[i];\n\t\tconst type = data.types[i];\n\t\tif (name && type) {\n\t\t\targTypes[name.toLowerCase()] = type;\n\t\t}\n\t}\n\n\treturn argTypes;\n};\n\n/**\n *\tFind the argument types for a given procedure to be executed.\n *\tAs the arguments are cached, we first look up the cache and only if not yet available we load them.\n *\t@param procedure - The procedure\n *\t@param databaseConnection - The database connection\n *\t@param argumentCache - The argument cache.\n *\t@returns The argument types\n */\nconst findArguments = async (procedure: string, databaseConnection: Connection, argumentCache: ArgumentCache): Promise<argsType> => {\n\tconst key = procedure.toUpperCase();\n\n\t// lookup in the cache\n\tconst cachedArgs = argumentCache.get(key);\n\n\t// if we found the procedure in the cache, we return it\n\tif (cachedArgs) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebug(`findArguments: procedure \"${procedure}\" found in cache`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\treturn cachedArgs;\n\t}\n\n\t// load from database\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tdebug(`findArguments: procedure \"${procedure}\" not found in cache and must be loaded`);\n\t}\n\t/* v8 ignore stop */\n\n\tconst args = await loadArguments(procedure, databaseConnection);\n\n\t// add to the cache\n\targumentCache.set(key, args);\n\n\treturn args;\n};\n\n/**\n *\tGet the bindling for an argument.\n *\t@param argName - The argument name.\n *\t@param argValue - The argument value.\n *\t@param argType - The argument type.\n *\t@returns The binding.\n */\nexport const getBinding = (argName: string, argValue: unknown, argType: string): BindParameter => {\n\tconst isEmpty = argValue === '' || argValue === null || argValue === undefined;\n\n\tif (argType === DATA_TYPES.VARCHAR2 || argType === DATA_TYPES.CHAR) {\n\t\treturn {dir: BIND_IN, type: DB_TYPE_VARCHAR, val: isEmpty ? null : argValue};\n\t}\n\n\tif (argType === DATA_TYPES.CLOB) {\n\t\treturn {dir: BIND_IN, type: DB_TYPE_CLOB, val: isEmpty ? null : argValue};\n\t}\n\n\tif (argType === DATA_TYPES.NUMBER || argType === DATA_TYPES.BINARY_INTEGER) {\n\t\tif (isEmpty) {\n\t\t\treturn {dir: BIND_IN, type: DB_TYPE_NUMBER, val: null};\n\t\t}\n\t\tconst value = stringToNumber(argValue);\n\t\tif (value === null) {\n\t\t\tthrow new Error(`Error in named parameter \"${argName}\": invalid value \"${inspect(argValue)}\" for type \"${argType}\"`);\n\t\t}\n\n\t\treturn {dir: BIND_IN, type: DB_TYPE_NUMBER, val: value};\n\t}\n\n\tif (argType === DATA_TYPES.DATE) {\n\t\tif (isEmpty) {\n\t\t\treturn {dir: BIND_IN, type: DB_TYPE_DATE, val: null};\n\t\t}\n\t\tif (typeof argValue !== 'string') {\n\t\t\tthrow new TypeError(`Error in named parameter \"${argName}\": invalid value \"${inspect(argValue)}\" for type \"${argType}\"`);\n\t\t}\n\t\tconst value = new Date(argValue);\n\t\tif (Number.isNaN(value.getTime())) {\n\t\t\tthrow new TypeError(`Error in named parameter \"${argName}\": invalid value \"${inspect(argValue)}\" for type \"${argType}\"`);\n\t\t}\n\n\t\treturn {dir: BIND_IN, type: DB_TYPE_DATE, val: value};\n\t}\n\n\tif (argType === DATA_TYPES.PL_SQL_TABLE || Array.isArray(argValue)) {\n\t\tconst value = typeof argValue === 'string' ? [argValue] : argValue;\n\n\t\treturn {dir: BIND_IN, type: DB_TYPE_VARCHAR, val: value};\n\t}\n\n\tthrow new Error(`Error in named parameter \"${argName}\": invalid binding type \"${argType}\"`);\n};\n\n/**\n *\tGet binding table for tracing.\n *\t@param argObj - The arguments to pass to the procedure\n *\t@param argTypes - The argument types.\n *\t@returns The text.\n */\nconst inspectBindings = (argObj: argObjType, argTypes: argsType): string => {\n\tconst rows = Object.entries(argObj).map(([key, value]) => {\n\t\treturn [key, value.toString(), typeof value, argTypes[key.toLowerCase()] ?? 'unknown'];\n\t});\n\n\tconst {text} = toTable(['id', 'value', 'value type', 'argument type'], rows);\n\n\treturn text;\n};\n\n/**\n *\tGet the sql statement and bindings for the procedure to execute for a fixed number of arguments\n *\t@param req - The req object represents the HTTP request. (only used for debugging)\n *\t@param procName - The procedure to execute\n *\t@param argObj - The arguments to pass to the procedure\n *\t@param databaseConnection - The database connection\n *\t@param argumentCache - The argument cache.\n *\t@returns The SQL statement and bindings for the procedure to execute\n */\nexport const getProcedureNamed = async (\n\treq: Request,\n\tprocName: string,\n\targObj: argObjType,\n\tdatabaseConnection: Connection,\n\targumentCache: ArgumentCache,\n): Promise<{sql: string; bind: BindParameters}> => {\n\tdebug(`getProcedureNamed: ${procName} arguments=`, argObj);\n\n\t// get the types of the arguments\n\tconst argTypes = await findArguments(procName, databaseConnection, argumentCache);\n\n\tconst sqlParameter: string[] = [];\n\n\tconst bindings: BindParameters = {};\n\n\t// bindings for the statement\n\tfor (const key in argObj) {\n\t\tconst parameterName = `p_${key}`;\n\t\tconst argValue = argObj[key];\n\t\tconst argType = argTypes[key.toLowerCase()];\n\t\tlet bind: BindParameter = {dir: BIND_IN, type: DB_TYPE_VARCHAR, val: argValue};\n\n\t\tif (argType) {\n\t\t\tbind = getBinding(key, argValue, argType);\n\t\t} else {\n\t\t\tconst text = inspectBindings(argObj, argTypes);\n\t\t\twarningMessage({\n\t\t\t\ttype: 'warning',\n\t\t\t\tmessage: `Error in named parameter \"${key}\": invalid binding type \"${argType}\"\\n\\n${text}`,\n\t\t\t\treq,\n\t\t\t});\n\t\t}\n\n\t\tsqlParameter.push(`${key}=>:${parameterName}`);\n\t\tbindings[parameterName] = bind;\n\t}\n\n\t// select statement\n\tconst sql = `${procName}(${sqlParameter.join(', ')})`;\n\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tdebug(sql);\n\t\tdebug(inspectBindings(argObj, argTypes));\n\t}\n\t/* v8 ignore stop */\n\n\treturn {sql, bind: bindings};\n};","import debugModule from 'debug';\nconst debug = debugModule('webplsql:parsePage');\n\nimport type {pageType, cookieType} from '../../types.ts';\n\n/**\n *\tParse the header and split it up into the individual components\n *\n * @param text - The text returned from the PL/SQL procedure.\n * @returns The parsed page.\n */\nexport const parsePage = (text: string): pageType => {\n\tconst page: pageType = {\n\t\tbody: '',\n\t\thead: {\n\t\t\tcookies: [],\n\t\t\totherHeaders: {},\n\t\t},\n\t\tfile: {\n\t\t\tfileType: null,\n\t\t\tfileSize: null,\n\t\t\tfileBlob: null,\n\t\t},\n\t};\n\n\t//\n\t//\t1)\tSplit up the text in header and body\n\t//\n\n\t// Find the end of the header identified by \\n\\n\n\tlet head = '';\n\tconst headerEndPosition = text.indexOf('\\n\\n');\n\tif (headerEndPosition === -1) {\n\t\thead = text;\n\t} else {\n\t\thead = text.slice(0, Math.max(0, headerEndPosition + 2));\n\t\tpage.body = text.slice(Math.max(0, headerEndPosition + 2));\n\t}\n\n\t//\n\t//\t2)\tparse the headers\n\t//\n\n\tdebug('parsing the headers received from PL/SQL');\n\thead.split('\\n').forEach((line) => {\n\t\tconst header = getHeader(line);\n\n\t\tif (header) {\n\t\t\tswitch (header.name.toLowerCase()) {\n\t\t\t\tcase 'set-cookie':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst cookie = parseCookie(header.value);\n\t\t\t\t\t\tdebug(`oracle header \"set-cookie\" with value \"${header.value}\" was received has been parsed to ${JSON.stringify(cookie)}`);\n\t\t\t\t\t\tif (cookie === null) {\n\t\t\t\t\t\t\tthrow new Error(`Unable to parse header \"set-cookie\" with value \"${header.value}\" received from PL/SQL`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpage.head.cookies.push(cookie);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'content-type':\n\t\t\t\t\tpage.head.contentType = header.value;\n\t\t\t\t\tdebug(`oracle header \"content-type\" with value \"${page.head.contentType}\" was parsed`);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'x-db-content-length':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst contentLength = Number.parseInt(header.value, 10);\n\t\t\t\t\t\tif (Number.isNaN(contentLength)) {\n\t\t\t\t\t\t\tthrow new TypeError(`Unable to parse header \"x-db-content-length\" with value \"${header.value}\" received from PL/SQL`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpage.head.contentLength = contentLength;\n\t\t\t\t\t\t\tdebug(`oracle header \"x-db-content-length\" with value \"${page.head.contentLength}\" was parsed`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'status':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst statusCode = Number.parseInt(header.value, 10);\n\t\t\t\t\t\tif (Number.isNaN(statusCode)) {\n\t\t\t\t\t\t\tthrow new TypeError(`Unable to parse header \"status\" with value \"${header.value}\" received from PL/SQL`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpage.head.statusCode = statusCode;\n\t\t\t\t\t\t\tdebug(`oracle header \"status\" with value \"${page.head.statusCode}\" was parsed`);\n\t\t\t\t\t\t\tconst index = header.value.indexOf(' ');\n\t\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\t\tpage.head.statusDescription = header.value.slice(Math.max(0, index + 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'location':\n\t\t\t\t\tpage.head.redirectLocation = header.value;\n\t\t\t\t\tdebug(`oracle header \"location\" with value \"${page.head.statusCode}\" was parsed`);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'x-oracle-ignore':\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tpage.head.otherHeaders[header.name] = header.value;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\treturn page;\n};\n\n/**\n *\tGet a header line\n *\t@param line - The line\n *\t@returns The header.\n */\nconst getHeader = (line: string): {name: string; value: string} | null => {\n\tconst index = line.indexOf(':');\n\n\tif (index !== -1) {\n\t\treturn {\n\t\t\tname: line.slice(0, Math.max(0, index)).trim(),\n\t\t\tvalue: line.slice(Math.max(0, index + 1)).trim(),\n\t\t};\n\t}\n\n\treturn null;\n};\n\n/**\n *\tParses a cookie string\n *\t@param text - The cookie string.\n *\t@returns The parsed cookie.\n */\nconst parseCookie = (text: string): cookieType | null => {\n\t// validate\n\tif (typeof text !== 'string' || text.trim().length === 0) {\n\t\treturn null;\n\t}\n\n\t// split the cookie into it's parts\n\tlet cookieElements = text.split(';');\n\n\t// trim cookie elements\n\tcookieElements = cookieElements.map((element) => element.trim());\n\n\t// get name and value\n\tconst firstElement = cookieElements[0];\n\tif (!firstElement) {\n\t\treturn null;\n\t}\n\tconst index = firstElement.indexOf('=');\n\tif (index <= 0) {\n\t\t// if the index is -1, there is no equal sign and if it's 0 the name is empty\n\t\treturn null;\n\t}\n\n\tconst cookie: cookieType = {\n\t\tname: firstElement.slice(0, Math.max(0, index)).trim(),\n\t\tvalue: firstElement.slice(Math.max(0, index + 1)).trim(),\n\t\toptions: {},\n\t};\n\n\t// remove the first element\n\tcookieElements.shift();\n\n\t// get the other options\n\tcookieElements.forEach((element) => {\n\t\tif (element.toLowerCase().startsWith('path=')) {\n\t\t\tcookie.options.path = element.slice(5);\n\t\t} else if (element.toLowerCase().startsWith('domain=')) {\n\t\t\tcookie.options.domain = element.slice(7);\n\t\t} else if (element.toLowerCase().startsWith('secure')) {\n\t\t\tcookie.options.secure = true;\n\t\t} else if (element.toLowerCase().startsWith('expires=')) {\n\t\t\tconst date = tryDecodeDate(element.slice(8));\n\t\t\tif (date) {\n\t\t\t\tcookie.options.expires = date;\n\t\t\t}\n\t\t} else if (element.toLowerCase().startsWith('httponly')) {\n\t\t\tcookie.options.httpOnly = true;\n\t\t}\n\t});\n\n\treturn cookie;\n};\n\n/**\n * Try to decode a date\n * @param value - The value to decode.\n * @returns The decoded date or null.\n */\nconst tryDecodeDate = (value: string): Date | null => {\n\tconst result = new Date(value);\n\tif (Number.isNaN(result.getTime())) {\n\t\treturn null;\n\t}\n\treturn result;\n};","/*\n *\tPage the raw page content and return the content to the client\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:sendResponse');\n\nimport stream from 'node:stream';\nimport {getBlock} from '../../util/trace.ts';\nimport type {Request, Response} from 'express';\nimport type {pageType} from '../../types.ts';\n\n/**\n * Pipe a readable to the response and await completion.\n * Listeners are attached before piping to avoid races.\n *\n * @param readable - The source readable stream.\n * @param res - The HTTP response stream.\n */\nconst pipeReadableToResponse = async (readable: stream.Readable, res: Response): Promise<void> => {\n\tawait new Promise<void>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst canAddResponseListener = typeof res.on === 'function';\n\t\tconst canRemoveResponseListener = typeof res.removeListener === 'function';\n\n\t\tconst cleanup = () => {\n\t\t\treadable.removeListener('end', onReadableEnd);\n\t\t\treadable.removeListener('close', onReadableClose);\n\t\t\treadable.removeListener('error', onReadableError);\n\t\t\tif (canRemoveResponseListener) {\n\t\t\t\tres.removeListener('finish', onResponseFinish);\n\t\t\t\tres.removeListener('close', onResponseClose);\n\t\t\t}\n\t\t};\n\n\t\tconst resolveOnce = () => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tresolve();\n\t\t};\n\n\t\tconst rejectOnce = (error: Error) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error);\n\t\t};\n\n\t\tconst onReadableEnd = () => {\n\t\t\tresolveOnce();\n\t\t};\n\n\t\tconst onReadableClose = () => {\n\t\t\tresolveOnce();\n\t\t};\n\n\t\tconst onReadableError = (error: Error) => {\n\t\t\trejectOnce(error);\n\t\t};\n\n\t\tconst onResponseFinish = () => {\n\t\t\tresolveOnce();\n\t\t};\n\n\t\tconst onResponseClose = () => {\n\t\t\tresolveOnce();\n\t\t};\n\n\t\treadable.on('end', onReadableEnd);\n\t\treadable.on('close', onReadableClose);\n\t\treadable.on('error', onReadableError);\n\t\tif (canAddResponseListener) {\n\t\t\tres.on('finish', onResponseFinish);\n\t\t\tres.on('close', onResponseClose);\n\t\t}\n\n\t\ttry {\n\t\t\treadable.pipe(res);\n\t\t} catch (error: unknown) {\n\t\t\trejectOnce(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t});\n};\n\n/**\n *\tSend \"default\" response to the browser\n *\t@param _req - The req object represents the HTTP request.\n *\t@param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n *\t@param page - The page to send.\n */\nexport const sendResponse = async (_req: Request, res: Response, page: pageType): Promise<void> => {\n\tconst debugText: string[] = [];\n\n\t// Send the \"cookies\"\n\tpage.head.cookies.forEach((cookie) => {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.cookie: name=\"${cookie.name}\" value=\"${cookie.value}\" options=${JSON.stringify(cookie.options)}`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.cookie(cookie.name, cookie.value, cookie.options);\n\t});\n\n\t// If there is a \"redirectLocation\" header, we immediately redirect and return\n\tif (typeof page.head.redirectLocation === 'string' && page.head.redirectLocation.length > 0) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.redirect(302, \"${page.head.redirectLocation}\")`);\n\t\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.redirect(302, page.head.redirectLocation);\n\t\treturn;\n\t}\n\n\t// Send all the \"otherHeaders\"\n\tfor (const key in page.head.otherHeaders) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.set(\"${key}\", \"${page.head.otherHeaders[key]}\")`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.set(key, page.head.otherHeaders[key]);\n\t}\n\n\t// If this is a file download, we eventually set the \"Content-Type\" and the file content and then return.\n\tif (page.file.fileType === 'B' || page.file.fileType === 'F') {\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (typeof page.head.contentType === 'string' && page.head.contentType.length > 0) {\n\t\t\theaders['Content-Type'] = page.head.contentType;\n\t\t}\n\n\t\tif (typeof page.file.fileSize === 'number' && page.file.fileSize > 0) {\n\t\t\theaders['Content-Length'] = page.file.fileSize.toString();\n\t\t}\n\n\t\tif (Object.keys(headers).length > 0) {\n\t\t\t/* v8 ignore start */\n\t\t\tif (debug.enabled) {\n\t\t\t\tdebugText.push(`res.writeHead(200, ${JSON.stringify(headers)})`);\n\t\t\t}\n\t\t\t/* v8 ignore stop */\n\n\t\t\tres.writeHead(200, headers);\n\t\t}\n\n\t\t// Check if fileBlob is a stream\n\t\tif (page.file.fileBlob instanceof stream.Readable) {\n\t\t\t/* v8 ignore start */\n\t\t\tif (debug.enabled) {\n\t\t\t\tdebugText.push(`res.pipe(\"${page.file.fileType ?? ''}\") - streaming`);\n\t\t\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t\t\t}\n\t\t\t/* v8 ignore stop */\n\n\t\t\tawait pipeReadableToResponse(page.file.fileBlob, res);\n\t\t} else {\n\t\t\t/* v8 ignore start */\n\t\t\tif (debug.enabled) {\n\t\t\t\tdebugText.push(`res.end(\"${page.file.fileType ?? ''}\") - buffer`);\n\t\t\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t\t\t}\n\t\t\t/* v8 ignore stop */\n\n\t\t\tres.end(page.file.fileBlob, 'binary');\n\t\t}\n\t\treturn;\n\t}\n\n\t// Is the a \"contentType\" header\n\tif (typeof page.head.contentType === 'string' && page.head.contentType.length > 0) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.set(\"Content-Type\", \"${page.head.contentType}\")`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.set('Content-Type', page.head.contentType);\n\t}\n\n\t// If we have a \"Status\" header, we send the header and then return.\n\tif (typeof page.head.statusCode === 'number') {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.status(page.head.statusCode).send(\"${page.head.statusDescription ?? ''}\")`);\n\t\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.status(page.head.statusCode).send(page.head.statusDescription);\n\t\treturn;\n\t}\n\n\t// Send the body\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tif (page.body instanceof stream.Readable) {\n\t\t\tdebugText.push(`${'-'.repeat(60)}\\n[Stream Body]`);\n\t\t} else {\n\t\t\tdebugText.push(`${'-'.repeat(60)}\\n${page.body}`);\n\t\t}\n\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t}\n\t/* v8 ignore stop */\n\n\tif (page.body instanceof stream.Readable) {\n\t\tawait pipeReadableToResponse(page.body, res);\n\t} else {\n\t\tres.send(page.body);\n\t}\n};","/*\n *\tRequestError\n */\n\nimport type {environmentType} from '../../types.ts';\nimport type {BindParameters} from 'oracledb';\n\nexport class ProcedureError extends Error {\n\ttimestamp: Date;\n\tenvironment: environmentType;\n\tsql: string;\n\tbind: BindParameters;\n\n\t/**\n\t * @param message - The error message.\n\t * @param environment - The environment.\n\t * @param sql - The SQL to execute.\n\t * @param bind - The bind parameters.\n\t */\n\tconstructor(message: string, environment: environmentType, sql: string, bind: BindParameters) {\n\t\tsuper(message);\n\n\t\t// Maintains proper stack trace for where our error was thrown (only available on V8)\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, ProcedureError);\n\t\t}\n\n\t\t// Custom debugging information\n\t\tthis.timestamp = new Date();\n\t\tthis.environment = environment;\n\t\tthis.sql = sql;\n\t\tthis.bind = bind;\n\t}\n}","import {DEFAULT_CACHE_MAX_SIZE, CACHE_PRUNE_PERCENT} from '../../common/constants.ts';\n\ntype cacheEntryType<T> = {\n\thitCount: number;\n\tvalue: T;\n};\n\n/**\n * Generic Cache class with LFU (Least Frequently Used) eviction policy.\n */\nexport class Cache<T> {\n\tcache: Map<string, cacheEntryType<T>>;\n\tmaxSize: number;\n\thits: number;\n\tmisses: number;\n\n\t/**\n\t * @param maxSize - Maximum number of entries in the cache.\n\t */\n\tconstructor(maxSize: number = DEFAULT_CACHE_MAX_SIZE) {\n\t\tthis.cache = new Map();\n\t\tthis.maxSize = maxSize;\n\t\tthis.hits = 0;\n\t\tthis.misses = 0;\n\t}\n\n\t/**\n\t * Get an entry from the cache.\n\t * @param key - The key.\n\t * @returns The value or undefined if not found.\n\t */\n\tget(key: string): T | undefined {\n\t\tconst entry = this.cache.get(key);\n\t\tif (entry) {\n\t\t\tentry.hitCount++;\n\t\t\tthis.hits++;\n\t\t\treturn entry.value;\n\t\t}\n\t\tthis.misses++;\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Set an entry in the cache.\n\t * @param key - The key.\n\t * @param value - The value.\n\t */\n\tset(key: string, value: T): void {\n\t\t// If updating an existing key, preserve its hitCount?\n\t\t// Typically LFU implies resetting or keeping.\n\t\t// For simplicity and avoiding complex aging, if we set it again, we reset hitCount or keep it?\n\t\t// The requirement is \"cache invalidation\" (delete) or \"cache loading\" (set).\n\t\t// If we overwrite, it's usually a new value. Let's reset hitCount to 0 for a fresh start or 1.\n\n\t\t// Ensure we have space\n\t\tif (this.cache.size >= this.maxSize && !this.cache.has(key)) {\n\t\t\tthis.prune();\n\t\t}\n\n\t\tthis.cache.set(key, {hitCount: 0, value});\n\t}\n\n\t/**\n\t * Delete an entry from the cache.\n\t * @param key - The key.\n\t */\n\tdelete(key: string): void {\n\t\tthis.cache.delete(key);\n\t}\n\n\t/**\n\t * Clear the cache.\n\t */\n\tclear(): void {\n\t\tthis.cache.clear();\n\t\tthis.hits = 0;\n\t\tthis.misses = 0;\n\t}\n\n\t/**\n\t * Prune the cache by removing the least frequently used entries.\n\t * Removes 10% of the cache size.\n\t */\n\tprune(): void {\n\t\t// Convert cache entries to an array\n\t\tconst entries = Array.from(this.cache.entries());\n\n\t\t// Sort entries by hitCount in ascending order\n\t\tentries.sort((a, b) => a[1].hitCount - b[1].hitCount);\n\n\t\t// Remove the bottom 10%\n\t\tconst removeCount = Math.max(1, Math.floor(this.maxSize * CACHE_PRUNE_PERCENT));\n\t\tconst keysToRemove = entries.slice(0, removeCount).map(([key]) => key);\n\n\t\tfor (const key of keysToRemove) {\n\t\t\tthis.cache.delete(key);\n\t\t}\n\t}\n\n\t/**\n\t * Get the size of the cache.\n\t * @returns The size.\n\t */\n\tget size(): number {\n\t\treturn this.cache.size;\n\t}\n\n\t/**\n\t * Get all keys in the cache.\n\t * @returns The keys.\n\t */\n\tkeys(): string[] {\n\t\treturn Array.from(this.cache.keys());\n\t}\n\n\t/**\n\t * Get cache statistics.\n\t * @returns The statistics.\n\t */\n\tgetStats(): {size: number; maxSize: number; hits: number; misses: number} {\n\t\treturn {\n\t\t\tsize: this.cache.size,\n\t\t\tmaxSize: this.maxSize,\n\t\t\thits: this.hits,\n\t\t\tmisses: this.misses,\n\t\t};\n\t}\n}","import debugModule from 'debug';\nconst debug = debugModule('webplsql:procedureSanitize');\n\nimport {BIND_IN, BIND_OUT, STRING, NUMBER} from '../../util/oracledb-provider.ts';\nimport z from 'zod';\nimport {RequestError} from './requestError.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {OWA_RESOLVED_NAME_MAX_LEN} from '../../../common/constants.ts';\nimport type {Connection, Result, BindParameters} from 'oracledb';\nimport type {configPlSqlHandlerType, ProcedureNameCache} from '../../types.ts';\nimport {Cache} from '../../util/cache.ts';\n\nconst DEFAULT_EXCLUSION_LIST = ['sys.', 'dbms_', 'utl_', 'owa_', 'htp.', 'htf.', 'wpg_docload.', 'ctxsys.', 'mdsys.'];\n\nconst validationFunctionCache = new Cache<{valid: boolean}>();\n\n/**\n * Resolve the procedure name using dbms_utility.name_resolve.\n *\n * @param procName - The procedure name to resolve.\n * @param databaseConnection - The database connection.\n * @param procedureNameCache - The procedure name cache.\n * @returns The resolved canonical procedure name (SCHEMA.NAME).\n */\nconst resolveProcedureName = async (procName: string, databaseConnection: Connection, procedureNameCache: ProcedureNameCache): Promise<string> => {\n\t// Check cache\n\tconst cachedName = procedureNameCache.get(procName);\n\tif (cachedName) {\n\t\tdebug(`resolveProcedureName: Cache hit for \"${procName}\" -> \"${cachedName}\"`);\n\t\treturn cachedName;\n\t}\n\n\tdebug(`resolveProcedureName: Cache miss for \"${procName}\". Resolving in DB...`);\n\n\tconst sql = `\n\t\tDECLARE\n\t\t\tl_schema VARCHAR2(128);\n\t\t\tl_part1 VARCHAR2(128);\n\t\t\tl_part2 VARCHAR2(128);\n\t\t\tl_dblink VARCHAR2(128);\n\t\t\tl_part1_type NUMBER;\n\t\t\tl_object_number NUMBER;\n\t\tBEGIN\n\t\t\tdbms_utility.name_resolve(\n\t\t\t\tname => :name,\n\t\t\t\tcontext => 1,\n\t\t\t\tschema => l_schema,\n\t\t\t\tpart1 => l_part1,\n\t\t\t\tpart2 => l_part2,\n\t\t\t\tdblink => l_dblink,\n\t\t\t\tpart1_type => l_part1_type,\n\t\t\t\tobject_number => l_object_number\n\t\t\t);\n\t\t\t\n\t\t\t-- Reconstruct the canonical name\n\t\t\t-- If it's a package procedure: schema.package.procedure\n\t\t\t-- If it's a standalone procedure: schema.procedure\n\t\t\t\n\t\t\tIF l_part1 IS NOT NULL THEN\n\t\t\t\t:resolved := l_schema || '.' || l_part1 || '.' || l_part2;\n\t\t\tELSE\n\t\t\t\t:resolved := l_schema || '.' || l_part2;\n\t\t\tEND IF;\n\t\tEND;\n\t`;\n\n\tconst bind: BindParameters = {\n\t\tname: {dir: BIND_IN, type: STRING, val: procName},\n\t\tresolved: {dir: BIND_OUT, type: STRING, maxSize: OWA_RESOLVED_NAME_MAX_LEN},\n\t};\n\n\ttry {\n\t\tconst result = await databaseConnection.execute(sql, bind);\n\t\tconst {resolved} = z.strictObject({resolved: z.string()}).parse(result.outBinds);\n\n\t\tif (!resolved) {\n\t\t\tthrow new RequestError(`Could not resolve procedure name \"${procName}\"`);\n\t\t}\n\n\t\tdebug(`resolveProcedureName: Resolved \"${procName}\" -> \"${resolved}\"`);\n\n\t\t// Update cache\n\t\tprocedureNameCache.set(procName, resolved);\n\n\t\treturn resolved;\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug(`resolveProcedureName: Error resolving \"${procName}\"`, err);\n\t\t/* v8 ignore stop */\n\n\t\t// Rethrow as RequestError to indicate 404/403\n\t\tthrow new RequestError(`Procedure \"${procName}\" not found or not accessible.\\n${errorToString(err)}`);\n\t}\n};\n\n/**\n * Sanitize the procedure name.\n *\n * @param procName - The procedure name.\n * @param databaseConnection - The database connection\n * @param options - the options for the middleware.\n * @param procedureNameCache - The procedure name cache.\n * @returns Promise resolving to final procedure name.\n */\nexport const sanitizeProcName = async (\n\tprocName: string,\n\tdatabaseConnection: Connection,\n\toptions: configPlSqlHandlerType,\n\tprocedureNameCache: ProcedureNameCache,\n): Promise<string> => {\n\tdebug('sanitizeProcName', procName);\n\n\t// make lowercase and trim\n\tlet finalProcName = procName.toLowerCase().trim();\n\n\t// remove special characters (basic sanity check before DB call)\n\tfinalProcName = removeSpecialCharacters(finalProcName);\n\n\t// check for default exclusions\n\tfor (const i of DEFAULT_EXCLUSION_LIST) {\n\t\tif (finalProcName.startsWith(i)) {\n\t\t\tconst error = `Procedure name \"${procName}\" is in default exclusion list \"${DEFAULT_EXCLUSION_LIST.join(',')}\"`;\n\t\t\t/* v8 ignore start */\n\t\t\tdebug(error);\n\t\t\t/* v8 ignore stop */\n\n\t\t\tthrow new RequestError(error);\n\t\t}\n\t}\n\n\t// check for custom exclusions\n\tif (options.exclusionList && options.exclusionList.length > 0) {\n\t\tfor (const i of options.exclusionList) {\n\t\t\tif (finalProcName.startsWith(i)) {\n\t\t\t\tconst error = `Procedure name \"${procName}\" is in custom exclusion list \"${options.exclusionList.join(',')}\"`;\n\t\t\t\t/* v8 ignore start */\n\t\t\t\tdebug(error);\n\t\t\t\t/* v8 ignore stop */\n\n\t\t\t\tthrow new RequestError(error);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check request validation function\n\tif (options.requestValidationFunction && options.requestValidationFunction.length > 0) {\n\t\t// Note: We might want to scope this cache too, but for now let's focus on the procedure name cache.\n\t\t// The original code used a global cache for this.\n\t\t// For strict correctness, we should probably verify the *resolved* name,\n\t\t// but legacy behavior checks the input name.\n\t\tconst valid = await requestValidationFunction(finalProcName, options.requestValidationFunction, databaseConnection);\n\t\tif (!valid) {\n\t\t\tconst error = `Procedure name \"${procName}\" is not valid according to the request validation function \"${options.requestValidationFunction}\"`;\n\t\t\t/* v8 ignore start */\n\t\t\tdebug(error);\n\t\t\t/* v8 ignore stop */\n\n\t\t\tthrow new RequestError(error);\n\t\t}\n\t}\n\n\t// NEW: Resolve the procedure name against the database\n\t// This prevents SQL injection and ensures the procedure exists\n\tconst resolvedName = await resolveProcedureName(finalProcName, databaseConnection, procedureNameCache);\n\n\treturn resolvedName;\n};\n\n/**\n * @param str - string\n * @returns string\n */\nconst removeSpecialCharacters = (str: string | null | undefined): string => {\n\tif (str === null || str === undefined) {\n\t\treturn '';\n\t}\n\n\tconst chars: string[] = [];\n\n\tfor (const c of str) {\n\t\tif ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c === '.' || c === '_' || c === '#' || c === '$') {\n\t\t\tchars.push(c);\n\t\t}\n\t}\n\n\treturn chars.join('');\n};\n\n/**\n * @param procName - The procedure name.\n * @param requestValidationFunction - The request validation function.\n * @param databaseConnection - The database connection\n * @returns Promise resolving to final procedure name.\n */\nconst loadRequestValid = async (procName: string, requestValidationFunction: string, databaseConnection: Connection): Promise<boolean> => {\n\tconst bind: BindParameters = {\n\t\tproc: {dir: BIND_IN, type: STRING, val: procName},\n\t\tvalid: {dir: BIND_OUT, type: NUMBER},\n\t};\n\n\tconst SQL = [\n\t\t'DECLARE',\n\t\t' l_valid NUMBER := 0;',\n\t\t'BEGIN',\n\t\t` IF (${requestValidationFunction}(:proc)) THEN`,\n\t\t' l_valid := 1;',\n\t\t' END IF;',\n\t\t' :valid := l_valid;',\n\t\t'END;',\n\t].join('\\n');\n\n\tlet result: Result<unknown> = {};\n\ttry {\n\t\tresult = await databaseConnection.execute(SQL, bind);\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug('result', result);\n\t\t/* v8 ignore stop */\n\n\t\tconst message = `Error when validating procedure name \"${procName}\"\\n${SQL}\\n${errorToString(err)}`;\n\t\tthrow new RequestError(message);\n\t}\n\n\ttry {\n\t\tconst data = z.strictObject({valid: z.number()}).parse(result.outBinds);\n\t\treturn data.valid === 1;\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug('result', result.outBinds);\n\t\t/* v8 ignore stop */\n\n\t\tconst message = `Internal error when parsing ${String(result.outBinds)}\\n${errorToString(err)}`;\n\t\tthrow new Error(message);\n\t}\n};\n\n/**\n * Request validation function.\n *\n * @param procName - The procedure name.\n * @param validationFunction - The request validation function.\n * @param databaseConnection - The database connection\n * @returns Promise resolving to final procedure name.\n */\nconst requestValidationFunction = async (procName: string, validationFunction: string, databaseConnection: Connection): Promise<boolean> => {\n\tdebug('requestValidationFunction', procName, validationFunction);\n\n\t// calculate the key\n\tconst key = procName.toLowerCase();\n\n\t// lookup in the cache\n\tconst cacheEntry = validationFunctionCache.get(key);\n\n\t// if we found the procedure in the cache, we return it (hitCount already incremented by get)\n\tif (cacheEntry !== undefined) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebug(`requestValidationFunction: procedure \"${procName}\" found in cache`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\treturn cacheEntry.valid;\n\t}\n\n\t// load from database\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tdebug(`requestValidationFunction: procedure \"${procName}\" not found in cache and must be loaded`);\n\t}\n\t/* v8 ignore stop */\n\n\tconst valid = await loadRequestValid(procName, validationFunction, databaseConnection);\n\n\t// add to the cache\n\tvalidationFunctionCache.set(key, {valid});\n\n\treturn valid;\n};","import {Readable} from 'node:stream';\nimport {BIND_OUT, BIND_INOUT, STRING, NUMBER} from '../../util/oracledb-provider.ts';\nimport z from 'zod';\nimport debugModule from 'debug';\nimport {ProcedureError} from './procedureError.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {OWA_STREAM_CHUNK_SIZE, OWA_STREAM_BUFFER_SIZE} from '../../../common/constants.ts';\nimport type {Connection, BindParameters} from 'oracledb';\n\nconst debug = debugModule('webplsql:owaPageStream');\n\nexport class OWAPageStream extends Readable {\n\tdatabaseConnection: Connection;\n\tchunkSize: number;\n\tisDone: boolean;\n\n\t/**\n\t * @param databaseConnection - The database connection.\n\t */\n\tconstructor(databaseConnection: Connection) {\n\t\tsuper({highWaterMark: OWA_STREAM_BUFFER_SIZE}); // 16KB buffer\n\t\tthis.databaseConnection = databaseConnection;\n\t\tthis.chunkSize = OWA_STREAM_CHUNK_SIZE;\n\t\tthis.isDone = false;\n\t}\n\n\t/**\n\t * Fetch a chunk of the page from the database.\n\t * @returns The array of lines fetched.\n\t */\n\tasync fetchChunk(): Promise<string[]> {\n\t\tif (this.isDone) return [];\n\n\t\tconst bindParameter: BindParameters = {\n\t\t\tlines: {dir: BIND_OUT, type: STRING, maxArraySize: this.chunkSize},\n\t\t\tirows: {dir: BIND_INOUT, type: NUMBER, val: this.chunkSize},\n\t\t};\n\n\t\tconst sqlStatement = 'BEGIN owa.get_page(thepage=>:lines, irows=>:irows); END;';\n\n\t\ttry {\n\t\t\tconst result = await this.databaseConnection.execute(sqlStatement, bindParameter);\n\t\t\tconst {lines, irows} = z.strictObject({irows: z.number(), lines: z.array(z.string())}).parse(result.outBinds);\n\n\t\t\tdebug(`fetched ${lines.length} lines (irows=${irows})`);\n\n\t\t\t// If we got fewer lines than requested, OR if we got 0 lines, we are done\n\t\t\tif (lines.length < this.chunkSize) {\n\t\t\t\tthis.isDone = true;\n\t\t\t}\n\n\t\t\treturn lines;\n\t\t} catch (err) {\n\t\t\tif (err instanceof ProcedureError) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tthrow new ProcedureError(`OWAPageStream: error when getting page\\n${errorToString(err)}`, {}, sqlStatement, bindParameter);\n\t\t}\n\t}\n\n\t/**\n\t * @override\n\t * @param _size - The size hint (unused).\n\t */\n\toverride _read(_size: number): void {\n\t\tthis.fetchChunk()\n\t\t\t.then((lines) => {\n\t\t\t\tif (lines.length > 0) {\n\t\t\t\t\tthis.push(lines.join(''));\n\t\t\t\t}\n\n\t\t\t\t// After fetching, check if we're done\n\t\t\t\tif (this.isDone) {\n\t\t\t\t\tthis.push(null);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tthis.destroy(err instanceof Error ? err : new Error(String(err)));\n\t\t\t});\n\t}\n\n\t/**\n\t * Add initial body content to the stream.\n\t * @param content - The initial content to prepend.\n\t */\n\taddBody(content: string): void {\n\t\tif (content && content.length > 0) {\n\t\t\tthis.push(content);\n\t\t}\n\t}\n}","import fs from 'node:fs';\nimport path from 'node:path';\nimport type {procedureTraceEntry} from '../types.ts';\n\nclass TraceManager {\n\tenabled = false;\n\tfilename = 'trace.json.log';\n\tmaxEntries = 1000;\n\n\t/**\n\t * Toggle tracing\n\t * @param enabled - New state\n\t */\n\tsetEnabled(enabled: boolean): void {\n\t\tthis.enabled = enabled;\n\t}\n\n\t/**\n\t * Is tracing enabled?\n\t * @returns The state\n\t */\n\tisEnabled(): boolean {\n\t\treturn this.enabled;\n\t}\n\n\t/**\n\t * Add a trace entry\n\t * @param entry - The trace entry\n\t */\n\taddTrace(entry: procedureTraceEntry): void {\n\t\tif (!this.enabled) return;\n\n\t\ttry {\n\t\t\tconst line = JSON.stringify(entry) + '\\n';\n\t\t\tfs.appendFileSync(this.filename, line);\n\t\t} catch (err) {\n\t\t\tconsole.error('TraceManager: error writing trace', err);\n\t\t}\n\t}\n\n\t/**\n\t * Clear all traces\n\t */\n\tclear(): void {\n\t\ttry {\n\t\t\tif (fs.existsSync(this.filename)) {\n\t\t\t\tfs.truncateSync(this.filename, 0);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.error('TraceManager: error clearing traces', err);\n\t\t}\n\t}\n\n\t/**\n\t * Get the full path to the trace file\n\t * @returns The path\n\t */\n\tgetFilePath(): string {\n\t\treturn path.resolve(this.filename);\n\t}\n}\n\nexport const traceManager = new TraceManager();","/*\n *\tInvoke the Oracle procedure and return the raw content of the page\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:procedure');\n\nimport {BIND_IN, BIND_OUT, BIND_INOUT, STRING, NUMBER, BLOB} from '../../util/oracledb-provider.ts';\nimport stream from 'node:stream';\nimport z from 'zod';\n\nimport {uploadFile} from './upload.ts';\nimport {getProcedureVariable} from './procedureVariable.ts';\nimport {getProcedureNamed} from './procedureNamed.ts';\nimport {parsePage} from './parsePage.ts';\nimport {sendResponse} from './sendResponse.ts';\nimport {ProcedureError} from './procedureError.ts';\nimport {RequestError} from './requestError.ts';\nimport {inspect, getBlock} from '../../util/trace.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {sanitizeProcName} from './procedureSanitize.ts';\nimport {OWAPageStream} from './owaPageStream.ts';\nimport {traceManager} from '../../util/traceManager.ts';\nimport type {procedureTraceEntry} from '../../../frontend/types.ts';\nimport type {Request, Response} from 'express';\nimport type {Connection, Result, Lob, BindParameters} from 'oracledb';\nimport type {argObjType, fileUploadType, environmentType, configPlSqlHandlerType, ProcedureNameCache, ArgumentCache} from '../../types.ts';\n\n/**\n *\tGet the procedure and arguments to execute\n *\t@param req - The req object represents the HTTP request. (only used for debugging)\n *\t@param procName - The procedure to execute\n *\t@param argObj - The arguments to pass to the procedure\n *\t@param options - The options for the middleware\n *\t@param databaseConnection - The database connection\n *\t@param procedureNameCache - The procedure name cache.\n *\t@param argumentCache - The argument cache.\n *\t@returns The SQL statement and bindings for the procedure to execute\n */\nconst getProcedure = async (\n\treq: Request,\n\tprocName: string,\n\targObj: argObjType,\n\toptions: configPlSqlHandlerType,\n\tdatabaseConnection: Connection,\n\tprocedureNameCache: ProcedureNameCache,\n\targumentCache: ArgumentCache,\n): Promise<{sql: string; bind: BindParameters; resolvedName?: string}> => {\n\t// path alias\n\tif (options.pathAlias?.toLowerCase() === procName.toLowerCase()) {\n\t\t/* v8 ignore start */\n\t\tdebug(`getProcedure: path alias \"${options.pathAlias}\" redirects to \"${options.pathAliasProcedure}\"`);\n\t\t/* v8 ignore stop */\n\t\treturn {\n\t\t\tsql: `${options.pathAliasProcedure}(p_path=>:p_path)`,\n\t\t\tbind: {\n\t\t\t\tp_path: {dir: BIND_IN, type: STRING, val: procName},\n\t\t\t},\n\t\t};\n\t}\n\n\t// check if we use variable arguments\n\tconst useVariableArguments = procName.startsWith('!');\n\n\t// sanitize procedure name\n\tconst rawName = useVariableArguments ? procName.slice(1) : procName;\n\tconst sanitizedProcName = await sanitizeProcName(rawName, databaseConnection, options, procedureNameCache);\n\n\t// run procedure\n\treturn useVariableArguments\n\t\t? {\n\t\t\t\t...getProcedureVariable(req, sanitizedProcName, argObj),\n\t\t\t\tresolvedName: sanitizedProcName,\n\t\t\t}\n\t\t: {\n\t\t\t\t...(await getProcedureNamed(req, sanitizedProcName, argObj, databaseConnection, argumentCache)),\n\t\t\t\tresolvedName: sanitizedProcName,\n\t\t\t};\n};\n\n/**\n * Prepare procedure\n *\n * NOTE:\n * \t1) dbms_session.modify_package_state(dbms_session.reinitialize) is used to ensure a stateless environment by resetting package state (dbms_session.reset_package)\n *\n * @param cgiObj - The cgi of the procedure to invoke.\n * @param databaseConnection - Database connection.\n * @returns Promise resolving to void.\n */\nconst procedurePrepare = async (cgiObj: environmentType, databaseConnection: Connection): Promise<void> => {\n\tlet sqlStatement = 'BEGIN dbms_session.modify_package_state(dbms_session.reinitialize); END;';\n\ttry {\n\t\tawait databaseConnection.execute(sqlStatement);\n\t} catch (err) {\n\t\tthrow new ProcedureError(`procedurePrepare: error when preparing procedure\\n${errorToString(err)}`, cgiObj, sqlStatement, {});\n\t}\n\n\t// htbuf_len: reduce this limit based on your worst-case character size.\n\t// For most character sets, this will be 2 bytes per character, so the limit would be 127.\n\t// For UTF8 Unicode, it's 3 bytes per character, meaning the limit should be 85.\n\t// For the newer AL32UTF8 Unicode, it's 4 bytes per character, and the limit should be 63.\n\tsqlStatement = 'BEGIN owa.init_cgi_env(:cgicount, :cginames, :cgivalues); owa.user_id := :remote_user; htp.init; htp.htbuf_len := 63; END;';\n\tconst bindParameter: BindParameters = {\n\t\tcgicount: {dir: BIND_IN, type: NUMBER, val: Object.keys(cgiObj).length},\n\t\tcginames: {dir: BIND_IN, type: STRING, val: Object.keys(cgiObj)},\n\t\tcgivalues: {dir: BIND_IN, type: STRING, val: Object.values(cgiObj)},\n\t\tremote_user: {dir: BIND_IN, type: STRING, val: (cgiObj.REMOTE_USER ?? '').slice(0, 30)},\n\t};\n\ttry {\n\t\tawait databaseConnection.execute(sqlStatement, bindParameter);\n\t} catch (err) {\n\t\tthrow new ProcedureError(`procedurePrepare: error when preparing procedure\\n${errorToString(err)}`, cgiObj, sqlStatement, bindParameter);\n\t}\n};\n\n/**\n * Execute procedure\n *\n * @param para - The statement and binding to use when executing the procedure.\n * @param para.sql - The SQL statement.\n * @param para.bind - The bind parameters.\n * @param databaseConnection - Database connection.\n * @returns Promise resolving to void.\n */\nconst procedureExecute = async (para: {sql: string; bind: BindParameters}, databaseConnection: Connection): Promise<void> => {\n\tconst sqlStatement = `BEGIN ${para.sql}; END;`;\n\n\ttry {\n\t\tawait databaseConnection.execute(sqlStatement, para.bind);\n\t} catch (err) {\n\t\tthrow new ProcedureError(`procedureExecute: error when executing procedure:\\n${sqlStatement}\\n${errorToString(err)}`, {}, para.sql, para.bind);\n\t}\n};\n\n/**\n * Download files from procedure\n *\n * @param fileBlob - The blob eventually containing the file.\n * @param databaseConnection - Database connection.\n * @returns Promise resolving to the result.\n */\nconst procedureDownloadFiles = async (\n\tfileBlob: Lob,\n\tdatabaseConnection: Connection,\n): Promise<{fileType: string; fileSize: number; fileBlob: stream.Readable | null}> => {\n\tconst bindParameter: BindParameters = {\n\t\tfileType: {dir: BIND_OUT, type: STRING},\n\t\tfileSize: {dir: BIND_OUT, type: NUMBER},\n\t\tfileBlob: {dir: BIND_INOUT, type: BLOB, val: fileBlob},\n\t};\n\n\tconst sqlStatement = `\nDECLARE\n\tl_file_type\t\tVARCHAR2(32767)\t:= '';\n\tl_file_size\t\tINTEGER\t\t\t:= 0;\nBEGIN\n\tIF (wpg_docload.is_file_download()) THEN\n\t\twpg_docload.get_download_file(l_file_type);\n\t\tIF (l_file_type = 'B') THEN\n\t\t\twpg_docload.get_download_blob(:fileBlob);\n\t\t\tl_file_size := dbms_lob.getlength(:fileBlob);\n\t\tEND IF;\n\tEND IF;\n\t:fileType := l_file_type;\n\t:fileSize := l_file_size;\nEND;\n`;\n\n\tlet result: Result<unknown> | null = null;\n\ttry {\n\t\tresult = await databaseConnection.execute(sqlStatement, bindParameter);\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebug(getBlock('procedureDownloadFiles: results', inspect(result)));\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tthrow new ProcedureError(`procedureDownloadFiles: error when downloading files\\n${errorToString(err)}`, {}, sqlStatement, bindParameter);\n\t}\n\n\treturn z\n\t\t.object({\n\t\t\tfileType: z\n\t\t\t\t.string()\n\t\t\t\t.nullable()\n\t\t\t\t.transform((val) => val ?? ''),\n\t\t\tfileSize: z\n\t\t\t\t.number()\n\t\t\t\t.nullable()\n\t\t\t\t.transform((val) => val ?? 0),\n\t\t\tfileBlob: z.instanceof(stream.Readable).nullable(),\n\t\t})\n\t\t.parse(result.outBinds);\n};\n\n/**\n * Invoke the Oracle procedure and return the page content\n *\n * @param req - The req object represents the HTTP request.\n * @param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n * @param argObj - - The arguments of the procedure to invoke.\n * @param cgiObj - The cgi of the procedure to invoke.\n * @param filesToUpload - Array of files to be uploaded\n * @param options - the options for the middleware.\n * @param databaseConnection - Database connection.\n * @param procedureNameCache - The procedure name cache.\n * @param argumentCache - The argument cache.\n * @returns Promise resolving to the page content generated by the executed procedure\n */\nexport const invokeProcedure = async (\n\treq: Request,\n\tres: Response,\n\targObj: argObjType,\n\tcgiObj: environmentType,\n\tfilesToUpload: fileUploadType[],\n\toptions: configPlSqlHandlerType,\n\tdatabaseConnection: Connection,\n\tprocedureNameCache: ProcedureNameCache,\n\targumentCache: ArgumentCache,\n): Promise<void> => {\n\tdebug('invokeProcedure: begin');\n\n\tconst startTime = Date.now();\n\tlet traceData: procedureTraceEntry | null = null;\n\n\tif (traceManager.isEnabled()) {\n\t\ttraceData = {\n\t\t\tid: Math.random().toString(36).slice(2, 15),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsource: cgiObj.REMOTE_ADDR ?? '',\n\t\t\turl: req.originalUrl,\n\t\t\tmethod: req.method,\n\t\t\tstatus: 'pending',\n\t\t\tduration: 0,\n\t\t\tcgi: cgiObj,\n\t\t\theaders: req.headers as Record<string, string>,\n\t\t\tcookies: req.cookies,\n\t\t\tuploads: filesToUpload.map((f) => ({\n\t\t\t\toriginalname: f.originalname,\n\t\t\t\tmimetype: f.mimetype,\n\t\t\t\tsize: f.size,\n\t\t\t})),\n\t\t};\n\t}\n\n\ttry {\n\t\t// 1) upload files\n\t\tdebug(`invokeProcedure: upload \"${filesToUpload.length}\" files`);\n\t\tif (filesToUpload.length > 0) {\n\t\t\tif (typeof options.documentTable === 'string' && options.documentTable.length > 0) {\n\t\t\t\tconst {documentTable} = options;\n\n\t\t\t\tawait Promise.all(filesToUpload.map((file) => uploadFile(file, documentTable, databaseConnection)));\n\t\t\t} else {\n\t\t\t\t// FIXME: this should be standartized\n\t\t\t\tconsole.warn(`Unable to upload \"${filesToUpload.length}\" files because the option \"\"doctable\" has not been defined`);\n\t\t\t}\n\t\t}\n\n\t\t// 2) get procedure to execute and the arguments\n\n\t\tdebug('invokeProcedure: get procedure to execute and the arguments');\n\t\t// Extract the raw procedure name from params\n\t\tconst rawProcName = Array.isArray(req.params.name) ? req.params.name[0] : req.params.name;\n\t\tif (!rawProcName) {\n\t\t\tthrow new RequestError('No procedure name provided');\n\t\t}\n\t\tconst para = await getProcedure(req, rawProcName, argObj, options, databaseConnection, procedureNameCache, argumentCache);\n\n\t\tif (traceData) {\n\t\t\ttraceData.procedure = para.resolvedName;\n\t\t\ttraceData.parameters = para.bind as Record<string, unknown> | unknown[];\n\t\t}\n\n\t\t// 3) prepare the session\n\n\t\tdebug('invokeProcedure: prepare the session');\n\t\tawait procedurePrepare(cgiObj, databaseConnection);\n\n\t\t// 4) execute the procedure\n\n\t\tdebug('invokeProcedure: execute the session');\n\t\ttry {\n\t\t\tawait procedureExecute(para, databaseConnection);\n\t\t} catch (err) {\n\t\t\t// Invalidation Logic\n\t\t\tif (err instanceof ProcedureError) {\n\t\t\t\tconst errorString = err.toString();\n\t\t\t\t// Check for ORA-04068, ORA-04061, ORA-04065, ORA-06550\n\t\t\t\tif (errorString.includes('ORA-04068') || errorString.includes('ORA-04061') || errorString.includes('ORA-04065') || errorString.includes('ORA-06550')) {\n\t\t\t\t\tdebug(`invokeProcedure: detected invalidation error (${errorString}). Clearing caches.`);\n\n\t\t\t\t\t// Clear name resolution cache for the input name\n\t\t\t\t\tif (rawProcName) {\n\t\t\t\t\t\tprocedureNameCache.delete(rawProcName);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Clear argument cache for the resolved name\n\t\t\t\t\tif (para.resolvedName) {\n\t\t\t\t\t\targumentCache.delete(para.resolvedName.toUpperCase());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\t// 5) get the page returned from the procedure\n\t\tdebug('invokeProcedure: get the page returned from the procedure');\n\n\t\tconst streamInstance = new OWAPageStream(databaseConnection);\n\t\tconst lines = await streamInstance.fetchChunk();\n\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebug(getBlock('data', lines.join('')));\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\t// 6) download files\n\n\t\tdebug('invokeProcedure: download files');\n\t\tconst fileBlob = await databaseConnection.createLob(BLOB);\n\n\t\ttry {\n\t\t\tconst fileDownload = await procedureDownloadFiles(fileBlob, databaseConnection);\n\t\t\t/* v8 ignore start */\n\t\t\tif (debug.enabled) {\n\t\t\t\tdebug(getBlock('fileDownload', inspect({fileType: fileDownload.fileType, fileSize: fileDownload.fileSize})));\n\t\t\t}\n\t\t\t/* v8 ignore stop */\n\n\t\t\t// 7) parse the page\n\n\t\t\tdebug('invokeProcedure: parse the page');\n\t\t\t// We parse the headers from the first chunk\n\t\t\tconst pageComponents = parsePage(lines.join(''));\n\n\t\t\t// add \"Server\" header\n\t\t\tpageComponents.head.server = cgiObj.SERVER_SOFTWARE ?? '';\n\n\t\t\t// add file download information\n\t\t\tif (fileDownload.fileType !== '' && fileDownload.fileSize > 0 && fileDownload.fileBlob !== null) {\n\t\t\t\tpageComponents.file.fileType = fileDownload.fileType;\n\t\t\t\tpageComponents.file.fileSize = fileDownload.fileSize;\n\t\t\t\tpageComponents.file.fileBlob = fileDownload.fileBlob;\n\n\t\t\t\tif (traceData) {\n\t\t\t\t\ttraceData.downloads = {\n\t\t\t\t\t\tfileType: fileDownload.fileType,\n\t\t\t\t\t\tfileSize: fileDownload.fileSize,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// For normal pages, we use the stream.\n\t\t\t\t// Prepend the initial body (parsed by parsePage) to the stream\n\t\t\t\tif (typeof pageComponents.body === 'string' && pageComponents.body.length > 0) {\n\t\t\t\t\tstreamInstance.addBody(pageComponents.body);\n\t\t\t\t}\n\t\t\t\t// Use the stream as the body\n\t\t\t\tpageComponents.body = streamInstance;\n\n\t\t\t\tif (traceData) {\n\t\t\t\t\t// Buffer HTML if tracing enabled\n\t\t\t\t\tlet htmlBuffer = typeof pageComponents.body === 'string' ? pageComponents.body : lines.join('');\n\t\t\t\t\tconst MAX_HTML_SIZE = 1024 * 1024; // 1MB\n\n\t\t\t\t\tconst originalPush = streamInstance.push.bind(streamInstance);\n\t\t\t\t\tstreamInstance.push = (chunk) => {\n\t\t\t\t\t\tif (chunk !== null && htmlBuffer.length < MAX_HTML_SIZE) {\n\t\t\t\t\t\t\tconst str = String(chunk);\n\t\t\t\t\t\t\thtmlBuffer += str;\n\t\t\t\t\t\t\tif (htmlBuffer.length > MAX_HTML_SIZE) {\n\t\t\t\t\t\t\t\thtmlBuffer = htmlBuffer.slice(0, Math.max(0, MAX_HTML_SIZE)) + '... [truncated]';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn originalPush(chunk);\n\t\t\t\t\t};\n\n\t\t\t\t\t// Since we can't easily wait for the stream to finish here without blocking,\n\t\t\t\t\t// we'll have to finalize traceData when the stream ends.\n\t\t\t\t\tconst currentTrace = traceData;\n\t\t\t\t\tstreamInstance.on('end', () => {\n\t\t\t\t\t\tcurrentTrace.html = htmlBuffer;\n\t\t\t\t\t\tcurrentTrace.status = 'success';\n\t\t\t\t\t\tcurrentTrace.duration = Date.now() - startTime;\n\t\t\t\t\t\ttraceManager.addTrace(currentTrace);\n\t\t\t\t\t});\n\t\t\t\t\tstreamInstance.on('error', (err) => {\n\t\t\t\t\t\tcurrentTrace.status = 'fail';\n\t\t\t\t\t\tcurrentTrace.error = err instanceof Error ? err.message : String(err);\n\t\t\t\t\t\tcurrentTrace.duration = Date.now() - startTime;\n\t\t\t\t\t\ttraceManager.addTrace(currentTrace);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 8) send the page to browser\n\n\t\t\tdebug('invokeProcedure: send the page to browser');\n\t\t\tawait sendResponse(req, res, pageComponents);\n\n\t\t\tif (traceData?.downloads) {\n\t\t\t\ttraceData.status = 'success';\n\t\t\t\ttraceData.duration = Date.now() - startTime;\n\t\t\t\ttraceManager.addTrace(traceData);\n\t\t\t}\n\t\t} finally {\n\t\t\t// 9) cleanup\n\n\t\t\tdebug('invokeProcedure: cleanup');\n\t\t\tfileBlob.destroy();\n\t\t}\n\t} catch (err) {\n\t\tif (traceData) {\n\t\t\ttraceData.status = err instanceof ProcedureError ? 'error' : 'fail';\n\t\t\ttraceData.error = err instanceof Error ? err.message : String(err);\n\t\t\ttraceData.duration = Date.now() - startTime;\n\t\t\ttraceManager.addTrace(traceData);\n\t\t}\n\t\tthrow err;\n\t}\n\n\tdebug('invokeProcedure: end');\n};","/*\n *\tPrepare the CGI information\n */\n\nimport os from 'node:os';\nimport {URL} from 'node:url';\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:cgi');\n\nimport type {Request} from 'express';\nimport type {environmentType} from '../../types.ts';\n\nconst DEFAULT_CGI: environmentType = {\n\tPLSQL_GATEWAY: 'WebDb',\n\tGATEWAY_IVERSION: '2',\n\tSERVER_SOFTWARE: 'web_plsql',\n\tGATEWAY_INTERFACE: 'CGI/1.1',\n\tSERVER_PORT: '',\n\tSERVER_NAME: os.hostname(),\n\tREQUEST_METHOD: '',\n\tPATH_INFO: '',\n\tSCRIPT_NAME: '',\n\tREMOTE_ADDR: '',\n\tSERVER_PROTOCOL: '',\n\tREQUEST_PROTOCOL: '',\n\tREMOTE_USER: '',\n\tHTTP_COOKIE: '',\n\tHTTP_USER_AGENT: '',\n\tHTTP_HOST: '',\n\tHTTP_ACCEPT: '',\n\tHTTP_ACCEPT_ENCODING: '',\n\tHTTP_ACCEPT_LANGUAGE: '',\n\tHTTP_REFERER: '',\n\tHTTP_X_FORWARDED_FOR: '',\n\tWEB_AUTHENT_PREFIX: '',\n\tDAD_NAME: '',\n\tDOC_ACCESS_PATH: 'doc',\n\tDOCUMENT_TABLE: '',\n\tPATH_ALIAS: '',\n\t// oxlint-disable-next-line unicorn/text-encoding-identifier-case\n\tREQUEST_CHARSET: 'UTF8',\n\t// oxlint-disable-next-line unicorn/text-encoding-identifier-case\n\tREQUEST_IANA_CHARSET: 'UTF-8',\n\tSCRIPT_PREFIX: '',\n};\n\n/**\n * Create the HTTP_COOKIE string\n *\n * @param req - The req object represents the HTTP request.\n * @returns The string representation of the cookies.\n */\nconst getCookieString = (req: Request): string => {\n\tlet cookieString = '';\n\n\tfor (const propName in req.cookies) {\n\t\tcookieString += `${propName}=${req.cookies[propName]};`;\n\t}\n\n\tdebug('getCookieString', req.cookies, cookieString);\n\n\treturn cookieString;\n};\n\n/**\n * Get the script name and DAD name from a URL\n *\n * @param req - The req object represents the HTTP request.\n * @returns The DAD structure.\n */\nconst getPath = (req: Request): {script: string; prefix: string; dad: string} => {\n\t// create a valid url\n\tconst validUrl = `${req.protocol}://${os.hostname()}${req.originalUrl}`;\n\n\t// get the pathname from the url (new URL('https://example.org/abc/xyz?123').pathname => /abc/xyz)\n\tconst pathname = new URL(validUrl).pathname;\n\n\tconst tmp = trimPath(pathname.slice(0, Math.max(0, pathname.lastIndexOf('/') + 1)));\n\tconst script = `/${tmp}`;\n\tconst prefix = `/${tmp.slice(0, Math.max(0, tmp.lastIndexOf('/')))}`;\n\tconst dad = tmp.slice(Math.max(0, tmp.indexOf('/') + 1));\n\n\treturn {script, prefix, dad};\n};\n\n/**\n * Get a path that is not enclodes in slashes\n *\n * @param value - The value to trim.\n * @returns The trimmed value.\n */\nconst trimPath = (value: string): string => value.replaceAll(/^\\/+|\\/+$/gu, '');\n\n/**\n * Create a CGI object\n *\n * @param req - The req object represents the HTTP request.\n * @param doctable - The document table.\n * @param cgi - The additional cgi.\n * @param authenticatedUser - The authenticated user.\n * @returns CGI object\n */\nexport const getCGI = (req: Request, doctable: string, cgi: environmentType, authenticatedUser: string | null = null): environmentType => {\n\tconst PROTOCOL = req.protocol ? req.protocol.toUpperCase() : '';\n\tconst PATH = getPath(req);\n\n\tconst CGI: environmentType = {\n\t\tSERVER_PORT: typeof req.socket.localPort === 'number' ? req.socket.localPort.toString() : '',\n\t\tREQUEST_METHOD: req.method,\n\t\tPATH_INFO: Array.isArray(req.params.name) ? (req.params.name[0] ?? '') : (req.params.name ?? ''),\n\t\tSCRIPT_NAME: PATH.script,\n\t\tREMOTE_ADDR: (req.ip ?? '').replace('::ffff:', ''),\n\t\tSERVER_PROTOCOL: `${PROTOCOL}/${req.httpVersion}`,\n\t\tREQUEST_PROTOCOL: PROTOCOL,\n\t\tREMOTE_USER: authenticatedUser ?? '',\n\t\tAUTH_TYPE: authenticatedUser ? 'Basic' : '',\n\t\tHTTP_COOKIE: getCookieString(req),\n\t\tHTTP_USER_AGENT: req.get('user-agent') ?? '',\n\t\tHTTP_HOST: req.get('host') ?? '',\n\t\tHTTP_ACCEPT: req.get('accept') ?? '',\n\t\tHTTP_ACCEPT_ENCODING: req.get('accept-encoding') ?? '',\n\t\tHTTP_ACCEPT_LANGUAGE: req.get('accept-language') ?? '',\n\t\tHTTP_REFERER: req.get('referer') ?? '',\n\t\tHTTP_X_FORWARDED_FOR: req.get('x-forwarded-for') ?? '',\n\t\tDAD_NAME: PATH.dad,\n\t\tDOCUMENT_TABLE: doctable,\n\t\tSCRIPT_PREFIX: PATH.prefix,\n\t};\n\n\treturn Object.assign({}, DEFAULT_CGI, CGI, cgi);\n};","/**\n *\tIs the given value a string or an array of strings\n *\t@param value - The value to check.\n *\t@returns True if the value is a string or an array of strings\n */\nexport const isStringOrArrayOfString = (value: unknown): value is string | string[] =>\n\ttypeof value === 'string' || (Array.isArray(value) && value.every((element) => typeof element === 'string'));","/*\n *\tProcess the http request\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:request');\n\nimport util from 'node:util';\nimport {invokeProcedure} from './procedure.ts';\nimport {getCGI} from './cgi.ts';\nimport {getFiles} from './upload.ts';\nimport {RequestError} from './requestError.ts';\nimport {isStringOrArrayOfString} from '../../util/type.ts';\nimport type {Request, Response} from 'express';\nimport type {Pool} from 'oracledb';\nimport type {argObjType, configPlSqlHandlerType, ProcedureNameCache, ArgumentCache} from '../../types.ts';\n\n/**\n *\tNormalize the body by making sure that only \"simple\" parameters and no nested objects are submitted\n *\t@param req - The req object represents the HTTP request.\n *\t@returns The normalized body.\n */\nconst normalizeBody = (req: Request): Record<string, string | string[]> => {\n\tconst args: Record<string, string | string[]> = {};\n\n\t/* v8 ignore else - body validation */\n\tif (typeof req.body === 'object' && req.body !== null) {\n\t\tconst body = req.body as Record<string, unknown>;\n\t\tfor (const key in body) {\n\t\t\tconst value = body[key];\n\t\t\t/* v8 ignore else - type validation */\n\t\t\tif (isStringOrArrayOfString(value)) {\n\t\t\t\targs[key] = value;\n\t\t\t} else {\n\t\t\t\t/* v8 ignore next - invalid body type */\n\t\t\t\tthrow new RequestError(\n\t\t\t\t\t`The element \"${key}\" in the body is not a string or an array of strings!\\n${util.inspect(req.body, {showHidden: false, depth: null, colors: false})}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn args;\n};\n\n/**\n * Execute the request\n *\n * @param req - The req object represents the HTTP request.\n * @param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n * @param options - the options for the middleware.\n * @param connectionPool - The connection pool.\n * @param procedureNameCache - The procedure name cache.\n * @param argumentCache - The argument cache.\n * @param authenticatedUser - The authenticated user identity.\n * @returns Promise resolving to th page\n */\nexport const processRequest = async (\n\treq: Request,\n\tres: Response,\n\toptions: configPlSqlHandlerType,\n\tconnectionPool: Pool,\n\tprocedureNameCache: ProcedureNameCache,\n\targumentCache: ArgumentCache,\n\tauthenticatedUser: string | null = null,\n): Promise<void> => {\n\tdebug('processRequest: ENTER');\n\n\tif (typeof req.params.name !== 'string') {\n\t\t// FIXME: this should be standartized\n\t\tconsole.warn(`processRequest: WARNING: the req.params.name is not a string but an array of string: ${req.params.name}`);\n\t}\n\n\t// open database connection\n\tconst connection = await connectionPool.getConnection();\n\n\ttry {\n\t\t// Get the CGI\n\t\tconst cgiObj = getCGI(req, options.documentTable, options.cgi ?? {}, authenticatedUser);\n\t\tdebug('processRequest: cgiObj=', cgiObj);\n\n\t\t// Does the request contain any files\n\t\tconst filesToUpload = getFiles(req);\n\t\tdebug('processRequest: filesToUpload=', filesToUpload);\n\n\t\t// Add the query properties\n\t\tconst argObj: argObjType = {};\n\t\t// oxlint-disable-next-line typescript/no-explicit-any, unicorn/no-immediate-mutation\n\t\tObject.assign(argObj, req.query as any);\n\n\t\t// For add the files that must be uploaded, we now copy the actual filename to the appropriate parameter to the invoked procedure.\n\t\tfilesToUpload.reduce((aggregator, file) => {\n\t\t\taggregator[file.fieldname] = file.filename;\n\t\t\treturn aggregator;\n\t\t}, argObj);\n\n\t\t// Does the request contain a body\n\t\tObject.assign(argObj, normalizeBody(req));\n\t\tdebug('processRequest: argObj=', argObj);\n\n\t\t// invoke the Oracle procedure and get the page contenst\n\t\tawait invokeProcedure(req, res, argObj, cgiObj, filesToUpload, options, connection, procedureNameCache, argumentCache);\n\n\t\t// transaction mode\n\t\tif (options.transactionMode === 'rollback') {\n\t\t\tdebug('transactionMode: rollback');\n\t\t\tawait connection.rollback();\n\t\t} else if (typeof options.transactionMode === 'function') {\n\t\t\tdebug('transactionMode: callback');\n\t\t\tconst procName = Array.isArray(req.params.name) ? req.params.name[0] : req.params.name;\n\t\t\tconst result = options.transactionMode(connection, procName ?? '');\n\t\t\tdebug('transactionMode: callback restult', result);\n\t\t\tif (result && typeof result.then === 'function') {\n\t\t\t\tawait result;\n\t\t\t}\n\t\t} else {\n\t\t\tdebug('transactionMode: commit');\n\t\t\tawait connection.commit();\n\t\t}\n\t} finally {\n\t\t// close database connection\n\t\tawait connection.release();\n\t}\n\n\tdebug('processRequest: EXIT');\n};","import * as rotatingFileStream from 'rotating-file-stream';\nimport {JSON_LOG_ROTATION_SIZE, JSON_LOG_ROTATION_INTERVAL, JSON_LOG_MAX_ROTATED_FILES} from '../../common/constants.ts';\nimport {type logEntryType} from '../types.ts';\nimport {type MakeOptional} from '../../common/typeUtilities.ts';\n\nexport class JsonLogger {\n\tstream: rotatingFileStream.RotatingFileStream;\n\n\tconstructor(filename = 'error.json.log') {\n\t\tthis.stream = rotatingFileStream.createStream(filename, {\n\t\t\tsize: JSON_LOG_ROTATION_SIZE, // rotate every 10 MegaBytes written\n\t\t\tinterval: JSON_LOG_ROTATION_INTERVAL, // rotate daily\n\t\t\tmaxFiles: JSON_LOG_MAX_ROTATED_FILES, // maximum number of rotated files to keep\n\t\t\tcompress: 'gzip', // compress rotated files\n\t\t});\n\t}\n\n\t/**\n\t * Log an entry as NDJSON.\n\t * @param entry - The entry to log.\n\t */\n\tlog(entry: MakeOptional<logEntryType, 'timestamp'>): void {\n\t\ttry {\n\t\t\t// Ensure timestamp exists\n\t\t\tentry.timestamp ??= new Date().toISOString();\n\t\t\tconst line = JSON.stringify(entry);\n\t\t\tthis.stream.write(line + '\\n');\n\t\t} catch (err) {\n\t\t\tconsole.error('JsonLogger: Failed to write log', err);\n\t\t}\n\t}\n\n\t/**\n\t * Close the stream.\n\t */\n\tclose(): void {\n\t\tthis.stream.end();\n\t}\n}\n\nexport const jsonLogger = new JsonLogger();","/*\n *\tError handling\n */\n\nimport {ProcedureError} from './procedureError.ts';\nimport {RequestError} from './requestError.ts';\nimport {getFormattedMessage, logToFile, type messageType} from '../../util/trace.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {getHtmlPage} from '../../util/html.ts';\nimport {jsonLogger} from '../../util/jsonLogger.ts';\nimport type {Request, Response} from 'express';\nimport type {environmentType, configPlSqlHandlerType} from '../../types.ts';\nimport type {BindParameters} from 'oracledb';\n\n/**\n *\tGet error data\n *\t@param req - The req object represents the HTTP request.\n *\t@param error - The error.\n *\t@returns The output.\n */\nconst getErrorData = (req: Request, error: unknown): messageType => {\n\tlet timestamp = new Date();\n\tlet message = '';\n\tlet environment: environmentType | null | undefined = null;\n\tlet sql: string | null | undefined = null;\n\tlet bind: BindParameters | null | undefined = null;\n\n\t// what type of Error did we receive\n\tif (error instanceof ProcedureError) {\n\t\ttimestamp = error.timestamp;\n\t\tmessage = error.stack ?? '';\n\t\tenvironment = error.environment;\n\t\tsql = error.sql;\n\t\tbind = error.bind;\n\t} else if (error instanceof RequestError) {\n\t\ttimestamp = error.timestamp;\n\t\tmessage = error.stack ?? '';\n\t} else if (error instanceof Error) {\n\t\tmessage = errorToString(error);\n\t} else {\n\t\tif (typeof error === 'string') {\n\t\t\tmessage = `${error}\\n`;\n\t\t}\n\t\t/* v8 ignore start - unreachable code: creating Error without throwing */\n\t\ttry {\n\t\t\t// oxlint-disable-next-line unicorn/error-message\n\t\t\tnew Error();\n\t\t} catch (err) {\n\t\t\tmessage += errorToString(err);\n\t\t}\n\t\t/* v8 ignore stop */\n\t}\n\n\treturn {type: 'error', timestamp, message, req, environment, sql, bind};\n};\n\n/**\n * Show an error page\n *\n * @param req - The req object represents the HTTP request.\n * @param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n * @param options - The configuration options.\n * @param error - The error.\n */\nexport const errorPage = (req: Request, res: Response, options: configPlSqlHandlerType, error: unknown): void => {\n\t// get error data\n\tconst errorData = getErrorData(req, error);\n\n\t// get formatted message\n\tconst {html, text} = getFormattedMessage(errorData);\n\n\t// trace to file\n\tlogToFile(text);\n\n\t// json log\n\tconst firstLine = errorData.message.split('\\n')[0];\n\tjsonLogger.log({\n\t\ttimestamp: errorData.timestamp?.toISOString() ?? new Date().toISOString(),\n\t\ttype: 'error',\n\t\tmessage: firstLine ?? '',\n\t\treq: {\n\t\t\tmethod: req.method,\n\t\t\turl: req.originalUrl,\n\t\t\tip: req.ip ?? '',\n\t\t\tuserAgent: req.get('user-agent') ?? '',\n\t\t},\n\t\tdetails: {\n\t\t\tfullMessage: errorData.message,\n\t\t\tsql: errorData.sql ?? '',\n\t\t\tbind: errorData.bind,\n\t\t\tenvironment: errorData.environment ?? {},\n\t\t},\n\t});\n\n\t// console\n\tconsole.error(text);\n\n\t// If headers have already been sent, we cannot show the error page\n\tif (res.headersSent) {\n\t\tconsole.warn('errorPage: Response headers already sent. Cannot show error page.');\n\t\treturn;\n\t}\n\n\t// show page\n\tif (options.errorStyle === 'basic') {\n\t\tres.status(404).send('Page not found');\n\t} else {\n\t\tres.status(404).send(getHtmlPage(html));\n\t}\n};","/*\n *\tExpress middleware for Oracle PL/SQL\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:handlerPlSql');\n\nimport {processRequest} from './request.ts';\nimport {RequestError} from './requestError.ts';\nimport {errorPage} from './errorPage.ts';\nimport {Cache} from '../../util/cache.ts';\nimport type {RequestHandler, Request, Response, NextFunction} from 'express';\nimport type {Pool} from 'oracledb';\nimport type {configPlSqlType, argsType} from '../../types.ts';\nimport type {AdminContext} from '../../server/adminContext.ts';\n\ntype WebPlSqlRequestHandler = RequestHandler & {\n\tprocedureNameCache: Cache<string>;\n\targumentCache: Cache<argsType>;\n};\n\n/**\n * express.Request handler\n * @param req - The req object represents the HTTP request.\n * @param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n * @param _next - The next function.\n * @param connectionPool - The connection pool.\n * @param options - the options for the middleware.\n * @param procedureNameCache - The procedure name cache.\n * @param argumentCache - The argument cache.\n */\nconst requestHandler = async (\n\treq: Request,\n\tres: Response,\n\t_next: NextFunction,\n\tconnectionPool: Pool,\n\toptions: configPlSqlType,\n\tprocedureNameCache: Cache<string>,\n\targumentCache: Cache<argsType>,\n): Promise<void> => {\n\ttry {\n\t\tlet authenticatedUser: string | null = null;\n\n\t\t// authentication logic\n\t\tif (options.auth?.type === 'basic') {\n\t\t\tconst b64auth = (req.headers.authorization ?? '').split(' ')[1] ?? '';\n\t\t\tconst [login, password] = Buffer.from(b64auth, 'base64').toString().split(':');\n\n\t\t\tif (login) {\n\t\t\t\tauthenticatedUser = await options.auth.callback({username: login, password}, connectionPool);\n\t\t\t}\n\n\t\t\tif (authenticatedUser === null) {\n\t\t\t\tconst realm = options.auth.realm ?? 'PL/SQL Gateway';\n\t\t\t\tres.set('WWW-Authenticate', `Basic realm=\"${realm}\"`);\n\t\t\t\tres.status(401).send('Authentication required.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else if (options.auth?.type === 'custom') {\n\t\t\tauthenticatedUser = await options.auth.callback(req, connectionPool);\n\n\t\t\tif (authenticatedUser === null) {\n\t\t\t\tres.status(401).send('Authentication required.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// should we switch to the default page if there is one defined\n\t\tif (typeof req.params.name !== 'string' || req.params.name.length === 0) {\n\t\t\tif (typeof options.defaultPage === 'string' && options.defaultPage.length > 0) {\n\t\t\t\tconst currentUrl = new URL(req.originalUrl, 'http://localhost');\n\t\t\t\tconst basePath = currentUrl.pathname.endsWith('/') ? currentUrl.pathname : `${currentUrl.pathname}/`;\n\t\t\t\tconst defaultPage = options.defaultPage.replace(/^\\/+/u, '');\n\t\t\t\tconst newUrl = `${basePath}${defaultPage}${currentUrl.search}`;\n\t\t\t\tdebug(`Redirect to the url \"${newUrl}\"`);\n\t\t\t\tres.redirect(newUrl);\n\t\t\t} else {\n\t\t\t\terrorPage(req, res, options, new RequestError('No procedure name given and no default page has been specified'));\n\t\t\t}\n\t\t} else {\n\t\t\t// request handler\n\t\t\tawait processRequest(req, res, options, connectionPool, procedureNameCache, argumentCache, authenticatedUser);\n\t\t}\n\t} catch (err) {\n\t\terrorPage(req, res, options, err);\n\t}\n};\n\n/**\n * Express middleware.\n *\n * @param connectionPool - The connection pool.\n * @param config - The configuration options.\n * @param adminContext - Optional admin context for self-registration and stats tracking.\n * @returns The handler.\n */\nexport const handlerWebPlSql = (\n\tconnectionPool: Pool,\n\tconfig: configPlSqlType,\n\tadminContext?: AdminContext,\n): WebPlSqlRequestHandler & {procedureNameCache: Cache<string>; argumentCache: Cache<argsType>} => {\n\tdebug('options', config);\n\n\tconst procedureNameCache = new Cache<string>();\n\tconst argumentCache = new Cache<argsType>();\n\n\t// Self-register with AdminContext\n\tif (adminContext) {\n\t\tadminContext.registerHandler(config.route, connectionPool, procedureNameCache, argumentCache);\n\t}\n\n\t/**\n\t * @param req - The request.\n\t * @param res - The response.\n\t * @param next - The next function.\n\t */\n\tconst handler = ((req: Request, res: Response, next: NextFunction) => {\n\t\tvoid requestHandler(req, res, next, connectionPool, config, procedureNameCache, argumentCache);\n\t}) as WebPlSqlRequestHandler;\n\n\thandler.procedureNameCache = procedureNameCache;\n\thandler.argumentCache = argumentCache;\n\n\treturn handler;\n};","import debugModule from 'debug';\nconst debug = debugModule('webplsql:handlerLogger');\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport morgan from 'morgan';\nimport type {RequestHandler} from 'express';\n\n/**\n * Create the upload middleware.\n * @param filename - Output filename.\n * @returns Request handler.\n */\nexport const handlerLogger = (filename: string): RequestHandler => {\n\tdebug('register');\n\n\treturn morgan('combined', {stream: fs.createWriteStream(path.join(process.cwd(), filename), {flags: 'a'})});\n};","import multer from 'multer';\nimport type {RequestHandler} from 'express';\n\n/**\n * Create the upload middleware.\n * @param uploadFileSizeLimit - Maximum size of each uploaded file in bytes or no limit if omitted.\n * @returns Request handler.\n */\nexport const handlerUpload = (uploadFileSizeLimit?: number): RequestHandler => {\n\tconst upload = multer({\n\t\tstorage: multer.diskStorage({}),\n\t\tlimits: {\n\t\t\tfileSize: uploadFileSizeLimit,\n\t\t},\n\t});\n\n\treturn upload.any();\n};","import express, {type Request, type Response, type Router} from 'express';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport readline from 'node:readline';\nimport type {AdminContext} from '../server/adminContext.ts';\nimport {traceManager} from '../util/traceManager.ts';\nimport {getVersion} from '../version.ts';\nimport {SHUTDOWN_GRACE_DELAY_MS} from '../../common/constants.ts';\nimport {forceShutdown} from '../util/shutdown.ts';\nimport {logEntrySchema, procedureTraceEntrySchema} from '../types.ts';\nimport {z} from 'zod';\n\nconst version = () => getVersion();\n\n/**\n * Helper to read last N lines of a file\n * @param filePath - Path to file\n * @param n - Number of lines\n * @param filter - Optional filter string\n * @returns The lines\n */\nconst readLastLines = async (filePath: string, n = 100, filter = ''): Promise<string[]> => {\n\tif (!fs.existsSync(filePath)) {\n\t\treturn [];\n\t}\n\n\tconst fileStream = fs.createReadStream(filePath);\n\tconst rl = readline.createInterface({\n\t\tinput: fileStream,\n\t\tcrlfDelay: Infinity,\n\t});\n\n\tconst filterLower = filter.toLowerCase();\n\n\tconst lines: string[] = [];\n\tfor await (const line of rl) {\n\t\tif (!filter || line.toLowerCase().includes(filterLower)) {\n\t\t\tlines.push(line);\n\t\t\tif (lines.length > n) {\n\t\t\t\tlines.shift();\n\t\t\t}\n\t\t}\n\t}\n\treturn lines;\n};\n\n/**\n * Create admin API router\n * @param adminContext - The admin context\n * @returns Express router\n */\nexport const createAdminRouter = (adminContext: AdminContext): Router => {\n\tconst router = express.Router();\n\n\t// GET /api/status\n\trouter.get('/api/status', (req: Request, res: Response) => {\n\t\tconst uptime = (Date.now() - adminContext.startTime.getTime()) / 1000;\n\t\tconst includeHistory = req.query.history === 'true';\n\t\tconst includeConfig = req.query.config === 'true';\n\n\t\tconst poolStats = adminContext.pools.map((pool, index) => {\n\t\t\tconst cache = adminContext.caches[index];\n\t\t\tconst name = cache?.poolName ?? `pool-${index}`;\n\t\t\tconst p = pool as {getStatistics?: () => unknown};\n\t\t\tconst stats = typeof p.getStatistics === 'function' ? p.getStatistics() : null;\n\t\t\tconst procStats = cache?.procedureNameCache?.getStats();\n\t\t\tconst argStats = cache?.argumentCache?.getStats();\n\n\t\t\treturn {\n\t\t\t\tname,\n\t\t\t\tstats,\n\t\t\t\tconnectionsOpen: pool.connectionsOpen,\n\t\t\t\tconnectionsInUse: pool.connectionsInUse,\n\t\t\t\tcache: {\n\t\t\t\t\tprocedureName: {\n\t\t\t\t\t\tsize: cache?.procedureNameCache?.keys().length ?? 0,\n\t\t\t\t\t\thits: procStats?.hits ?? 0,\n\t\t\t\t\t\tmisses: procStats?.misses ?? 0,\n\t\t\t\t\t},\n\t\t\t\t\targument: {\n\t\t\t\t\t\tsize: cache?.argumentCache?.keys().length ?? 0,\n\t\t\t\t\t\thits: argStats?.hits ?? 0,\n\t\t\t\t\t\tmisses: argStats?.misses ?? 0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\n\t\tconst memUsage = process.memoryUsage();\n\t\tconst systemMemoryUsed = os.totalmem() - os.freemem();\n\t\tconst cpuUsage = process.cpuUsage();\n\t\tconst summary = adminContext.statsManager.getSummary();\n\n\t\tconst history = adminContext.statsManager.getHistory();\n\t\t// If history is not requested, return only the last bucket for charts\n\t\tconst historyData = includeHistory ? history : history.slice(-1);\n\n\t\tres.json({\n\t\t\tversion: version(),\n\t\t\tstatus: adminContext.paused ? 'paused' : 'running',\n\t\t\tuptime,\n\t\t\tstartTime: adminContext.startTime,\n\t\t\tintervalMs: adminContext.statsManager.config.intervalMs,\n\t\t\tmetrics: {\n\t\t\t\trequestCount: summary.totalRequests,\n\t\t\t\terrorCount: summary.totalErrors,\n\t\t\t\tavgResponseTime: summary.avgResponseTime,\n\t\t\t\tminResponseTime: summary.minResponseTime,\n\t\t\t\tmaxResponseTime: summary.maxResponseTime,\n\t\t\t\tmaxRequestsPerSecond: summary.maxRequestsPerSecond,\n\t\t\t},\n\t\t\thistory: historyData,\n\t\t\tpools: poolStats,\n\t\t\tsystem: {\n\t\t\t\tnodeVersion: process.version,\n\t\t\t\tplatform: process.platform,\n\t\t\t\tarch: process.arch,\n\t\t\t\tcpuCores: os.cpus().length,\n\t\t\t\tmemory: {\n\t\t\t\t\trss: systemMemoryUsed,\n\t\t\t\t\theapTotal: memUsage.heapTotal,\n\t\t\t\t\theapUsed: memUsage.heapUsed,\n\t\t\t\t\texternal: memUsage.external,\n\t\t\t\t\ttotalMemory: os.totalmem(),\n\t\t\t\t\t...summary.maxMemory,\n\t\t\t\t},\n\t\t\t\tcpu: {\n\t\t\t\t\tuser: cpuUsage.user,\n\t\t\t\t\tsystem: cpuUsage.system,\n\t\t\t\t\tmax: summary.cpu.max,\n\t\t\t\t\tuserMax: summary.cpu.userMax,\n\t\t\t\t\tsystemMax: summary.cpu.systemMax,\n\t\t\t\t},\n\t\t\t},\n\t\t\tconfig:\n\t\t\t\tincludeConfig && adminContext.config\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...adminContext.config,\n\t\t\t\t\t\t\tadminPassword: adminContext.config.adminPassword ? '********' : undefined,\n\t\t\t\t\t\t\troutePlSql: adminContext.config.routePlSql.map((p) => {\n\t\t\t\t\t\t\t\tconst {auth, transactionMode, cgi, ...rest} = p;\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t...rest,\n\t\t\t\t\t\t\t\t\tpassword: '********',\n\t\t\t\t\t\t\t\t\thasAuth: !!auth,\n\t\t\t\t\t\t\t\t\thasTransactionMode: !!transactionMode,\n\t\t\t\t\t\t\t\t\thasCgi: !!cgi,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t});\n\t});\n\n\t// GET /api/stats/history\n\trouter.get('/api/stats/history', (req: Request, res: Response) => {\n\t\tconst limitQuery = req.query.limit;\n\t\tlet limit = 100;\n\t\tif (typeof limitQuery === 'string') {\n\t\t\tconst parsed = Number(limitQuery);\n\t\t\tif (!Number.isNaN(parsed)) {\n\t\t\t\tlimit = parsed;\n\t\t\t}\n\t\t}\n\n\t\tconst history = adminContext.statsManager.getHistory();\n\t\t// Return the last 'limit' entries, reversed (newest first)\n\t\t// Create a copy to avoid mutating the original history array\n\t\tconst slice = limit > 0 ? history.slice(-limit) : [...history];\n\t\tres.json(slice.toReversed());\n\t});\n\n\t// GET /api/logs/error\n\trouter.get('/api/logs/error', async (req: Request, res: Response) => {\n\t\ttry {\n\t\t\tconst limit = Number(req.query.limit) || 100;\n\t\t\tconst filter = typeof req.query.filter === 'string' ? req.query.filter : '';\n\t\t\tconst logFile = 'error.json.log';\n\t\t\tconst lines = await readLastLines(logFile, limit, filter);\n\t\t\tconst parsedLines = lines\n\t\t\t\t.map((line) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn JSON.parse(line) as unknown;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((l): l is unknown => l !== null);\n\t\t\tconst schema = z.array(logEntrySchema);\n\t\t\tconst logs = schema.safeParse(parsedLines);\n\t\t\tif (!logs.success) {\n\t\t\t\t// FIXME: this must be standardized\n\t\t\t\tthrow new Error(`Validation failed: ${logs.error.message}`);\n\t\t\t}\n\n\t\t\treturn res.json(logs.data.toReversed());\n\t\t} catch (err) {\n\t\t\treturn res.status(500).json({error: String(err)});\n\t\t}\n\t});\n\n\t// GET /api/logs/access\n\trouter.get('/api/logs/access', async (req: Request, res: Response) => {\n\t\ttry {\n\t\t\tconst limit = Number(req.query.limit) || 100;\n\t\t\tconst filter = typeof req.query.filter === 'string' ? req.query.filter : '';\n\t\t\tconst logFile = adminContext.config?.loggerFilename ?? 'access.log';\n\n\t\t\tif (!adminContext.config?.loggerFilename) {\n\t\t\t\tres.json({message: 'Access logging not enabled'});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst lines = await readLastLines(logFile, limit, filter);\n\t\t\tres.json(lines.toReversed());\n\t\t} catch (err) {\n\t\t\tres.status(500).json({error: String(err)});\n\t\t}\n\t});\n\n\t// POST /api/cache/clear\n\trouter.post('/api/cache/clear', (req: Request, res: Response) => {\n\t\tconst body = req.body as {poolName?: unknown} | null | undefined;\n\t\tconst poolName = typeof body?.poolName === 'string' ? body.poolName : undefined;\n\n\t\tlet cleared = 0;\n\t\tadminContext.caches.forEach((c) => {\n\t\t\tif (!poolName || c.poolName === poolName) {\n\t\t\t\tc.procedureNameCache.clear();\n\t\t\t\tcleared++;\n\t\t\t\tc.argumentCache.clear();\n\t\t\t\tcleared++;\n\t\t\t}\n\t\t});\n\n\t\tres.json({message: `Cleared ${cleared} caches`});\n\t});\n\n\t// POST /api/server/:action\n\trouter.post('/api/server/:action', (req: Request, res: Response) => {\n\t\tconst action = req.params.action;\n\n\t\tswitch (action) {\n\t\t\tcase 'stop': {\n\t\t\t\tres.json({message: 'Server shutting down...'});\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tforceShutdown();\n\t\t\t\t}, SHUTDOWN_GRACE_DELAY_MS);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'pause': {\n\t\t\t\tadminContext.setPaused(true);\n\t\t\t\tres.json({message: 'Server paused', status: 'paused'});\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'resume': {\n\t\t\t\tadminContext.setPaused(false);\n\t\t\t\tres.json({message: 'Server resumed', status: 'running'});\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tres.status(400).json({error: 'Invalid action'});\n\t\t\t}\n\t\t}\n\t});\n\n\t// GET /api/trace/status\n\trouter.get('/api/trace/status', (_req: Request, res: Response) => {\n\t\tres.json({enabled: traceManager.isEnabled()});\n\t});\n\n\t// POST /api/trace/toggle\n\trouter.post('/api/trace/toggle', (req: Request, res: Response) => {\n\t\tconst body = req.body as {enabled?: unknown} | null | undefined;\n\t\tconst enabled = typeof body?.enabled === 'boolean' ? body.enabled : false;\n\t\ttraceManager.setEnabled(enabled);\n\t\tres.json({enabled: traceManager.isEnabled()});\n\t});\n\n\t// GET /api/trace/logs\n\trouter.get('/api/trace/logs', async (req: Request, res: Response) => {\n\t\ttry {\n\t\t\tconst limit = Number(req.query.limit) || 100;\n\t\t\tconst filter = typeof req.query.filter === 'string' ? req.query.filter : '';\n\t\t\tconst logFile = traceManager.getFilePath();\n\t\t\tconst lines = await readLastLines(logFile, limit, filter);\n\t\t\tconst parsedLines = lines\n\t\t\t\t.map((line) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn JSON.parse(line) as unknown;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((l): l is unknown => l !== null);\n\t\t\tconst schema = z.array(procedureTraceEntrySchema);\n\t\t\tconst logs = schema.safeParse(parsedLines);\n\t\t\tif (!logs.success) {\n\t\t\t\t// FIXME: this must be standardized\n\t\t\t\tthrow new Error(`Validation failed: ${logs.error.message}`);\n\t\t\t}\n\n\t\t\treturn res.json(logs.data.toReversed());\n\t\t} catch (err) {\n\t\t\treturn res.status(500).json({error: String(err)});\n\t\t}\n\t});\n\n\t// POST /api/trace/clear\n\trouter.post('/api/trace/clear', (_req: Request, res: Response) => {\n\t\ttraceManager.clear();\n\t\tres.json({message: 'Traces cleared'});\n\t});\n\n\treturn router;\n};","import {Router, type Request, type Response, type NextFunction, type RequestHandler} from 'express';\nimport {existsSync} from 'node:fs';\nimport path from 'node:path';\nimport expressStaticGzip from 'express-static-gzip';\nimport type {AdminContext} from '../server/adminContext.ts';\nimport type {PoolSnapshot} from '../util/statsManager.ts';\nimport {createAdminRouter} from './handlerAdmin.ts';\n\n/**\n * Resolves the admin console static directory by walking up from the current module\n * to find the project root (identified by package.json), then returns dist/frontend path.\n * @returns Path to dist/frontend directory\n * @throws {Error} if project root cannot be found\n */\nexport const resolveAdminStaticDir = (): string => {\n\tconst __dirname = import.meta.dirname;\n\n\tlet projectRoot = __dirname;\n\twhile (!existsSync(path.join(projectRoot, 'package.json')) && projectRoot !== '/') {\n\t\tprojectRoot = path.dirname(projectRoot);\n\t}\n\n\tif (projectRoot === '/') {\n\t\tthrow new Error('Could not find project root (package.json). Please provide explicit staticDir in AdminConsoleConfig.');\n\t}\n\n\treturn path.join(projectRoot, 'dist', 'frontend');\n};\n\nexport type AdminConsoleConfig = {\n\t/** Base route for the admin console (defaults to '/admin') */\n\tadminRoute?: string | undefined;\n\t/** Path to built admin frontend directory (optional - auto-detects if omitted) */\n\tstaticDir?: string | undefined;\n\t/** Optional username for basic auth */\n\tuser?: string | undefined;\n\t/** Optional password for basic auth */\n\tpassword?: string | undefined;\n\t/** Skip static dir validation (for dev mode) */\n\tdevMode?: boolean | undefined;\n};\n\n/**\n * Creates the admin console middleware.\n * @param config - The admin console configuration.\n * @param adminContext - The admin context.\n * @returns The express request handler.\n */\nexport const handlerAdminConsole = (config: AdminConsoleConfig, adminContext: AdminContext): RequestHandler => {\n\tconst adminRoute = config.adminRoute ?? '/admin';\n\tconst resolvedStaticDir = config.staticDir ?? resolveAdminStaticDir();\n\n\t// Validation\n\tif (adminRoute && !adminRoute.startsWith('/')) {\n\t\tthrow new Error('adminRoute must start with /');\n\t}\n\n\tif (!config.devMode && !existsSync(resolvedStaticDir)) {\n\t\tthrow new Error(`Admin console not built. Run 'npm run build:frontend' first.\\nExpected: ${resolvedStaticDir}`);\n\t}\n\n\t// StatsManager hook - ensure we only wrap once\n\tconst statsManager = adminContext.statsManager;\n\t// oxlint-disable-next-line typescript/unbound-method\n\tconst currentRotate = statsManager.rotateBucket;\n\tif (!Object.prototype.hasOwnProperty.call(currentRotate, '_isWrapped')) {\n\t\t// oxlint-disable-next-line typescript/unbound-method\n\t\tconst originalRotate = statsManager.rotateBucket;\n\t\tconst wrappedRotate = (poolSnapshots: PoolSnapshot[] = []) => {\n\t\t\tconst currentSnapshots: PoolSnapshot[] = adminContext.pools.map((pool, index) => {\n\t\t\t\tconst cache = adminContext.caches[index];\n\t\t\t\tconst name = cache?.poolName ?? `pool-${index}`;\n\t\t\t\tconst procStats = cache?.procedureNameCache?.getStats();\n\t\t\t\tconst argStats = cache?.argumentCache?.getStats();\n\n\t\t\t\treturn {\n\t\t\t\t\tname,\n\t\t\t\t\tconnectionsOpen: pool.connectionsOpen,\n\t\t\t\t\tconnectionsInUse: pool.connectionsInUse,\n\t\t\t\t\tcache: {\n\t\t\t\t\t\tprocedureName: {\n\t\t\t\t\t\t\tsize: cache?.procedureNameCache?.keys().length ?? 0,\n\t\t\t\t\t\t\thits: procStats?.hits ?? 0,\n\t\t\t\t\t\t\tmisses: procStats?.misses ?? 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t\targument: {\n\t\t\t\t\t\t\tsize: cache?.argumentCache?.keys().length ?? 0,\n\t\t\t\t\t\t\thits: argStats?.hits ?? 0,\n\t\t\t\t\t\t\tmisses: argStats?.misses ?? 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\t\t\t// Merge snapshots if provided\n\t\t\tconst mergedSnapshots: PoolSnapshot[] = [...currentSnapshots];\n\t\t\tif (Array.isArray(poolSnapshots)) {\n\t\t\t\tfor (const ps of poolSnapshots) {\n\t\t\t\t\tif (!mergedSnapshots.some((s) => s.name === ps.name)) {\n\t\t\t\t\t\tmergedSnapshots.push(ps);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\toriginalRotate.call(statsManager, mergedSnapshots);\n\t\t};\n\t\tObject.defineProperty(wrappedRotate, '_isWrapped', {value: true, writable: false});\n\t\tstatsManager.rotateBucket = wrappedRotate;\n\t}\n\n\tconst router = Router();\n\n\t// Pause middleware\n\trouter.use((req: Request, res: Response, next: NextFunction) => {\n\t\tif (adminContext.paused && !req.path.startsWith(adminRoute)) {\n\t\t\tres.status(503).send('Server Paused');\n\t\t\treturn;\n\t\t}\n\t\tnext();\n\t});\n\n\t// Route filter - all following middleware only apply to adminRoute\n\trouter.use(adminRoute, (req: Request, res: Response, next: NextFunction) => {\n\t\t// Trailing slash redirect\n\t\tconst baseUrl = req.baseUrl || '';\n\t\tconst [path] = req.originalUrl.split('?');\n\n\t\tif (path === baseUrl) {\n\t\t\tconst query = req.originalUrl.split('?')[1];\n\t\t\treturn res.redirect(baseUrl + '/' + (query ? '?' + query : ''));\n\t\t}\n\t\tnext();\n\t});\n\n\t// Auth middleware\n\tif (config.user && config.password) {\n\t\trouter.use(adminRoute, (req: Request, res: Response, next: NextFunction) => {\n\t\t\tconst b64auth = (req.headers.authorization ?? '').split(' ')[1] ?? '';\n\t\t\tconst [login, password] = Buffer.from(b64auth, 'base64').toString().split(':');\n\n\t\t\tif (login !== config.user || password !== config.password) {\n\t\t\t\tres.set('WWW-Authenticate', 'Basic realm=\"Admin Console\"');\n\t\t\t\tres.status(401).send('Authentication required.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tnext();\n\t\t});\n\t}\n\n\t// Mount handlerAdmin API routes\n\trouter.use(adminRoute, createAdminRouter(adminContext));\n\n\t// Mount static files\n\tif (existsSync(resolvedStaticDir)) {\n\t\trouter.use(\n\t\t\tadminRoute,\n\t\t\texpressStaticGzip(resolvedStaticDir, {\n\t\t\t\tenableBrotli: true,\n\t\t\t\torderPreference: ['br'],\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn router;\n};","import path from 'node:path';\nimport {type Request, type Response, type NextFunction, type RequestHandler} from 'express';\n\n/**\n * Creates middleware that serves index.html for SPA routes.\n *\n * Handles React Router (createBrowserRouter), Vue Router, Angular Router, etc.\n *\n * **CRITICAL**: This middleware MUST be mounted AFTER express-static-gzip.\n *\n * Middleware order:\n * 1. express-static-gzip → Serves actual files (CSS, JS, images)\n * 2. handlerSpaFallback → Serves index.html for navigation requests\n *\n * @param directoryPath - Path to the static directory containing index.html\n * @param _route - The route prefix (for debugging)\n * @returns Express request handler\n *\n * @example\n * ```typescript\n * app.use('/app', expressStaticGzip('./build'));\n * app.use('/app', createSpaFallback('./build', '/app'));\n * ```\n */\nexport const createSpaFallback = (directoryPath: string, _route: string): RequestHandler => {\n\tconst indexPath = path.join(directoryPath, 'index.html');\n\n\treturn (req: Request, res: Response, next: NextFunction): void => {\n\t\t// Only handle GET/HEAD requests (standard browser navigation)\n\t\tif (req.method !== 'GET' && req.method !== 'HEAD') {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Check Accept header to avoid serving HTML for API/asset requests\n\t\tconst accept = req.headers.accept ?? '';\n\n\t\t// Skip if Accept header explicitly excludes HTML\n\t\t// Handles: Accept: application/json, image/*, text/css, etc.\n\t\tif (accept && !accept.includes('text/html') && !accept.includes('*/*')) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Send index.html for navigation requests\n\t\tres.sendFile(indexPath, (err) => {\n\t\t\tif (err) {\n\t\t\t\t// index.html missing - let Express handle 404\n\t\t\t\tnext(err);\n\t\t\t}\n\t\t});\n\t};\n};","import process from 'node:process';\nimport chalk from 'chalk';\n\n// Named aliases — chalk 16-color approximations, original ansi256 noted\nconst C = {\n\tred: chalk.ansi256(196), // chalk.redBright.bold\n\tgray: chalk.gray, // ansi256(245)\n\tdimGray: chalk.blackBright, // ansi256(240)\n\twhite: chalk.whiteBright, // ansi256(255)\n} as const;\n\n/**\n * Prints a formatted CLI error block to stderr with timestamp.\n *\n * @param message - Primary error description\n * @param meta - Optional metadata\n */\nexport const printError = (message: string, meta?: Record<string, string>): void => {\n\tconst ts = new Date()\n\t\t.toISOString()\n\t\t.replace('T', ' ')\n\t\t.replace(/(\\.\\d{3})Z$/u, '.$1 UTC');\n\n\tconst sep = C.dimGray('─'.repeat(48));\n\tconst header = `${C.red('✖ ERROR')} ${C.dimGray(ts)}`;\n\tconst body = C.white(message);\n\n\tconst defaultMeta: Record<string, string> = {\n\t\tpid: String(process.pid),\n\t\tnode: process.version,\n\t\t...meta,\n\t};\n\n\tconst footer = Object.entries(defaultMeta)\n\t\t.map(([k, v]) => `${C.dimGray(k)} ${C.gray(v)}`)\n\t\t.join(' ');\n\n\tconsole.error([sep, header, body, sep, footer].join('\\n'));\n};","/*\n *\tError handling\n */\n\nimport {logToFile} from './trace.ts';\nimport {printError} from './printError.ts';\nimport {errorToString} from './errorToString.ts';\nimport {jsonLogger} from './jsonLogger.ts';\n\n/**\n * Log an error.\n *\n * @param error - The error.\n */\nexport const logError = (error: unknown): void => {\n\tlet message = '';\n\n\t// what type of Error did we receive\n\tif (error instanceof Error) {\n\t\tmessage = errorToString(error);\n\t} else {\n\t\tif (typeof error === 'string') {\n\t\t\tmessage = error;\n\t\t}\n\t\t/* v8 ignore start - unreachable code: creating Error without throwing */\n\t\ttry {\n\t\t\t// oxlint-disable-next-line unicorn/error-message\n\t\t\tnew Error();\n\t\t} catch (err) {\n\t\t\tmessage += errorToString(err);\n\t\t}\n\t\t/* v8 ignore stop */\n\t}\n\n\t// trace to file\n\tlogToFile(message);\n\n\t// json log\n\tjsonLogger.log({\n\t\ttimestamp: new Date().toISOString(),\n\t\ttype: 'error',\n\t\tmessage,\n\t});\n\n\t// print error\n\tprintError(message);\n};"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["z","z","createPool","debug","oracledb.createPool","debug","debug","fs","debug","debug","debug","debug","debug","debug","debug","debug","debug","URL","debug","debug","z","process"],"sources":["../src/common/configStaticSchema.ts","../src/common/procedureTraceEntry.ts","../src/common/logEntrySchema.ts","../src/backend/types.ts","../src/backend/util/oracledb-mock.ts","../src/backend/util/oracledb-provider.ts","../src/backend/version.ts","../src/backend/server/printBanner.ts","../src/backend/server/server.ts","../src/backend/util/shutdown.ts","../src/common/constants.ts","../src/backend/util/statsManager.ts","../src/backend/server/adminContext.ts","../src/backend/util/file.ts","../src/backend/util/html.ts","../src/backend/util/trace.ts","../src/backend/util/errorToString.ts","../src/backend/handler/plsql/upload.ts","../src/backend/handler/plsql/procedureVariable.ts","../src/backend/handler/plsql/requestError.ts","../src/backend/util/util.ts","../src/backend/handler/plsql/procedureNamed.ts","../src/backend/handler/plsql/parsePage.ts","../src/backend/handler/plsql/sendResponse.ts","../src/backend/handler/plsql/procedureError.ts","../src/backend/util/cache.ts","../src/backend/handler/plsql/procedureSanitize.ts","../src/backend/handler/plsql/owaPageStream.ts","../src/backend/util/traceManager.ts","../src/backend/handler/plsql/procedure.ts","../src/backend/handler/plsql/cgi.ts","../src/backend/util/type.ts","../src/backend/handler/plsql/request.ts","../src/backend/util/jsonLogger.ts","../src/backend/handler/plsql/errorPage.ts","../src/backend/handler/plsql/handlerPlSql.ts","../src/backend/handler/handlerLogger.ts","../src/backend/handler/handlerUpload.ts","../src/backend/handler/handlerAdmin.ts","../src/backend/handler/handlerAdminConsole.ts","../src/backend/handler/handlerSpaFallback.ts","../src/backend/util/printError.ts","../src/backend/util/logError.ts"],"sourcesContent":["import z from 'zod';\n\n/**\n * Configuration for serving static files\n */\nexport const configStaticSchema = z.strictObject({\n\t/** URL route prefix for static assets */\n\troute: z.string(),\n\t/** Local filesystem path to the static assets directory */\n\tdirectoryPath: z.string(),\n\t/**\n\t * Enable SPA fallback mode.\n\t * When true, serves index.html for unmatched routes (for React Router, Vue Router, etc.)\n\t * Requires: Application uses HTML5 History Mode routing\n\t * Default: false\n\t */\n\tspaFallback: z.boolean().optional(),\n});\nexport type configStaticType = z.infer<typeof configStaticSchema>;","import {z} from 'zod';\n\nexport const procedureTraceEntrySchema = z.strictObject({\n\tid: z.string(),\n\ttimestamp: z.string(),\n\tsource: z.string(),\n\turl: z.string(),\n\tmethod: z.string(),\n\tstatus: z.string(),\n\tduration: z.number(),\n\tprocedure: z.string().optional(),\n\tparameters: z.union([z.record(z.string(), z.unknown()), z.array(z.unknown())]).optional(),\n\tuploads: z\n\t\t.array(\n\t\t\tz.strictObject({\n\t\t\t\toriginalname: z.string(),\n\t\t\t\tmimetype: z.string(),\n\t\t\t\tsize: z.number(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n\tdownloads: z\n\t\t.strictObject({\n\t\t\tfileType: z.string(),\n\t\t\tfileSize: z.number(),\n\t\t})\n\t\t.optional(),\n\thtml: z.string().optional(),\n\tcookies: z.record(z.string(), z.string()).optional(),\n\theaders: z.record(z.string(), z.string()).optional(),\n\tcgi: z.record(z.string(), z.string()).optional(),\n\terror: z.string().optional(),\n});\n\nexport type procedureTraceEntry = z.infer<typeof procedureTraceEntrySchema>;","import {z} from 'zod';\n\n/**\n * Error log entry schema.\n */\nconst logEntryTypeSchema = z.union([z.literal('error'), z.literal('info'), z.literal('warning')]);\nexport const logEntrySchema = z.strictObject({\n\ttimestamp: z.string(),\n\ttype: logEntryTypeSchema,\n\tmessage: z.string(),\n\treq: z\n\t\t.strictObject({\n\t\t\tmethod: z.string().optional(),\n\t\t\turl: z.string().optional(),\n\t\t\tip: z.string().optional(),\n\t\t\tuserAgent: z.string().optional(),\n\t\t})\n\t\t.optional(),\n\tdetails: z\n\t\t.strictObject({\n\t\t\tfullMessage: z.string().optional(),\n\t\t\tsql: z.string().optional(),\n\t\t\tbind: z.unknown().optional(),\n\t\t\tenvironment: z.record(z.string(), z.string()).optional(),\n\t\t})\n\t\t.optional(),\n});\nexport type logEntryType = z.infer<typeof logEntrySchema>;","import z from 'zod';\nimport {configStaticSchema} from '../common/configStaticSchema.ts';\nimport type {Connection, Pool} from 'oracledb';\nimport type {CookieOptions, Express, Request} from 'express';\nimport type {Readable} from 'node:stream';\nimport type {Cache} from './util/cache.ts';\n\nexport {procedureTraceEntrySchema, type procedureTraceEntry} from '../common/procedureTraceEntry.ts';\nexport {logEntrySchema, type logEntryType} from '../common/logEntrySchema.ts';\n\n/**\n * Defines the style of error reporting\n * 'basic': standard error messages\n * 'debug': detailed error messages including database context\n */\nconst z$errorStyleType = z.enum(['basic', 'debug']);\n\n/**\n * Custom callback signature for manual transaction handling\n */\ntype transactionCallbackType = (connection: Connection, procedure: string) => void | Promise<void>;\n\n/**\n * Defines how transactions are handled after procedure execution\n * 'commit': automatically commit\n * 'rollback': automatically rollback\n * callback: custom function for manual handling\n */\nconst transactionModeSchema = z.union([\n\tz.custom<transactionCallbackType>((val) => typeof val === 'function', {\n\t\tmessage: 'Invalid transaction callback',\n\t}),\n\tz.literal('commit'),\n\tz.literal('rollback'),\n\tz.undefined(),\n\tz.null(),\n]);\nexport type transactionModeType = z.infer<typeof transactionModeSchema>;\n\n/**\n * Basic authentication callback signature.\n * Returns the identity string on success, or null on failure.\n * @public\n */\nexport type BasicAuthCallback = (credentials: {username: string; password?: string | undefined}, connectionPool: Pool) => Promise<string | null>;\n\n/**\n * Custom authentication callback signature.\n * Returns the identity string on success, or null on failure.\n * @public\n */\nexport type CustomAuthCallback = (req: Request, connectionPool: Pool) => Promise<string | null>;\n\n/**\n * Authentication configuration for a PL/SQL route\n */\nconst z$authSchema = z.union([\n\tz.strictObject({\n\t\t/** Authentication type */\n\t\ttype: z.literal('basic'),\n\t\t/** Callback function to validate credentials */\n\t\tcallback: z.custom<BasicAuthCallback>((val) => typeof val === 'function', {\n\t\t\tmessage: 'Invalid auth callback',\n\t\t}),\n\t\t/** Authentication realm */\n\t\trealm: z.string().optional(),\n\t}),\n\tz.strictObject({\n\t\t/** Authentication type */\n\t\ttype: z.literal('custom'),\n\t\t/** Callback function to validate request */\n\t\tcallback: z.custom<CustomAuthCallback>((val) => typeof val === 'function', {\n\t\t\tmessage: 'Invalid auth callback',\n\t\t}),\n\t}),\n]);\n\n/**\n * PL/SQL handler behavior configuration\n */\nexport const z$configPlSqlHandlerType = z.strictObject({\n\t/** Default procedure to execute if none specified */\n\tdefaultPage: z.string(),\n\t/** Virtual path alias for procedures */\n\tpathAlias: z.string().optional(),\n\t/** Procedure name associated with the path alias */\n\tpathAliasProcedure: z.string().optional(),\n\t/** Database table used for file uploads/downloads */\n\tdocumentTable: z.string(),\n\t/** List of pattern/procedure names excluded from execution */\n\texclusionList: z.array(z.string()).optional(),\n\t/** PL/SQL function called to validate requests */\n\trequestValidationFunction: z.string().optional(),\n\t/** Post-execution transaction behavior */\n\ttransactionMode: transactionModeSchema.optional(),\n\t/** Error reporting style */\n\terrorStyle: z$errorStyleType,\n\t/** Static CGI environment variables to be passed to the session */\n\tcgi: z.record(z.string(), z.string()).optional(),\n\t/** Authentication settings */\n\tauth: z$authSchema.optional(),\n});\nexport type configPlSqlHandlerType = z.infer<typeof z$configPlSqlHandlerType>;\n\n/**\n * Database connection configuration for a PL/SQL route\n */\nconst z$configPlSqlConfigType = z.strictObject({\n\t/** URL route prefix for this database connection */\n\troute: z.string(),\n\t/** Database username */\n\tuser: z.string(),\n\t/** Database password */\n\tpassword: z.string(),\n\t/** Oracle connection string (TNS or EZConnect) */\n\tconnectString: z.string(),\n});\ntype configPlSqlConfigType = z.infer<typeof z$configPlSqlConfigType>;\n\n/**\n * Complete PL/SQL route configuration combining handler and connection settings\n */\nexport type configPlSqlType = configPlSqlHandlerType & configPlSqlConfigType;\nconst z$configPlSqlType = z.strictObject({\n\t...z$configPlSqlHandlerType.shape,\n\t...z$configPlSqlConfigType.shape,\n});\n\n/**\n * Root application configuration\n */\nexport const z$configType = z.strictObject({\n\t/** Server listening port */\n\tport: z.number(),\n\t/** Array of static file routes */\n\trouteStatic: z.array(configStaticSchema),\n\t/** Array of PL/SQL routes */\n\troutePlSql: z.array(z$configPlSqlType),\n\t/** Maximum allowed size for file uploads (bytes) */\n\tuploadFileSizeLimit: z.number().optional(),\n\t/** Path to the log file */\n\tloggerFilename: z.string(),\n\t/** URL route prefix for the admin console */\n\tadminRoute: z.string().optional(),\n\t/** Username for admin console authentication */\n\tadminUser: z.string().optional(),\n\t/** Password for admin console authentication */\n\tadminPassword: z.string().optional(),\n\t/** Developer mode (skips frontend build check, enables CORS) */\n\tdevMode: z.boolean().optional(),\n\t/** Callback function to setup custom Express extensions */\n\tsetupExtensions: z\n\t\t.custom<(app: Express, pools: Pool[]) => void | Promise<void>>((val) => typeof val === 'function', {\n\t\t\tmessage: 'Invalid setupExtensions callback',\n\t\t})\n\t\t.optional(),\n\toracle: z\n\t\t.strictObject({\n\t\t\tpoolMin: z.int().min(10).default(10),\n\t\t\tpoolMax: z.int().min(10).default(100),\n\t\t\tpoolIncrement: z.int().min(1).default(10),\n\t\t})\n\t\t.optional()\n\t\t.default({\n\t\t\tpoolMin: 10,\n\t\t\tpoolMax: 100,\n\t\t\tpoolIncrement: 10,\n\t\t}),\n});\nexport type configInputType = z.input<typeof z$configType>;\nexport type configType = z.output<typeof z$configType>;\n\n/**\n * Environment variables as string key-value pairs\n */\nexport type environmentType = Record<string, string>;\n\n/**\n * HTTP arguments mapping with support for multi-value parameters\n */\nexport type argObjType = Record<string, string | string[]>;\n\n/**\n * Mapping of PL/SQL procedure argument names to their database types\n */\nexport type argsType = Record<string, string>;\n\n/**\n * Metadata for uploaded files\n */\nexport type fileUploadType = {\n\t/** HTML form field name */\n\tfieldname: string;\n\t/** Original filename as uploaded by the client */\n\toriginalname: string;\n\t/** Content encoding */\n\tencoding: string;\n\t/** MIME type */\n\tmimetype: string;\n\t/** Local temporary filename */\n\tfilename: string;\n\t/** Absolute path to the temporary file */\n\tpath: string;\n\t/** File size in bytes */\n\tsize: number;\n};\n\n/**\n * HTTP cookie definition\n */\nexport type cookieType = {\n\t/** Cookie name */\n\tname: string;\n\t/** Cookie value */\n\tvalue: string;\n\t/** Express cookie options (domain, path, expires, etc.) */\n\toptions: CookieOptions;\n};\n\n/**\n * Internal representation of a generated web page or file response\n */\nexport type pageType = {\n\t/** Response body content as string or stream */\n\tbody: string | Readable;\n\t/** HTTP response headers and status */\n\thead: {\n\t\t/** Array of cookies to be set */\n\t\tcookies: cookieType[];\n\t\t/** Content-Type header value */\n\t\tcontentType?: string;\n\t\t/** Content-Length header value */\n\t\tcontentLength?: number;\n\t\t/** HTTP status code */\n\t\tstatusCode?: number;\n\t\t/** HTTP status reason phrase */\n\t\tstatusDescription?: string;\n\t\t/** Location header for redirects */\n\t\tredirectLocation?: string;\n\t\t/** Additional custom HTTP headers */\n\t\totherHeaders: Record<string, string>;\n\t\t/** Server header value */\n\t\tserver?: string;\n\t};\n\t/** Metadata for file downloads if applicable */\n\tfile: {\n\t\t/** MIME type of the file */\n\t\tfileType: string | null;\n\t\t/** Size of the file in bytes */\n\t\tfileSize: number | null;\n\t\t/** File content as stream or buffer */\n\t\tfileBlob: Readable | Buffer | null;\n\t};\n};\n\nexport type ProcedureNameCache = Cache<string>;\nexport type ArgumentCache = Cache<argsType>;","import type {Connection, Pool, Lob, Result, BindParameters, ExecuteOptions, DbType} from 'oracledb';\n\n// Mock implementation\nexport type ExecuteCallback = (sql: string, binds?: BindParameters) => Promise<Result<unknown>> | Result<unknown>;\nlet executeCallback: ExecuteCallback | null = null;\n\n/**\n * Test utility: Set the callback for execute calls.\n * @param cb - The callback\n */\nexport const setExecuteCallback = (cb: ExecuteCallback | null) => {\n\texecuteCallback = cb;\n};\n\n/**\n * Mock LOB class.\n */\nclass MockLob {\n\ttype: DbType | number;\n\tconstructor(type: DbType | number) {\n\t\tthis.type = type;\n\t}\n\t// oxlint-disable-next-line typescript/no-empty-function\n\tdestroy(): void {}\n}\n\n/**\n * Mock Connection class.\n */\nclass MockConnection {\n\tasync execute<T = unknown>(sql: string, bindParams?: BindParameters, _options?: ExecuteOptions): Promise<Result<T>> {\n\t\tif (executeCallback) {\n\t\t\treturn (await executeCallback(sql, bindParams)) as Result<T>;\n\t\t}\n\t\treturn {rows: []} as Result<T>;\n\t}\n\n\t// oxlint-disable-next-line typescript/require-await\n\tasync createLob(type: DbType | number): Promise<Lob> {\n\t\treturn new MockLob(type) as unknown as Lob;\n\t}\n\n\tasync commit(): Promise<void> {\n\t\t// empty\n\t}\n\tasync rollback(): Promise<void> {\n\t\t// empty\n\t}\n\tasync release(): Promise<void> {\n\t\t// empty\n\t}\n}\n\n/**\n * Mock Pool class.\n */\nclass MockPool {\n\tconnectionsOpen = 0;\n\tconnectionsInUse = 0;\n\n\t// oxlint-disable-next-line typescript/require-await\n\tasync getConnection(): Promise<Connection> {\n\t\tthis.connectionsInUse++;\n\t\tthis.connectionsOpen = Math.max(this.connectionsOpen, this.connectionsInUse);\n\t\treturn new MockConnection() as unknown as Connection;\n\t}\n\n\t// oxlint-disable-next-line typescript/require-await\n\tasync close(_drainTime?: number): Promise<void> {\n\t\tthis.connectionsOpen = 0;\n\t\tthis.connectionsInUse = 0;\n\t}\n}\n\n/**\n * Mock createPool function.\n * @param _config - The configuration\n * @returns The pool\n */\n// oxlint-disable-next-line typescript/require-await\nexport async function createPool(_config: unknown): Promise<Pool> {\n\treturn new MockPool() as unknown as Pool;\n}\n\n// Default export mimics oracledb module structure for test mocking\nexport default {\n\t// Constants will be merged from actual oracledb by vi.importActual in test_setup.ts\n\tcreatePool,\n\tsetExecuteCallback,\n};","import oracledb from 'oracledb';\n\nconst USE_MOCK = process.env.MOCK_ORACLE === 'true';\n\n/**\n * Create a database pool.\n * @param config - The pool attributes.\n * @returns The pool.\n */\n// Runtime switch for createPool\nexport async function createPool(config: oracledb.PoolAttributes): Promise<oracledb.Pool> {\n\tif (USE_MOCK) {\n\t\tconst mock = await import('./oracledb-mock.ts');\n\t\treturn mock.createPool(config);\n\t}\n\treturn await oracledb.createPool(config);\n}\n\n// Always export real oracledb constants (they're identical in mock)\nexport const BIND_IN = oracledb.BIND_IN;\nexport const BIND_OUT = oracledb.BIND_OUT;\nexport const BIND_INOUT = oracledb.BIND_INOUT;\nexport const STRING = oracledb.STRING;\nexport const NUMBER = oracledb.NUMBER;\nexport const DATE = oracledb.DATE;\nexport const CURSOR = oracledb.CURSOR;\nexport const BUFFER = oracledb.BUFFER;\nexport const CLOB = oracledb.CLOB;\nexport const BLOB = oracledb.BLOB;\nexport const DB_TYPE_VARCHAR = oracledb.DB_TYPE_VARCHAR;\nexport const DB_TYPE_CLOB = oracledb.DB_TYPE_CLOB;\nexport const DB_TYPE_NUMBER = oracledb.DB_TYPE_NUMBER;\nexport const DB_TYPE_DATE = oracledb.DB_TYPE_DATE;\n\n// Re-export types from real oracledb for convenience\nexport type {Connection, Pool, Lob, Result, BindParameter, BindParameters, ExecuteOptions, DbType} from 'oracledb';\n\n// Export mock-specific utilities\nexport {setExecuteCallback, type ExecuteCallback} from './oracledb-mock.ts';","declare global {\n\tvar __VERSION__: string;\n}\n\nglobalThis.__VERSION__ ??= '**development**';\n\ndeclare const __VERSION__: string;\n\n/**\n * Returns the current library version\n * @returns {string} - Version.\n */\nexport const getVersion = () => __VERSION__;","import chalk from 'chalk';\nimport stringWidth from 'string-width';\nimport sliceAnsi from 'slice-ansi';\nimport {getVersion} from '../version.ts';\nimport type {configType} from '../types.ts';\n\n// ── TTY\nconst IS_TTY = process.stdout.isTTY === true;\n\n// ── Icons\n// Authoritative form is the hex escape; emoji in comments are for readability only.\n// ICON_GEAR uses U+2699 without VS-16 (U+FE0F) intentionally — the variation selector\n// forces emoji presentation and makes string-width report width=2. Without it the\n// character is \"ambiguous\" and resolves to width=1 via the ambiguousIsNarrow option below.\nconst ICON_GLOBE = '\\u{1F310}'; // 🌐\nconst ICON_KEY = '\\u{1F511}'; // 🔑\nconst ICON_DOC = '\\u{1F4C4}'; // 📄\nconst ICON_PACKAGE = '\\u{1F4E6}'; // 📦\nconst ICON_LINK = '\\u{1F517}'; // 🔗\nconst ICON_FOLDER = '\\u{1F4C1}'; // 📁\nconst ICON_GEAR = '\\u{1F527}'; // 🔧\nconst ICON_HOME = '\\u{1F3E0}'; // 🏠\n\n// ── Layout\n// Each row: │(1) space(1) label(35) sep(1) value(40) space(1) │(1) = 80\nconst W = 80;\nconst LABEL_W = 35;\nconst VALUE_W = W - LABEL_W - 5; // 5 = left-border + left-space + separator + right-space + right-border\n\nconst BOX = {\n\th: '─',\n\tv: '│',\n\ttl: '╭',\n\ttr: '╮',\n\tbl: '╰',\n\tbr: '╯',\n\tml: '├',\n\tmr: '┤',\n} as const;\n\n/* Returns the visible terminal column-width of `s`. */\nconst displayWidth = (s: string): number => stringWidth(s, {ambiguousIsNarrow: true});\n\n/* Pads `s` with trailing spaces to `w` visible columns. Returns `s` unchanged if already ≥ `w`. */\nconst padTo = (s: string, w: number): string => {\n\tconst delta = w - displayWidth(s);\n\treturn delta > 0 ? s + ' '.repeat(delta) : s;\n};\n\n/* Truncates `s` to at most `w` visible columns. */\nconst truncateTo = (s: string, w: number): string => (w > 0 ? sliceAnsi(s, 0, w) : '');\n\n/* Mid-box horizontal divider. */\nconst divider = (): string => (IS_TTY ? chalk.dim(BOX.ml + BOX.h.repeat(W - 2) + BOX.mr) : '-'.repeat(W));\n\n/* Opening border. */\nconst borderOpen = (): string => (IS_TTY ? chalk.dim(BOX.tl + BOX.h.repeat(W - 2) + BOX.tr) : divider());\n\n/* Closing border. */\nconst borderClose = (): string => (IS_TTY ? chalk.dim(BOX.bl + BOX.h.repeat(W - 2) + BOX.br) : divider());\n\n/**\n * Single key/value row.\n * @param key - Label text.\n * @param value - Display value; null/undefined/empty renders as a dim dash.\n * @param icon - Optional leading icon (must be a single-cell or double-cell glyph).\n * @returns Formatted string.\n */\nconst row = (key: string, value: string | number | null | undefined, icon?: string): string => {\n\tconst left = IS_TTY ? (icon ? `${icon} ${key}` : ` ${key}`) : `${key}`;\n\tconst label = padTo(left, LABEL_W);\n\tconst hasValue = value !== null && value !== undefined && value !== '';\n\tconst valueText = hasValue ? String(value) : '—';\n\tconst colorFn = hasValue ? chalk.white : chalk.dim;\n\tconst valueCell = padTo(truncateTo(valueText, VALUE_W), VALUE_W);\n\n\treturn IS_TTY ? chalk.dim(BOX.v) + ' ' + chalk.dim(label) + ' ' + colorFn(valueCell) + ' ' + chalk.dim(BOX.v) : label + ' ' + valueCell;\n};\n\n/**\n * Renders the server startup banner to stdout.\n * @param cfg - Server configuration.\n */\nexport const printBanner = (cfg: configType): void => {\n\tconst adminRoute = cfg.adminRoute ?? '/admin';\n\tconst baseUrl = `http://localhost:${cfg.port}`;\n\tconst lines: string[] = [];\n\n\t// ── top border\n\tlines.push(borderOpen());\n\n\t// ── title\n\tconst title = `NODE PL/SQL SERVER ${getVersion()}`;\n\tconst pad = W - 2 - displayWidth(title);\n\tlines.push(IS_TTY ? chalk.dim(BOX.v) + ' '.repeat(Math.floor(pad / 2)) + chalk.bold.cyan(title) + ' '.repeat(Math.ceil(pad / 2)) + chalk.dim(BOX.v) : title);\n\tlines.push(divider());\n\n\t// ── server\n\tlines.push(row('Port', cfg.port, ICON_GLOBE));\n\tlines.push(row('Admin route', `${adminRoute}${cfg.adminUser ? ' (authenticated)' : ''}`, ICON_KEY));\n\tlines.push(row('Access log', cfg.loggerFilename, ICON_DOC));\n\tlines.push(row('Upload limit', typeof cfg.uploadFileSizeLimit === 'number' ? `${cfg.uploadFileSizeLimit} bytes` : null, ICON_PACKAGE));\n\tlines.push(divider());\n\n\t// ── connection pool\n\tlines.push(row('Oracle pool min', cfg.oracle.poolMin, ICON_LINK));\n\tlines.push(row('Oracle pool max', cfg.oracle.poolMax, ICON_LINK));\n\tlines.push(row('Oracle pool increment', cfg.oracle.poolIncrement, ICON_LINK));\n\n\t// ── static routes\n\tif (cfg.routeStatic.length > 0) {\n\t\tlines.push(divider());\n\t\tcfg.routeStatic.forEach((r, i) => {\n\t\t\tlines.push(row(`Static route #${i + 1} route`, r.route, ICON_FOLDER));\n\t\t\tlines.push(row(`Static route #${i + 1} path`, r.directoryPath));\n\t\t});\n\t}\n\n\t// ── PL/SQL routes\n\tif (cfg.routePlSql.length > 0) {\n\t\tlines.push(divider());\n\t\tcfg.routePlSql.forEach((r, i) => {\n\t\t\tconst txMode = typeof r.transactionMode === 'string' ? r.transactionMode : r.transactionMode ? 'custom' : '';\n\t\t\tconst n = `PL/SQL route #${i + 1}`;\n\n\t\t\tlines.push(row(`${n} route`, r.route, ICON_GEAR));\n\t\t\tlines.push(row(`${n} Oracle user`, r.user));\n\t\t\tlines.push(row(`${n} Oracle server`, r.connectString));\n\t\t\tlines.push(row(`${n} document table`, r.documentTable));\n\t\t\tlines.push(row(`${n} default page`, r.defaultPage));\n\t\t\tlines.push(row(`${n} path alias`, r.pathAlias ?? ''));\n\t\t\tlines.push(row(`${n} path alias proc`, r.pathAliasProcedure ?? ''));\n\t\t\tlines.push(row(`${n} exclusion list`, r.exclusionList?.join(', ') ?? ''));\n\t\t\tlines.push(row(`${n} validation fn`, r.requestValidationFunction ?? ''));\n\t\t\tlines.push(row(`${n} session mode`, txMode));\n\t\t\tlines.push(row(`${n} auth`, typeof r.auth === 'string' ? r.auth : ''));\n\t\t\tlines.push(row(`${n} error style`, r.errorStyle));\n\t\t});\n\t}\n\n\t// ── footer: quick-access URLs\n\tlines.push(divider());\n\tlines.push(row('Admin console', `${baseUrl}${adminRoute}`, ICON_HOME));\n\tcfg.routePlSql.forEach((r) => {\n\t\tlines.push(row(r.route, `${baseUrl}${r.route}`, ICON_GEAR));\n\t});\n\tlines.push(borderClose());\n\n\tconsole.log(lines.join('\\n'));\n};","import debugModule from 'debug';\nconst debug = debugModule('webplsql:server');\n\nimport http from 'node:http';\nimport https from 'node:https';\nimport type {Socket} from 'node:net';\n\nimport express, {type Express, type Request, type Response, type NextFunction} from 'express';\nimport type {Pool} from 'oracledb';\nimport cors from 'cors';\nimport cookieParser from 'cookie-parser';\nimport compression from 'compression';\nimport expressStaticGzip from 'express-static-gzip';\n\n// NOTE: it is only allowed to import from the API './index.ts'\nimport {\n\thandlerWebPlSql,\n\thandlerAdminConsole,\n\thandlerUpload,\n\thandlerLogger,\n\tAdminContext,\n\tprintBanner,\n\treadFileSyncUtf8,\n\tgetJsonFile,\n\tinstallShutdown,\n\tz$configType,\n\ttype configInputType,\n\ttype configType,\n\ttype configPlSqlType,\n\toracledb,\n\tcreateSpaFallback,\n} from '../index.ts';\n\n/**\n * Close multiple pools.\n * @param pools - The pools to close.\n */\nexport const poolsClose = async (pools: Pool[]): Promise<void> => {\n\tawait Promise.all(pools.map((pool) => pool.close(0)));\n};\n\nexport type webServer = {\n\tconfig: configType;\n\tconnectionPools: Pool[];\n\tapp: Express;\n\tserver: http.Server | https.Server;\n\tadminContext: AdminContext;\n\tshutdown: () => Promise<void>;\n};\n\nexport type sslConfig = {\n\tkeyFilename: string;\n\tcertFilename: string;\n};\n\n/**\n * Create HTTPS server.\n * @param app - express application\n * @param ssl - ssl configuration.\n * @returns server\n */\nexport const createServer = (app: Express, ssl?: sslConfig): http.Server | https.Server => {\n\tif (ssl) {\n\t\tconst key = readFileSyncUtf8(ssl.keyFilename);\n\t\tconst cert = readFileSyncUtf8(ssl.certFilename);\n\n\t\treturn https.createServer({key, cert}, app);\n\t} else {\n\t\treturn http.createServer(app);\n\t}\n};\n\n/**\n * Start server.\n * @param config - The config.\n * @param ssl - ssl configuration.\n * @returns Promise resolving to the web server object.\n */\nexport const startServer = async (config: configInputType, ssl?: sslConfig): Promise<webServer> => {\n\tdebug('startServer: BEGIN', config, ssl);\n\n\tconst internalConfig = z$configType.parse(config);\n\n\tprintBanner(internalConfig);\n\n\t// Create express app\n\tconst app = express();\n\n\t// Default middleware\n\tif (internalConfig.devMode) {\n\t\tapp.use(\n\t\t\tcors({\n\t\t\t\torigin: 'http://localhost:5173',\n\t\t\t\tcredentials: true,\n\t\t\t}),\n\t\t);\n\t}\n\tapp.use(handlerUpload(internalConfig.uploadFileSizeLimit));\n\tapp.use(express.json({limit: '50mb'}));\n\tapp.use(express.urlencoded({limit: '50mb', extended: true}));\n\tapp.use(cookieParser());\n\tapp.use(compression());\n\n\t// Create AdminContext\n\tconst adminContext = new AdminContext(internalConfig);\n\n\t// Mount Admin Console (includes Pause middleware)\n\tapp.use(\n\t\thandlerAdminConsole(\n\t\t\t{\n\t\t\t\tadminRoute: internalConfig.adminRoute,\n\t\t\t\tuser: internalConfig.adminUser,\n\t\t\t\tpassword: internalConfig.adminPassword,\n\t\t\t\tdevMode: internalConfig.devMode,\n\t\t\t},\n\t\t\tadminContext,\n\t\t),\n\t);\n\n\t// Oracle pl/sql express middleware\n\tfor (const i of internalConfig.routePlSql) {\n\t\t// Allocate the Oracle database pool\n\t\tconst pool = await oracledb.createPool({\n\t\t\tuser: i.user,\n\t\t\tpassword: i.password,\n\t\t\tconnectString: i.connectString,\n\t\t\tpoolMin: internalConfig.oracle.poolMin,\n\t\t\tpoolMax: internalConfig.oracle.poolMax,\n\t\t\tpoolIncrement: internalConfig.oracle.poolIncrement,\n\t\t});\n\n\t\tconst handler = handlerWebPlSql(pool, i as configPlSqlType, adminContext);\n\n\t\tapp.use([`${i.route}/:name`, i.route], (req: Request, res: Response, next: NextFunction) => {\n\t\t\tconst start = process.hrtime();\n\t\t\tres.on('finish', () => {\n\t\t\t\tconst diff = process.hrtime(start);\n\t\t\t\tconst duration = diff[0] * 1000 + diff[1] / 1_000_000;\n\t\t\t\tadminContext.statsManager.recordRequest(duration, res.statusCode >= 400);\n\t\t\t});\n\t\t\thandler(req, res, next);\n\t\t});\n\t}\n\n\t// Access log\n\tif (internalConfig.loggerFilename.length > 0) {\n\t\tapp.use(handlerLogger(internalConfig.loggerFilename));\n\t}\n\n\t// Execute custom extensions before static/SPA routes capture the request\n\tif (internalConfig.setupExtensions) {\n\t\tawait internalConfig.setupExtensions(app, adminContext.pools);\n\t}\n\n\t// Serving static files\n\tfor (const i of internalConfig.routeStatic) {\n\t\tapp.use(\n\t\t\ti.route,\n\t\t\texpressStaticGzip(i.directoryPath, {\n\t\t\t\tenableBrotli: true,\n\t\t\t\torderPreference: ['br'],\n\t\t\t}),\n\t\t);\n\n\t\t// Mount SPA fallback (serves index.html for unmatched routes)\n\t\t// IMPORTANT: Must come AFTER expressStaticGzip\n\t\tif (i.spaFallback) {\n\t\t\tapp.use(i.route, createSpaFallback(i.directoryPath, i.route));\n\t\t}\n\t}\n\n\t// Mount PL/SQL handlers with stats tracking\n\t// (already mounted in the loop above)\n\n\t// create server\n\tdebug('startServer: createServer');\n\tconst server = createServer(app, ssl);\n\n\t// Track open connections\n\tconst connections = new Set<Socket>();\n\tserver.on('connection', (socket: Socket) => {\n\t\tconnections.add(socket);\n\t\tsocket.on('close', () => {\n\t\t\tconnections.delete(socket);\n\t\t});\n\t});\n\n\tconst closeAllConnections = () => {\n\t\tfor (const socket of connections) {\n\t\t\tsocket.destroy(); // forcibly closes the connection\n\t\t\tconnections.delete(socket);\n\t\t}\n\t};\n\n\tconst shutdown = async () => {\n\t\tdebug('startServer: onShutdown');\n\n\t\tadminContext.statsManager.stop();\n\n\t\tawait poolsClose(adminContext.pools);\n\n\t\tserver.close(() => {\n\t\t\tconsole.log('Server has closed');\n\t\t\tprocess.exit(0);\n\t\t});\n\n\t\tcloseAllConnections();\n\t};\n\n\t// Install shutdown handler\n\tinstallShutdown(shutdown);\n\n\t// Listen\n\tdebug('startServer: start listener');\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver\n\t\t\t.listen(internalConfig.port)\n\t\t\t.on('listening', () => {\n\t\t\t\tdebug('startServer: listener running');\n\t\t\t\tresolve();\n\t\t\t})\n\t\t\t.on('error', (err: NodeJS.ErrnoException) => {\n\t\t\t\tif ('code' in err) {\n\t\t\t\t\tif (err.code === 'EADDRINUSE') {\n\t\t\t\t\t\terr.message = `Port ${internalConfig.port} is already in use`;\n\t\t\t\t\t} else if (err.code === 'EACCES') {\n\t\t\t\t\t\terr.message = `Port ${internalConfig.port} requires elevated privileges`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treject(err);\n\t\t\t});\n\t});\n\n\tdebug('startServer: END');\n\n\treturn {\n\t\tconfig: internalConfig,\n\t\tconnectionPools: adminContext.pools,\n\t\tapp,\n\t\tserver,\n\t\tadminContext,\n\t\tshutdown,\n\t};\n};\n\n/**\n * Load configuration.\n * @param filename - The configuration filename.\n * @returns Promise.\n */\nexport const loadConfig = (filename = 'config.json'): configType => z$configType.parse(getJsonFile(filename));\n\n/**\n * Start server from config file.\n * @param filename - The configuration filename.\n * @param ssl - ssl configuration.\n * @returns Promise resolving to the web server object.\n */\nexport const startServerConfig = async (filename = 'config.json', ssl?: sslConfig): Promise<webServer> => startServer(loadConfig(filename), ssl);","import debugModule from 'debug';\nconst debug = debugModule('webplsql:shutdown');\n\n/**\n * Install a shutdown handler.\n * @param handler - Shutdown handler\n */\nexport const installShutdown = (handler: () => Promise<void>): void => {\n\tdebug('installShutdown');\n\n\tlet isShuttingDown = false;\n\n\t/*\n\t *\tThe 'unhandledRejection' event is emitted whenever a Promise is rejected and no error handler is attached to the promise within a turn of the event loop.\n\t */\n\tprocess.on('unhandledRejection', (reason) => {\n\t\tif (isShuttingDown) {\n\t\t\treturn;\n\t\t}\n\t\tisShuttingDown = true;\n\n\t\tif (reason instanceof Error) {\n\t\t\tconsole.error(`\\n${reason.message}. Graceful shutdown...`);\n\t\t} else {\n\t\t\tconsole.error('\\nUnhandled promise rejection. Graceful shutdown...', reason);\n\t\t}\n\t\tvoid handler().catch((err: unknown) => {\n\t\t\tconsole.error('Error during shutdown:', err);\n\t\t\tprocess.exit(1);\n\t\t});\n\t});\n\n\t// install signal event handler\n\tprocess.on('SIGTERM', function sigterm() {\n\t\tif (isShuttingDown) {\n\t\t\treturn;\n\t\t}\n\t\tisShuttingDown = true;\n\n\t\tconsole.log('\\nGot SIGTERM (aka docker container stop). Graceful shutdown...');\n\t\tvoid handler().catch((err: unknown) => {\n\t\t\tconsole.error('Error during shutdown:', err);\n\t\t\tprocess.exit(1);\n\t\t});\n\t});\n\n\tprocess.on('SIGINT', function sigint() {\n\t\tif (isShuttingDown) {\n\t\t\treturn;\n\t\t}\n\t\tisShuttingDown = true;\n\n\t\tconsole.log('\\nGot SIGINT (aka ctrl-c in docker). Graceful shutdown...');\n\t\tvoid handler().catch((err: unknown) => {\n\t\t\tconsole.error('Error during shutdown:', err);\n\t\t\tprocess.exit(1);\n\t\t});\n\t});\n};\n\n/**\n * Force a shutdown.\n */\nexport const forceShutdown = (): void => {\n\tdebug('forceShutdown');\n\n\tprocess.kill(process.pid, 'SIGTERM');\n};","/**\n * Web PL/SQL Gateway - Common Shared Constants\n *\n * This file centralizes all hardcoded numeric and string constants used throughout\n * the application. Constants are organized by functional category.\n */\n\n// =============================================================================\n// CACHE CONFIGURATION\n// =============================================================================\n\n/**\n * DEFAULT_CACHE_MAX_SIZE = 10000\n *\n * Purpose: Maximum number of entries in the generic LFU (Least Frequently Used) cache.\n *\n * Used By:\n * - procedureNameCache: Caches resolved Oracle procedure names (e.g., \"HR.EMPLOYEES\")\n * - argumentCache: Caches procedure argument introspection results from all_arguments view\n *\n * Related Values:\n * - CACHE_PRUNE_PERCENT (0.1): When cache is full, removes 10% = 1000 entries\n * - Cache instantiation in src/handler/plsql/handlerPlSql.js creates new Cache() without params\n *\n * Implications:\n * - Memory footprint: ~1-2MB at max capacity (strings + hitCount metadata)\n * - Pruning: Removes least-frequently-used entries when full\n * - Higher values = better cache hit rates but more memory\n */\nexport const DEFAULT_CACHE_MAX_SIZE = 10_000;\n\n/**\n * CACHE_PRUNE_PERCENT = 0.1\n *\n * Purpose: Fraction of cache entries to remove during pruning (10%).\n *\n * Used By: Cache.prune() method only\n *\n * Related Values:\n * - DEFAULT_CACHE_MAX_SIZE (10000): Applied to this value to calculate removeCount = 1000\n *\n * Implications:\n * - Balances between removing too few entries (frequent pruning) vs too many (evicting useful data)\n * - 10% is a common pattern for cache eviction\n */\nexport const CACHE_PRUNE_PERCENT = 0.1;\n\n// =============================================================================\n// ORACLE LIMITS\n// =============================================================================\n\n/**\n * MAX_PROCEDURE_PARAMETERS = 1000\n *\n * Purpose: Maximum number of procedure arguments that can be introspected from Oracle's\n * all_arguments view using BULK COLLECT with dbms_utility.name_resolve.\n *\n * Used By:\n * - src/handler/plsql/procedureNamed.js\n * bind.names = {maxArraySize: MAX_PARAMETER_NUMBER}\n * bind.types = {maxArraySize: MAX_PARAMETER_NUMBER}\n *\n * Related Values:\n * - Procedure introspection SQL: SQL_GET_ARGUMENT block at procedureNamed.js:27-43\n * - oracledb.BIND_OUT direction for array fetches\n *\n * Implications:\n * - This is an Oracle driver limitation for array binding, not an arbitrary choice\n * - Procedures with >1000 arguments will have introspection truncated\n * - No error handling exists for this edge case\n * - Practical limit: most procedures have <50 arguments\n */\nexport const MAX_PROCEDURE_PARAMETERS = 1000;\n\n/**\n * OWA_STREAM_CHUNK_SIZE = 1000\n *\n * Purpose: Number of lines fetched per Oracle OWA call when streaming page content.\n *\n * Used By:\n * - owaPageStream.js: maxArraySize for :lines bind variable\n * - owaPageStream.js: :irows INOUT parameter value\n * - owaPageStream.js: Determines when streaming is complete (lines.length < chunkSize)\n *\n * Related Values:\n * - OWA_GET_PAGE_SQL: 'BEGIN owa.get_page(thepage=>:lines, irows=>:irows); END;'\n * - OWAPageStream class constructor at line 20\n *\n * Implications:\n * - Controls round-trip frequency to Oracle database\n * - Higher = fewer round-trips but larger memory buffers per fetch\n * - Lower = more responsive streaming but more database calls\n * - Each line is a PL/SQL varchar2; total data per chunk depends on htp.htbuf_len (63 chars)\n * - Estimated max data per chunk: 1000 lines × 63 chars = 63KB\n */\nexport const OWA_STREAM_CHUNK_SIZE = 1000;\n\n// =============================================================================\n// STREAMING\n// =============================================================================\n\n/**\n * OWA_STREAM_BUFFER_SIZE = 16384\n *\n * Purpose: Node.js Readable stream highWaterMark in bytes (16KB).\n *\n * Used By: OWAPageStream class extends Readable stream\n *\n * Related Values:\n * - OWA_STREAM_CHUNK_SIZE (1000): Lines per fetch\n * - Default Node.js highWaterMark is 64KB (Readable stream default)\n * - OWAPageStream.push() converts lines to string buffer\n *\n * Implications:\n * - Smaller than default (64KB) = more frequent _read() callbacks\n * - Reduces memory footprint for large responses\n * - Improves backpressure handling responsiveness\n * - Trade-off: More CPU for _read() calls vs memory efficiency\n */\nexport const OWA_STREAM_BUFFER_SIZE = 16_384;\n\n/**\n * OWA_RESOLVED_NAME_MAX_LEN = 400\n *\n * Purpose: Maximum string length for resolved Oracle procedure canonical names.\n * Canonical format: SCHEMA.PACKAGE.PROCEDURE or SCHEMA.PROCEDURE.\n *\n * Used By:\n * - resolveProcedureName() function for dbms_utility.name_resolve output\n * - Procedure name resolution SQL at procedureSanitize.js:46-76\n *\n * Related Values:\n * - dbms_utility.name_resolve context = 1 (procedure/function resolution)\n * - Oracle identifier limits: Schema (128) + Package (128) + Procedure (128) + 2 dots = ~386\n * - 400 provides comfortable headroom\n *\n * Implications:\n * - Oracle object names: 30 bytes for most, extended to 128 in some contexts\n * - Canonical name: schema.package.procedure (max ~128+1+128+1+128 = 386)\n * - 400 is safe upper bound with margin\n */\nexport const OWA_RESOLVED_NAME_MAX_LEN = 400;\n\n// =============================================================================\n// STATS COLLECTION\n// =============================================================================\n\n/**\n * STATS_INTERVAL_MS = 5000\n *\n * Purpose: Duration of each statistical bucket in milliseconds.\n *\n * Used By:\n * - src/util/statsManager.js:165: setInterval(this.rotateBucket, this.config.intervalMs)\n * - src/handler/handlerAdmin.js:123: Exposed as intervalMs in /api/status response\n * - src/frontend/main.ts\n * - src/frontend/charts.ts\n *\n * Related Values:\n * - MAX_HISTORY_BUCKETS (1000): At 5s per bucket = ~83 minutes of history\n * - MAX_PERCENTILE_SAMPLES (1000): Samples per bucket for P95/P99\n *\n * Implications:\n * - Bucket aggregation: request counts, durations, errors, system metrics\n * - Affects granularity of performance monitoring\n * - Lower values = more granular but more history entries\n * - Higher values = smoother averages but less detail\n */\nexport const STATS_INTERVAL_MS = 5000;\n\n/**\n * MAX_HISTORY_BUCKETS = 1000\n *\n * Purpose: Maximum number of statistical buckets retained in StatsManager ring buffer.\n *\n * Used By:\n * - src/util/statsManager.js: Ring buffer limit check\n * if (this.history.length > this.config.maxHistoryPoints) { this.history.shift(); }\n * - Exposed via /api/stats/history endpoint\n *\n * Related Values:\n * - STATS_INTERVAL_MS (5000): 5s per bucket = ~83 minutes total history\n * - Each bucket contains: timestamp, requestCount, errors, durations, system metrics\n * - Bucket memory estimate: ~100 bytes × 1000 = ~100KB\n *\n * Implications:\n * - Ring buffer: oldest bucket is removed when new one exceeds limit\n * - Affects admin console chart history display\n * - Higher = more historical context but more memory\n */\nexport const MAX_HISTORY_BUCKETS = 1000;\n\n/**\n * MAX_PERCENTILE_SAMPLES = 1000\n *\n * Purpose: Maximum number of request duration samples collected per bucket\n * for calculating P95/P99 percentiles.\n *\n * Used By:\n * - src/util/statsManager.js: Array length check\n * if (b.durations.length < this.config.percentilePrecision)\n * - src/util/statsManager.js: P95/P99 calculation\n *\n * Related Values:\n * - Percentile calculation: floor(length × 0.95) and floor(length × 0.99)\n * - FIFO replacement: When exceeded, new samples replace oldest\n *\n * Implications:\n * - With 1000 samples, P95/P99 are statistically meaningful\n * - Higher = more accurate percentiles but more memory per bucket\n * - With STATS_INTERVAL_MS = 5000, 1000 samples ≈ 5 req/sec sustained\n * - Under heavy load, older samples are discarded (FIFO)\n */\nexport const MAX_PERCENTILE_SAMPLES = 1000;\n\n// =============================================================================\n// SHUTDOWN\n// =============================================================================\n\n/**\n * SHUTDOWN_GRACE_DELAY_MS = 100\n *\n * Purpose: Delay between initiating server shutdown and forced termination.\n *\n * Used By: POST /api/server/stop handler only\n *\n * Related Values:\n * - forceShutdown() at src/util/shutdown.js\n * - SIGTERM/SIGINT handlers at shutdown.js\n *\n * Implications:\n * - Allows graceful completion of in-flight requests\n * - Gives Express middleware time to send final responses\n * - 100ms is short; may be insufficient under heavy load\n * - Consider making configurable for high-traffic deployments\n */\nexport const SHUTDOWN_GRACE_DELAY_MS = 100;\n\n// =============================================================================\n// LOG ROTATION - TRACE\n// =============================================================================\n\n/**\n * TRACE_LOG_ROTATION_SIZE = '10M'\n *\n * Purpose: Log file size threshold triggering trace log rotation (10 Megabytes).\n *\n * Used By: rotating-file-stream library for 'trace.log'\n *\n * Related Values:\n * - TRACE_LOG_ROTATION_INTERVAL ('1d'): Also triggers rotation\n * - TRACE_LOG_MAX_ROTATED_FILES (10): Maximum retained files\n *\n * Implications:\n * - When either size OR time threshold is reached, rotation occurs\n * - Combined with daily rotation: ~10MB/day minimum\n * - gzip compression reduces rotated file size by ~70-90%\n */\nexport const TRACE_LOG_ROTATION_SIZE = '10M';\n\n/**\n * TRACE_LOG_ROTATION_INTERVAL = '1d'\n *\n * Purpose: Time-based trace log rotation trigger (daily).\n *\n * Used By: rotating-file-stream library for 'trace.log'\n *\n * Implications:\n * - Guarantees at least one rotation per day\n * - Midnight-based or 24h from first write\n */\nexport const TRACE_LOG_ROTATION_INTERVAL = '1d';\n\n/**\n * TRACE_LOG_MAX_ROTATED_FILES = 10\n *\n * Purpose: Maximum number of rotated trace log files to retain.\n *\n * Used By: rotating-file-stream library for 'trace.log'\n *\n * Implications:\n * - When exceeded, oldest rotated file is deleted\n * - Maximum: ~10 files × 10MB = ~100MB (compressed: ~10-30MB)\n */\nexport const TRACE_LOG_MAX_ROTATED_FILES = 10;\n\n// =============================================================================\n// LOG ROTATION - JSON\n// =============================================================================\n\n/**\n * JSON_LOG_ROTATION_SIZE = '10M'\n *\n * Purpose: Log file size threshold triggering JSON error log rotation (10 Megabytes).\n *\n * Used By: rotating-file-stream library for 'error.json.log'\n *\n * Related Values:\n * - JSON_LOG_ROTATION_INTERVAL ('1d'): Also triggers rotation\n * - JSON_LOG_MAX_ROTATED_FILES (10): Maximum retained files\n *\n * Implications:\n * - When either size OR time threshold is reached, rotation occurs\n * - Combined with daily rotation: ~10MB/day minimum\n * - gzip compression reduces rotated file size by ~70-90%\n */\nexport const JSON_LOG_ROTATION_SIZE = '10M';\n\n/**\n * JSON_LOG_ROTATION_INTERVAL = '1d'\n *\n * Purpose: Time-based JSON error log rotation trigger (daily).\n *\n * Used By: rotating-file-stream library for 'error.json.log'\n *\n * Implications:\n * - Guarantees at least one rotation per day\n * - Midnight-based or 24h from first write\n */\nexport const JSON_LOG_ROTATION_INTERVAL = '1d';\n\n/**\n * JSON_LOG_MAX_ROTATED_FILES = 10\n *\n * Purpose: Maximum number of rotated JSON error log files to retain.\n *\n * Used By: rotating-file-stream library for 'error.json.log'\n *\n * Implications:\n * - When exceeded, oldest rotated file is deleted\n * - Maximum: ~10 files × 10MB = ~100MB (compressed: ~10-30MB)\n */\nexport const JSON_LOG_MAX_ROTATED_FILES = 10;","import debugModule from 'debug';\nimport os from 'node:os';\nimport {STATS_INTERVAL_MS, MAX_HISTORY_BUCKETS, MAX_PERCENTILE_SAMPLES} from '../../common/constants.ts';\n\nconst debug = debugModule('webplsql:statsManager');\n\ntype StatsConfig = {\n\tintervalMs: number;\n\tmaxHistoryPoints: number;\n\tsampleSystem: boolean;\n\tsamplePools: boolean;\n\tpercentilePrecision: number;\n};\n\ntype CacheStats = {\n\tsize: number;\n\thits: number;\n\tmisses: number;\n};\n\ntype PoolCacheSnapshot = {\n\tprocedureName: CacheStats;\n\targument: CacheStats;\n};\n\nexport type PoolSnapshot = {\n\tname: string;\n\tconnectionsInUse: number;\n\tconnectionsOpen: number;\n\tcache?: PoolCacheSnapshot;\n};\n\ntype Bucket = {\n\ttimestamp: number;\n\trequests: number;\n\terrors: number;\n\tdurationMin: number;\n\tdurationMax: number;\n\tdurationAvg: number;\n\tdurationP95: number;\n\tdurationP99: number;\n\tsystem: {\n\t\tcpu: number;\n\t\theapUsed: number;\n\t\theapTotal: number;\n\t\trss: number;\n\t\texternal: number;\n\t};\n\tpools: PoolSnapshot[];\n};\n\ntype CurrentBucket = {\n\tcount: number;\n\terrors: number;\n\tdurationSum: number;\n\tdurationMin: number;\n\tdurationMax: number;\n\tdurations: number[];\n};\n\ntype MemoryLifetime = {\n\theapUsedMax: number;\n\theapTotalMax: number;\n\trssMax: number;\n\texternalMax: number;\n};\n\ntype LifetimeStats = {\n\ttotalRequests: number;\n\ttotalErrors: number;\n\tminDuration: number;\n\tmaxDuration: number;\n\ttotalDuration: number;\n\tmaxRequestsPerSecond: number;\n\tmemory: MemoryLifetime;\n\tcpu: {\n\t\tmax: number;\n\t\tuserMax: number;\n\t\tsystemMax: number;\n\t};\n};\n\ntype StatsSummary = {\n\tstartTime: Date;\n\ttotalRequests: number;\n\ttotalErrors: number;\n\tavgResponseTime: number;\n\tminResponseTime: number;\n\tmaxResponseTime: number;\n\tmaxRequestsPerSecond: number;\n\tmaxMemory: MemoryLifetime;\n\tcpu: {\n\t\tmax: number;\n\t\tuserMax: number;\n\t\tsystemMax: number;\n\t};\n};\n\n/**\n * Manager for statistical data collection and temporal bucketing.\n */\nexport class StatsManager {\n\tconfig: StatsConfig;\n\tstartTime: Date;\n\thistory: Bucket[];\n\tlifetime: LifetimeStats;\n\t_currentBucket: CurrentBucket;\n\t_lastCpuTimes: {user: number; nice: number; sys: number; idle: number; irq: number; total: number};\n\t_timer: NodeJS.Timeout | undefined;\n\n\t/**\n\t * @param config - Configuration.\n\t */\n\tconstructor(config: Partial<StatsConfig> = {}) {\n\t\tthis.config = {\n\t\t\tintervalMs: STATS_INTERVAL_MS,\n\t\t\tmaxHistoryPoints: MAX_HISTORY_BUCKETS,\n\t\t\tsampleSystem: true,\n\t\t\tsamplePools: true,\n\t\t\tpercentilePrecision: MAX_PERCENTILE_SAMPLES,\n\t\t\t...config,\n\t\t};\n\n\t\tthis.startTime = new Date();\n\t\tthis.history = [];\n\n\t\tthis.lifetime = {\n\t\t\ttotalRequests: 0,\n\t\t\ttotalErrors: 0,\n\t\t\tminDuration: -1,\n\t\t\tmaxDuration: -1,\n\t\t\ttotalDuration: 0,\n\t\t\tmaxRequestsPerSecond: 0,\n\t\t\tmemory: {\n\t\t\t\theapUsedMax: 0,\n\t\t\t\theapTotalMax: 0,\n\t\t\t\trssMax: 0,\n\t\t\t\texternalMax: 0,\n\t\t\t},\n\t\t\tcpu: {\n\t\t\t\tmax: 0,\n\t\t\t\tuserMax: 0,\n\t\t\t\tsystemMax: 0,\n\t\t\t},\n\t\t};\n\n\t\tthis._currentBucket = {\n\t\t\tcount: 0,\n\t\t\terrors: 0,\n\t\t\tdurations: [],\n\t\t\tdurationSum: 0,\n\t\t\tdurationMin: -1,\n\t\t\tdurationMax: -1,\n\t\t};\n\n\t\tthis._lastCpuTimes = this._getSystemCpuTimes();\n\n\t\tthis._timer = undefined;\n\t\tif (this.config.sampleSystem) {\n\t\t\tthis._timer = setInterval(() => {\n\t\t\t\tthis.rotateBucket();\n\t\t\t}, this.config.intervalMs);\n\t\t\tif (this._timer && typeof this._timer.unref === 'function') {\n\t\t\t\tthis._timer.unref();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Reset the current bucket accumulator.\n\t */\n\tprivate _resetBucket(): void {\n\t\tthis._currentBucket = {\n\t\t\tcount: 0,\n\t\t\terrors: 0,\n\t\t\tdurations: [],\n\t\t\tdurationSum: 0,\n\t\t\tdurationMin: -1,\n\t\t\tdurationMax: -1,\n\t\t};\n\t}\n\n\t/**\n\t * Record a request event.\n\t * @param duration - Duration in milliseconds.\n\t * @param isError - Whether the request was an error.\n\t */\n\trecordRequest(duration: number, isError = false): void {\n\t\tthis.lifetime.totalRequests++;\n\t\tif (isError) {\n\t\t\tthis.lifetime.totalErrors++;\n\t\t}\n\n\t\tthis.lifetime.totalDuration += duration;\n\t\tif (this.lifetime.minDuration < 0 || duration < this.lifetime.minDuration) {\n\t\t\tthis.lifetime.minDuration = duration;\n\t\t}\n\t\tif (this.lifetime.maxDuration < 0 || duration > this.lifetime.maxDuration) {\n\t\t\tthis.lifetime.maxDuration = duration;\n\t\t}\n\n\t\tconst b = this._currentBucket;\n\t\tb.count++;\n\t\tif (isError) {\n\t\t\tb.errors++;\n\t\t}\n\n\t\tb.durationSum += duration;\n\t\tif (b.durationMin < 0 || duration < b.durationMin) {\n\t\t\tb.durationMin = duration;\n\t\t}\n\t\tif (b.durationMax < 0 || duration > b.durationMax) {\n\t\t\tb.durationMax = duration;\n\t\t}\n\n\t\tif (b.durations.length < this.config.percentilePrecision) {\n\t\t\tb.durations.push(duration);\n\t\t}\n\t}\n\n\t/**\n\t * Get system CPU times.\n\t * @returns System CPU times.\n\t */\n\tprivate _getSystemCpuTimes(): {user: number; nice: number; sys: number; idle: number; irq: number; total: number} {\n\t\tconst cpus = os.cpus();\n\t\tlet user = 0;\n\t\tlet nice = 0;\n\t\tlet sys = 0;\n\t\tlet idle = 0;\n\t\tlet irq = 0;\n\n\t\tfor (const cpu of cpus) {\n\t\t\tuser += cpu.times.user;\n\t\t\tnice += cpu.times.nice;\n\t\t\tsys += cpu.times.sys;\n\t\t\tidle += cpu.times.idle;\n\t\t\tirq += cpu.times.irq;\n\t\t}\n\n\t\tconst total = user + nice + sys + idle + irq;\n\t\treturn {user, nice, sys, idle, irq, total};\n\t}\n\n\t/**\n\t * Calculate CPU usage percentage since last call.\n\t * @returns CPU usage percentage (0-100).\n\t */\n\tprivate _calculateCpuUsage(): number {\n\t\tconst current = this._getSystemCpuTimes();\n\t\tconst last = this._lastCpuTimes || {user: 0, nice: 0, sys: 0, idle: 0, irq: 0, total: 0};\n\n\t\tconst deltaTotal = current.total - last.total;\n\t\tconst deltaIdle = current.idle - last.idle;\n\n\t\tthis._lastCpuTimes = current;\n\n\t\tif (deltaTotal <= 0) return 0;\n\n\t\tconst percent = ((deltaTotal - deltaIdle) / deltaTotal) * 100;\n\t\treturn Math.min(100, Math.max(0, percent));\n\t}\n\n\t/**\n\t * Rotate the current bucket into history and start a new one.\n\t * @param poolSnapshots - Optional pool snapshots to include.\n\t */\n\trotateBucket(poolSnapshots: PoolSnapshot[] = []): void {\n\t\tconst b = this._currentBucket;\n\t\tconst memUsage = process.memoryUsage();\n\t\tconst systemMemoryUsed = os.totalmem() - os.freemem();\n\t\tconst cpuUsage = process.cpuUsage();\n\t\tconst cpu = this._calculateCpuUsage();\n\n\t\t// Update lifetime extremes\n\t\tconst reqPerSec = b.count / (this.config.intervalMs / 1000);\n\t\tthis.lifetime.maxRequestsPerSecond = Math.max(this.lifetime.maxRequestsPerSecond, reqPerSec);\n\t\tthis.lifetime.memory.heapUsedMax = Math.max(this.lifetime.memory.heapUsedMax, memUsage.heapUsed);\n\t\tthis.lifetime.memory.heapTotalMax = Math.max(this.lifetime.memory.heapTotalMax, memUsage.heapTotal);\n\t\tthis.lifetime.memory.rssMax = Math.max(this.lifetime.memory.rssMax, systemMemoryUsed);\n\t\tthis.lifetime.memory.externalMax = Math.max(this.lifetime.memory.externalMax, memUsage.external);\n\t\tthis.lifetime.cpu.max = Math.max(this.lifetime.cpu.max, cpu);\n\t\tthis.lifetime.cpu.userMax = Math.max(this.lifetime.cpu.userMax, cpuUsage.user);\n\t\tthis.lifetime.cpu.systemMax = Math.max(this.lifetime.cpu.systemMax, cpuUsage.system);\n\n\t\tlet p95 = 0;\n\t\tlet p99 = 0;\n\t\tif (b.durations.length > 0) {\n\t\t\tconst sorted = b.durations.toSorted((x, y) => x - y);\n\t\t\tconst p95Idx = Math.floor(sorted.length * 0.95);\n\t\t\tconst p99Idx = Math.floor(sorted.length * 0.99);\n\t\t\tconst lastIdx = sorted.length - 1;\n\n\t\t\tp95 = sorted[p95Idx] ?? sorted[lastIdx] ?? 0;\n\t\t\tp99 = sorted[p99Idx] ?? sorted[lastIdx] ?? 0;\n\t\t}\n\n\t\tconst bucket: Bucket = {\n\t\t\ttimestamp: Date.now(),\n\t\t\trequests: b.count,\n\t\t\terrors: b.errors,\n\t\t\tdurationMin: Math.max(b.durationMin, 0),\n\t\t\tdurationMax: Math.max(b.durationMax, 0),\n\t\t\tdurationAvg: b.count > 0 ? b.durationSum / b.count : 0,\n\t\t\tdurationP95: p95,\n\t\t\tdurationP99: p99,\n\t\t\tsystem: {\n\t\t\t\tcpu,\n\t\t\t\theapUsed: memUsage.heapUsed,\n\t\t\t\theapTotal: memUsage.heapTotal,\n\t\t\t\trss: systemMemoryUsed,\n\t\t\t\texternal: memUsage.external,\n\t\t\t},\n\t\t\tpools: poolSnapshots,\n\t\t};\n\n\t\tthis.history.push(bucket);\n\t\tif (this.history.length > this.config.maxHistoryPoints) {\n\t\t\tthis.history.shift();\n\t\t}\n\n\t\tthis._resetBucket();\n\t\tdebug('Bucket rotated: %j', bucket);\n\t}\n\n\t/**\n\t * Stop the background timer.\n\t */\n\tstop(): void {\n\t\tif (this._timer) {\n\t\t\tclearInterval(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Get lifetime summary.\n\t * @returns Summary.\n\t */\n\tgetSummary(): StatsSummary {\n\t\treturn {\n\t\t\tstartTime: this.startTime,\n\t\t\ttotalRequests: this.lifetime.totalRequests,\n\t\t\ttotalErrors: this.lifetime.totalErrors,\n\t\t\tavgResponseTime: this.lifetime.totalRequests > 0 ? this.lifetime.totalDuration / this.lifetime.totalRequests : 0,\n\t\t\tminResponseTime: this.lifetime.minDuration,\n\t\t\tmaxResponseTime: this.lifetime.maxDuration,\n\t\t\tmaxRequestsPerSecond: this.lifetime.maxRequestsPerSecond,\n\t\t\tmaxMemory: this.lifetime.memory,\n\t\t\tcpu: this.lifetime.cpu,\n\t\t};\n\t}\n\n\t/**\n\t * Get history buffer.\n\t * @returns The history buffer.\n\t */\n\tgetHistory(): Bucket[] {\n\t\treturn this.history;\n\t}\n}","import {StatsManager} from '../util/statsManager.ts';\nimport type {Pool} from 'oracledb';\nimport type {configType, argsType} from '../types.ts';\nimport type {Cache} from '../util/cache.ts';\n\ntype PoolCacheEntry = {\n\tpoolName: string;\n\tprocedureNameCache: Cache<string>;\n\targumentCache: Cache<argsType>;\n};\n\n/**\n * Admin Context Class\n */\nexport class AdminContext {\n\treadonly startTime: Date;\n\treadonly config: configType;\n\treadonly pools: Pool[];\n\treadonly caches: PoolCacheEntry[];\n\treadonly statsManager: StatsManager;\n\tprivate _paused: boolean;\n\n\tconstructor(config: configType) {\n\t\tthis.startTime = new Date();\n\t\tthis.config = config;\n\t\tthis.pools = [];\n\t\tthis.caches = [];\n\t\tthis.statsManager = new StatsManager();\n\t\tthis._paused = false;\n\t}\n\n\t/**\n\t * Register a PL/SQL handler with the admin context.\n\t * @param route - The route for the handler.\n\t * @param pool - The connection pool.\n\t * @param procedureNameCache - The procedure name cache.\n\t * @param argumentCache - The argument cache.\n\t */\n\tregisterHandler(route: string, pool: Pool, procedureNameCache: Cache<string>, argumentCache: Cache<argsType>): void {\n\t\tthis.pools.push(pool);\n\t\tthis.caches.push({\n\t\t\tpoolName: route,\n\t\t\tprocedureNameCache,\n\t\t\targumentCache,\n\t\t});\n\t}\n\n\tget paused(): boolean {\n\t\treturn this._paused;\n\t}\n\n\tsetPaused(value: boolean): void {\n\t\tthis._paused = value;\n\t}\n}","import {promises as fs, readFileSync} from 'node:fs';\n\n/**\n * Read file.\n *\n * @param filePath - File name.\n * @returns The string.\n */\nexport const readFileSyncUtf8 = (filePath: string): string => {\n\ttry {\n\t\treturn readFileSync(filePath, 'utf8');\n\t} catch {\n\t\tthrow new Error(`Unable to read file \"${filePath}\"`);\n\t}\n};\n\n/**\n * Read file.\n *\n * @param filePath - File name.\n * @returns The buffer.\n */\nexport const readFile = async (filePath: string): Promise<Buffer> => {\n\ttry {\n\t\treturn await fs.readFile(filePath);\n\t} catch {\n\t\tthrow new Error(`Unable to read file \"${filePath}\"`);\n\t}\n};\n\n/**\n * Remove file.\n *\n * @param filePath - File name.\n */\nexport const removeFile = async (filePath: string): Promise<void> => {\n\ttry {\n\t\tawait fs.unlink(filePath);\n\t} catch {\n\t\tthrow new Error(`Unable to remove file \"${filePath}\"`);\n\t}\n};\n\n/**\n * Load a json file.\n *\n * @param filePath - File name.\n * @returns The json object.\n */\nexport const getJsonFile = (filePath: string): unknown => {\n\ttry {\n\t\tconst fileContent = readFileSync(filePath, 'utf8');\n\t\treturn JSON.parse(fileContent);\n\t} catch {\n\t\tthrow new Error(`Unable to load file \"${filePath}\"`);\n\t}\n};\n\n/**\n * Is this a directory.\n * @param directoryPath - Directory name.\n * @returns Return true if it is a directory.\n */\nexport const isDirectory = async (directoryPath: unknown): Promise<boolean> => {\n\tif (typeof directoryPath !== 'string') {\n\t\treturn false;\n\t}\n\n\tconst stats = await fs.stat(directoryPath);\n\n\treturn stats.isDirectory();\n};\n\n/**\n * Is this a file.\n * @param filePath - File name.\n * @returns Return true if it is a file.\n */\nexport const isFile = async (filePath: unknown): Promise<boolean> => {\n\tif (typeof filePath !== 'string') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst stats = await fs.stat(filePath);\n\t\treturn stats.isFile();\n\t} catch {\n\t\treturn false;\n\t}\n};","/*\n *\tHtml utilities\n */\n\n/**\n * Escape html string.\n *\n * @param value - The value.\n * @returns The escaped value.\n */\nexport const escapeHtml = (value: string): string =>\n\tvalue.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('\"', '"').replaceAll(\"'\", ''');\n\n/**\n *\tConvert LF and/or CR to <br>\n *\t@param text - The text to convert.\n *\t@returns The converted text.\n */\nexport const convertAsciiToHtml = (text: string): string => {\n\tlet html = escapeHtml(text);\n\n\thtml = html.replaceAll(/\\r\\n|\\r|\\n/gu, '<br />');\n\thtml = html.replaceAll('\\t', ' ');\n\n\treturn html;\n};\n\n/**\n *\tget a minimal html page.\n *\t@param body - The body.\n *\t@returns The html page.\n */\nexport const getHtmlPage = (body: string): string => `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>web_plsql error page</title>\n<style type=\"text/css\">\nhtml {\n\tfont-family: monospace, sans-serif;\n\tfont-size: 12px;\n}\nh1 {\n\tfont-size: 16px;\n\tpadding: 2px;\n\tbackground-color: #cc0000;\n}\n</style>\n</head>\n<body>\n${body}\n</body>\n</html>\n`;","/*\n *\tTrace utilities\n */\n\nimport * as rotatingFileStream from 'rotating-file-stream';\nimport type {Request} from 'express';\nimport util from 'node:util';\nimport oracledb from 'oracledb';\nimport {escapeHtml, convertAsciiToHtml} from './html.ts';\nimport {errorToString} from './errorToString.ts';\nimport {TRACE_LOG_ROTATION_SIZE, TRACE_LOG_ROTATION_INTERVAL, TRACE_LOG_MAX_ROTATED_FILES} from '../../common/constants.ts';\nimport type {environmentType} from '../types.ts';\nimport type {BindParameter, BindParameters} from 'oracledb';\n\n/**\n * Type guard for BindParameter\n * @param row - The row to check\n * @returns True if row is a BindParameter\n */\nconst isBindParameter = (row: unknown): row is BindParameter => {\n\tif (typeof row !== 'object' || row === null) {\n\t\treturn false;\n\t}\n\treturn 'dir' in row || 'type' in row || 'val' in row || 'maxSize' in row || 'maxArraySize' in row;\n};\n\ntype outputType = {\n\thtml: string;\n\ttext: string;\n};\n\nexport type messageType = {\n\ttype: 'error' | 'warning' | 'trace';\n\tmessage: string;\n\ttimestamp?: Date | null;\n\treq?: Request | null;\n\tenvironment?: environmentType | null;\n\tsql?: string | null;\n\tbind?: BindParameters | null;\n};\n\nconst SEPARATOR_H1 = '='.repeat(100);\nconst SEPARATOR_H2 = '-'.repeat(30);\n\n/**\n * Return a string representation of the value.\n *\n * @param value - Any value.\n * @param depth - Specifies the number of times to recurse while formatting object.\n * @returns The string representation.\n */\nexport const inspect = (value: unknown, depth: number | null = null): string => {\n\ttry {\n\t\treturn util.inspect(value, {showHidden: false, depth, colors: false});\n\t} catch {\n\t\t/* empty */\n\t}\n\n\ttry {\n\t\treturn JSON.stringify(value);\n\t} catch {\n\t\t/* empty */\n\t}\n\n\treturn 'Unable to convert value to string';\n};\n\n// Build text representation\n/**\n *\t@param cell - The string\n *\t@param width - The width\n *\t@returns The result\n */\nconst padCell = (cell: string, width: number) => cell.padEnd(width, ' ');\n\n/**\n * Return a tabular representation of the values.\n *\n * @param head - The header values.\n * @param body - The row values.\n * @returns The output.\n */\nexport const toTable = (head: string[], body: string[][]): outputType => {\n\tif (head.length === 0) {\n\t\tthrow new Error('head cannot be empty');\n\t}\n\n\t// Calculate column widths\n\tconst widths = head.map((h, i) => {\n\t\tconst bodyMax = Math.max(0, ...body.map((row) => (row[i] ?? '').length));\n\t\treturn Math.max(h.length, bodyMax);\n\t});\n\n\t/**\n\t *\t@param i - The index\n\t *\t@returns The width\n\t */\n\tconst getWidth = (i: number): number => widths[i] ?? 0;\n\tconst textHeader = head.map((h, i) => padCell(h, getWidth(i))).join(' | ');\n\tconst textSeparator = widths.map((w) => '-'.repeat(w ?? 0)).join('-+-');\n\tconst textRows = body.map((row) => head.map((_, i) => padCell(row[i] ?? '', getWidth(i))).join(' | '));\n\tconst text = [textHeader, textSeparator, ...textRows].join('\\n');\n\n\tconst htmlHead = head.map((h) => `<th>${escapeHtml(h)}</th>`).join('');\n\tconst htmlBody = body.map((row) => `<tr>${head.map((_, i) => `<td>${escapeHtml(row[i] ?? '')}</td>`).join('')}</tr>`).join('');\n\tconst html = `<table><thead><tr>${htmlHead}</tr></thead><tbody>${htmlBody}</tbody></table>`;\n\n\treturn {text, html};\n};\n\n/**\n * Log text to the console and to a file.\n *\n * @param text - Text to log.\n */\nexport const logToFile = (text: string): void => {\n\tconst fs = rotatingFileStream.createStream('trace.log', {\n\t\tsize: TRACE_LOG_ROTATION_SIZE, // rotate every 10 MegaBytes written\n\t\tinterval: TRACE_LOG_ROTATION_INTERVAL, // rotate daily\n\t\tmaxFiles: TRACE_LOG_MAX_ROTATED_FILES, // maximum number of rotated files to keep\n\t\tcompress: 'gzip', // compress rotated files\n\t});\n\n\tfs.write(text);\n\tfs.end();\n};\n\n/**\n * Return a string representation of the request.\n *\n * @param req - express.Request.\n * @returns The string representation.\n */\nconst inspectRequest = (req: Request): string => {\n\tconst requestData: Record<string, unknown> = {};\n\n\tObject.keys(req)\n\t\t.filter((prop) => ['originalUrl', 'params', 'query', 'url', 'method', 'body', 'files', 'secret', 'cookies'].includes(prop))\n\t\t.forEach((prop) => {\n\t\t\trequestData[prop] = req[prop as keyof Request];\n\t\t});\n\n\treturn inspect(requestData);\n};\n\n/**\n *\tReturn a string representation of the bind parameter.\n *\t@param dir - The direction.\n *\t@returns The string.\n */\nconst dirToString = (dir: number | undefined): string => {\n\tswitch (dir) {\n\t\tcase oracledb.BIND_IN:\n\t\t\treturn 'IN';\n\t\tcase oracledb.BIND_OUT:\n\t\t\treturn 'OUT';\n\t\tcase oracledb.BIND_INOUT:\n\t\t\treturn 'INOUT';\n\t\tdefault:\n\t\t\treturn '';\n\t}\n};\n\n/**\n *\tReturn a string representation of the bind type.\n *\t@param type - The type.\n *\t@returns The string.\n */\nconst bindTypeToString = (type: unknown): string => {\n\tif (typeof type === 'object' && type !== null && 'name' in type) {\n\t\treturn (type as {name: string}).name;\n\t}\n\n\tif (typeof type === 'string') {\n\t\treturn type;\n\t}\n\n\tif (typeof type === 'number') {\n\t\treturn type.toString();\n\t}\n\n\treturn '';\n};\n\n/**\n *\tReturn a string representation of the bind parameter.\n *\t@param output - The output.\n *\t@param bind - The bind parameters.\n */\nconst inspectBindParameter = (output: outputType, bind: BindParameters): void => {\n\tconst rows = Object.entries(bind);\n\n\tif (rows.length === 0) {\n\t\treturn;\n\t}\n\n\tconst body = rows.map(([id, row]) => {\n\t\tlet dir = '';\n\t\tlet maxArraySize = '';\n\t\tlet maxSize = '';\n\t\tlet bindType = '';\n\t\tlet value = '';\n\t\tlet valueType = '';\n\n\t\tif (isBindParameter(row)) {\n\t\t\tdir = dirToString(row.dir);\n\t\t\tmaxArraySize = row.maxArraySize ? row.maxArraySize.toString() : '';\n\t\t\tmaxSize = row.maxSize ? row.maxSize.toString() : '';\n\t\t\tbindType = bindTypeToString(row.type);\n\t\t\tvalue = inspect(row.val);\n\t\t\tvalueType = typeof row.val;\n\t\t} else {\n\t\t\tvalue = inspect(row);\n\t\t\tvalueType = typeof row;\n\t\t}\n\n\t\treturn [id, dir, maxArraySize, maxSize, bindType, value, valueType];\n\t});\n\n\tconst {html, text} = toTable(['id', 'dir', 'maxArraySize', 'maxSize', 'bind type', 'value', 'value type'], body);\n\n\toutput.html += html;\n\toutput.text += text;\n};\n\n/**\n * Add environment\n *\t@param output - The output.\n *\t@param environment - The environment.\n */\nconst inspectEnvironment = (output: outputType, environment: environmentType): void => {\n\tconst rows = Object.entries(environment);\n\n\tif (rows.length === 0) {\n\t\treturn;\n\t}\n\n\tconst {html, text} = toTable(['key', 'value'], rows);\n\n\toutput.html += html;\n\toutput.text += text;\n};\n\n/**\n *\tGet a block.\n *\t@param title - The name.\n *\t@param body - The name.\n *\t@returns The text.\n */\nexport const getBlock = (title: string, body: string): string => `\\n${SEPARATOR_H2}${title.toUpperCase()}${SEPARATOR_H2}\\n${body}`;\n\n/**\n *\tGet line html\n *\t@param text - The text.\n *\t@returns The line.\n */\nconst getLineHtml = (text: string): string => `<p>${convertAsciiToHtml(text)}</p>`;\n\n/**\n *\tGet line text\n *\t@param text - The text.\n *\t@returns The line.\n */\nconst getLineText = (text: string): string => `${text}\\n`;\n\n/**\n *\tAdd line\n *\t@param output - The output.\n *\t@param text - The text to convert.\n */\nconst addLine = (output: outputType, text: string): void => {\n\toutput.html += getLineHtml(text);\n\toutput.text += getLineText(text);\n};\n\n/**\n *\tAdd header\n *\t@param output - The output.\n *\t@param text - The text to convert.\n */\nconst addHeader = (output: outputType, text: string): void => {\n\toutput.html += `<h2>${text}</h2>`;\n\toutput.text += `\\n${text}\\n${'-'.repeat(text.length)}\\n`;\n};\n\n/**\n *\tAdd procedure\n *\t@param output - The output.\n *\t@param sql - The SQL to execute.\n *\t@param bind - The bind parameters.\n */\nconst addProcedure = (output: outputType, sql: string, bind: BindParameters): void => {\n\toutput.html += `${sql}<br><br>`;\n\toutput.text += `${sql}\\n\\n`;\n\n\ttry {\n\t\tinspectBindParameter(output, bind);\n\t} catch (err) {\n\t\taddLine(output, `Unable to inspect bind parameter: ${errorToString(err)}`);\n\t}\n\n\toutput.html += `<br>`;\n\toutput.text += `\\n`;\n};\n\n/**\n *\tGet a formatted message.\n *\t@param para - The req object represents the HTTP request.\n *\t@returns The output.\n */\nexport const getFormattedMessage = (para: messageType): outputType => {\n\tconst timestamp = para.timestamp ?? new Date();\n\n\t// header\n\tconst url = typeof para.req?.originalUrl === 'string' && para.req.originalUrl.length > 0 ? ` on ${para.req.originalUrl}` : '';\n\tconst type = (para.type ?? 'trace').toUpperCase();\n\tconst header = `${type} at ${timestamp.toUTCString()}${url}`;\n\tconst output: outputType = {\n\t\thtml: `<h1>${header}</h1>`,\n\t\ttext: `\\n\\n${SEPARATOR_H1}\\n== ${header}\\n${SEPARATOR_H1}\\n`,\n\t};\n\n\t// error\n\taddHeader(output, 'ERROR');\n\taddLine(output, para.message);\n\n\t// request\n\tif (para.req) {\n\t\taddHeader(output, 'REQUEST');\n\t\taddLine(output, inspectRequest(para.req));\n\t}\n\n\t// parameters\n\tif (para.sql && para.bind) {\n\t\taddHeader(output, 'PROCEDURE');\n\t\taddProcedure(output, para.sql, para.bind);\n\t}\n\n\t// environment\n\tif (para.environment) {\n\t\taddHeader(output, 'ENVIRONMENT');\n\t\tinspectEnvironment(output, para.environment);\n\t}\n\n\treturn output;\n};\n\n/**\n *\tLog a warning message.\n *\t@param para - The req object represents the HTTP request.\n */\nexport const warningMessage = (para: messageType): void => {\n\tconst {text} = getFormattedMessage(para);\n\n\t// trace to file\n\tlogToFile(text);\n\n\t// console\n\tconsole.warn(text);\n};","import {inspect} from './trace.ts';\n\n/**\n * Convert Error to a string.\n *\n * @param error - The error.\n * @returns The string representation.\n */\nexport const errorToString = (error: unknown): string => {\n\tif (typeof error === 'string') {\n\t\treturn error;\n\t} else if (error instanceof Error) {\n\t\tconst parts = [error.name];\n\t\tif (typeof error.message === 'string' && error.message.length > 0) {\n\t\t\tparts.push(error.message);\n\t\t}\n\t\tif (typeof error.stack === 'string' && error.stack.length > 0) {\n\t\t\tparts.push(error.stack);\n\t\t}\n\t\treturn parts.join('\\n');\n\t} else {\n\t\treturn inspect(error);\n\t}\n};","/*\n *\tProcess file uploads\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:fileUpload');\n\nimport {BUFFER} from '../../util/oracledb-provider.ts';\nimport {readFile, removeFile} from '../../util/file.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport type {Connection} from 'oracledb';\nimport z from 'zod';\nimport type {Request} from 'express';\nimport type {fileUploadType} from '../../types.ts';\n\nconst z$reqFiles = z.array(\n\tz.strictObject({\n\t\tfieldname: z.string(),\n\t\toriginalname: z.string(),\n\t\tencoding: z.string(),\n\t\tmimetype: z.string(),\n\t\tdestination: z.string(),\n\t\tfilename: z.string(),\n\t\tpath: z.string(),\n\t\tsize: z.number(),\n\t}),\n);\n\n/**\n * Get the files\n *\n * @param req - The req object represents the HTTP request.\n * @returns Promise that resolves with an array of files to be uploaded.\n */\nexport const getFiles = (req: Request): fileUploadType[] => {\n\tif (!('files' in req)) {\n\t\tdebug('getFiles: no files');\n\t\treturn [];\n\t}\n\n\tif (typeof req.files === 'object' && req.files !== null && Object.keys(req.files as object).length === 0) {\n\t\tdebug('getFiles: no files');\n\t\treturn [];\n\t}\n\n\tconst files = z$reqFiles.parse(req.files) as fileUploadType[];\n\n\tfor (const file of files) {\n\t\tfile.filename += `/${file.originalname}`;\n\t}\n\n\tdebug('getFiles', files);\n\n\treturn files;\n};\n\n/**\n * Upload the given file and return a promise.\n *\n * @param file - The file to upload.\n * @param doctable - The file to upload.\n * @param databaseConnection - The file to upload.\n * @returns Promise that resolves when uploaded.\n */\nexport const uploadFile = async (file: fileUploadType, doctable: string, databaseConnection: Connection): Promise<void> => {\n\tdebug(`uploadFile`, file, doctable);\n\n\t/* v8 ignore next - defensive validation */\n\tif (typeof doctable !== 'string' || doctable.length === 0) {\n\t\tthrow new Error(`Unable to upload file \"${file.filename}\" because the option \"\"doctable\" has not been defined`);\n\t}\n\n\t// read file\n\tlet blobContent;\n\ttry {\n\t\tblobContent = await readFile(file.path);\n\t} catch (err) {\n\t\tthrow new Error(`Unable to load file \"${file.path}\".\\n${errorToString(err)}`);\n\t}\n\n\t// insert file in document table\n\tconst sql = `INSERT INTO ${doctable} (name, mime_type, doc_size, dad_charset, last_updated, content_type, blob_content) VALUES (:name, :mime_type, :doc_size, 'ascii', SYSDATE, 'BLOB', :blob_content)`;\n\tconst bind = {\n\t\tname: file.filename,\n\t\tmime_type: file.mimetype,\n\t\tdoc_size: file.size,\n\t\tblob_content: {\n\t\t\tval: blobContent,\n\t\t\ttype: BUFFER,\n\t\t},\n\t};\n\ttry {\n\t\tawait databaseConnection.execute(sql, bind, {autoCommit: true});\n\t} catch (err) {\n\t\tthrow new Error(`Unable to insert file \"${file.filename}\".\\n${errorToString(err)}`);\n\t}\n\n\t// remove the file\n\ttry {\n\t\tawait removeFile(file.path);\n\t} catch (err) {\n\t\tthrow new Error(`Unable to remove file \"${file.filename}\".\\n${errorToString(err)}`);\n\t}\n};","/*\n *\tInvoke the Oracle procedure and return the raw content of the page\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:procedureVariable');\n\nimport {BIND_IN, STRING} from '../../util/oracledb-provider.ts';\nimport type {Request} from 'express';\nimport type {argObjType} from '../../types.ts';\nimport type {BindParameters} from 'oracledb';\n\n/**\n *\tGet the sql statement and bindings for the procedure to execute for a variable number of arguments\n *\t@param _req - The req object represents the HTTP request. (only used for debugging)\n *\t@param procName - The procedure to execute\n *\t@param argObj - The arguments to pass to the procedure\n *\t@returns The SQL statement and bindings for the procedure to execute\n */\nexport const getProcedureVariable = (_req: Request, procName: string, argObj: argObjType): {sql: string; bind: BindParameters} => {\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tdebug(`getProcedureVariable: ${procName} arguments=`, argObj);\n\t}\n\t/* v8 ignore stop */\n\n\tconst names: string[] = [];\n\tconst values: string[] = [];\n\n\tfor (const key in argObj) {\n\t\tconst value = argObj[key];\n\t\tif (typeof value === 'string') {\n\t\t\tnames.push(key);\n\t\t\tvalues.push(value);\n\t\t} else if (Array.isArray(value)) {\n\t\t\tvalue.forEach((item) => {\n\t\t\t\tnames.push(key);\n\t\t\t\tvalues.push(item);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn {\n\t\tsql: `${procName}(:argnames, :argvalues)`,\n\t\tbind: {\n\t\t\targnames: {dir: BIND_IN, type: STRING, val: names},\n\t\t\targvalues: {dir: BIND_IN, type: STRING, val: values},\n\t\t},\n\t};\n};","/*\n *\tRequestError\n */\n\nexport class RequestError extends Error {\n\ttimestamp: Date;\n\n\t/**\n\t * @param message - The error message.\n\t */\n\tconstructor(message: string) {\n\t\tsuper(message);\n\n\t\t// Maintains proper stack trace for where our error was thrown (only available on V8)\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, RequestError);\n\t\t}\n\n\t\t// Custom debugging information\n\t\tthis.timestamp = new Date();\n\t}\n}","/**\n * Get duration as human readable string.\n * @param duration - Milliseconds.\n * @returns String.\n */\nexport const humanDuration = (duration: number): string => {\n\tif (!Number.isFinite(duration)) return 'invalid';\n\n\tconst ms = Math.floor(duration % 1000);\n\tconst s = Math.floor((duration / 1000) % 60);\n\tconst m = Math.floor((duration / (1000 * 60)) % 60);\n\tconst h = Math.floor((duration / (1000 * 60 * 60)) % 24);\n\tconst d = Math.floor(duration / (1000 * 60 * 60 * 24));\n\n\tconst parts = [];\n\tif (d) parts.push(`${d}d`);\n\tif (h) parts.push(`${h}h`);\n\tif (m) parts.push(`${m}m`);\n\tif (s) parts.push(`${s}s`);\n\tif (ms || parts.length === 0) parts.push(`${ms}ms`);\n\n\treturn parts.join(' ');\n};\n\n/**\n * Convert a string to a number\n *\n * @param value - The string to convert\n * @returns The number or null if the string could not be converted\n */\nexport const stringToNumber = (value: unknown): number | null => {\n\t// is the value already of type number?\n\tif (typeof value === 'number') {\n\t\treturn !Number.isNaN(value) && Number.isFinite(value) ? value : null;\n\t}\n\n\t// Test for invalid characters\n\t// oxlint-disable-next-line unicorn/better-regex\n\tif (typeof value !== 'string' || !/^[+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:E[+-]?\\d+)?$/iu.test(value)) {\n\t\treturn null;\n\t}\n\n\t// Convert value to a number\n\treturn Number(value);\n};\n\n/**\n * Convert a string to a integer\n *\n * @param value - The value to convert\n * @returns The integer or null if the string could not be converted\n */\nexport const stringToInteger = (value: unknown): number | null => {\n\t// is the value already a \"real\" integer, we just return the value\n\tif (typeof value === 'number' && Number.isInteger(value)) {\n\t\treturn value;\n\t}\n\n\t// try to convert value to a number\n\tconst num = stringToNumber(value);\n\tif (num === null || !Number.isInteger(num)) {\n\t\treturn null;\n\t}\n\n\treturn num;\n};\n\n/**\n * Centers text within a fixed width by padding both sides with spaces.\n * If padding is odd, the extra space goes to the right.\n *\n * @param text - The string to center\n * @param width - Total output width in characters\n * @returns Padded string of exactly `width` characters\n * @throws {RangeError} If `width` is less than `text.length`\n */\nexport const centerText = (text: string, width: number, padding = ' '): string => {\n\tif (width < text.length) {\n\t\tthrow new RangeError(`width (${width}) < text.length (${text.length})`);\n\t}\n\n\tconst total = width - text.length;\n\tconst left = Math.floor(total / 2);\n\tconst right = total - left;\n\n\treturn padding.repeat(left) + text + padding.repeat(right);\n};","/*\n *\tInvoke the Oracle procedure and return the raw content of the page\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:procedureNamed');\n\nimport {BIND_IN, BIND_OUT, STRING, DB_TYPE_VARCHAR, DB_TYPE_CLOB, DB_TYPE_NUMBER, DB_TYPE_DATE} from '../../util/oracledb-provider.ts';\nimport z from 'zod';\nimport {RequestError} from './requestError.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {stringToNumber} from '../../util/util.ts';\nimport {toTable, warningMessage, inspect} from '../../util/trace.ts';\nimport {MAX_PROCEDURE_PARAMETERS} from '../../../common/constants.ts';\nimport type {Request} from 'express';\nimport type {Connection, Result, BindParameter, BindParameters} from 'oracledb';\nimport type {argObjType, argsType, ArgumentCache} from '../../types.ts';\n\nconst SQL_GET_ARGUMENT = [\n\t'DECLARE',\n\t'\tschemaName\t\tVARCHAR2(32767);',\n\t'\tpart1\t\t\tVARCHAR2(32767);',\n\t'\tpart2\t\t\tVARCHAR2(32767);',\n\t'\tdblink\t\t\tVARCHAR2(32767);',\n\t'\tobjectType\t\tNUMBER;',\n\t'\tobjectID\t\tNUMBER;',\n\t'BEGIN',\n\t'\tdbms_utility.name_resolve(name=>UPPER(:name), context=>1, schema=>schemaName, part1=>part1, part2=>part2, dblink=>dblink, part1_type=>objectType, object_number=>objectID);',\n\t'\tIF (part1 IS NOT NULL) THEN',\n\t'\t\tSELECT argument_name, data_type BULK COLLECT INTO :names, :types FROM all_arguments WHERE owner = schemaName AND package_name = part1 AND object_name = part2 AND argument_name IS NOT NULL ORDER BY overload, sequence;',\n\t'\tELSE',\n\t'\t\tSELECT argument_name, data_type BULK COLLECT INTO :names, :types FROM all_arguments WHERE owner = schemaName AND package_name IS NULL AND object_name = part2 AND argument_name IS NOT NULL ORDER BY overload, sequence;',\n\t'\tEND IF;',\n\t'END;',\n].join('\\n');\n\nconst DATA_TYPES = Object.freeze({\n\tVARCHAR2: 'VARCHAR2',\n\tCHAR: 'CHAR',\n\tBINARY_INTEGER: 'BINARY_INTEGER',\n\tNUMBER: 'NUMBER',\n\tDATE: 'DATE',\n\tCLOB: 'CLOB',\n\tPL_SQL_TABLE: 'PL/SQL TABLE',\n\t//\tPL/SQL BOOLEAN\n\t//\tPL/SQL RECORD\n\t//\tOBJECT\n\t//\tTABLE\n\t//\tBLOB\n\t//\tRAW\n\t//\tVARRAY\n\t//\tREF CURSOR\n});\n\n/**\n *\tRetrieve the argument types for a given procedure to be executed.\n *\tThis is important because if the procedure is defined to take a PL/SQL indexed table,\n *\twe must provise a table, even if there is only one argument to be submitted.\n *\t@param procedure - The procedure\n *\t@param databaseConnection - The database connection\n *\t@returns The argument types\n */\nconst loadArguments = async (procedure: string, databaseConnection: Connection): Promise<argsType> => {\n\tconst bind: BindParameters = {\n\t\tname: {dir: BIND_IN, type: STRING, val: procedure},\n\t\tnames: {dir: BIND_OUT, type: STRING, maxSize: 60, maxArraySize: MAX_PROCEDURE_PARAMETERS},\n\t\ttypes: {dir: BIND_OUT, type: STRING, maxSize: 60, maxArraySize: MAX_PROCEDURE_PARAMETERS},\n\t};\n\n\tlet result: Result<unknown> = {};\n\ttry {\n\t\tresult = await databaseConnection.execute(SQL_GET_ARGUMENT, bind);\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug('result', result);\n\t\t/* v8 ignore stop */\n\n\t\tconst message = `Error when retrieving arguments\\n${SQL_GET_ARGUMENT}\\n${errorToString(err)}`;\n\t\tthrow new RequestError(message);\n\t}\n\n\tlet data: {names: (string | null)[]; types: (string | null)[]};\n\ttry {\n\t\tdata = z\n\t\t\t.object({\n\t\t\t\tnames: z.array(z.string().nullable()),\n\t\t\t\ttypes: z.array(z.string().nullable()),\n\t\t\t})\n\t\t\t.parse(result.outBinds);\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug('result.outBinds', result.outBinds);\n\t\t/* v8 ignore stop */\n\n\t\tconst message = `Error when decoding arguments\\n${SQL_GET_ARGUMENT}\\n${errorToString(err)}`;\n\t\tthrow new RequestError(message);\n\t}\n\n\tif (data.names.length !== data.types.length) {\n\t\tthrow new RequestError('Error when decoding arguments. The number of names and types does not match');\n\t}\n\n\tconst argTypes: argsType = {};\n\tfor (let i = 0; i < data.names.length; i++) {\n\t\tconst name = data.names[i];\n\t\tconst type = data.types[i];\n\t\tif (name && type) {\n\t\t\targTypes[name.toLowerCase()] = type;\n\t\t}\n\t}\n\n\treturn argTypes;\n};\n\n/**\n *\tFind the argument types for a given procedure to be executed.\n *\tAs the arguments are cached, we first look up the cache and only if not yet available we load them.\n *\t@param procedure - The procedure\n *\t@param databaseConnection - The database connection\n *\t@param argumentCache - The argument cache.\n *\t@returns The argument types\n */\nconst findArguments = async (procedure: string, databaseConnection: Connection, argumentCache: ArgumentCache): Promise<argsType> => {\n\tconst key = procedure.toUpperCase();\n\n\t// lookup in the cache\n\tconst cachedArgs = argumentCache.get(key);\n\n\t// if we found the procedure in the cache, we return it\n\tif (cachedArgs) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebug(`findArguments: procedure \"${procedure}\" found in cache`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\treturn cachedArgs;\n\t}\n\n\t// load from database\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tdebug(`findArguments: procedure \"${procedure}\" not found in cache and must be loaded`);\n\t}\n\t/* v8 ignore stop */\n\n\tconst args = await loadArguments(procedure, databaseConnection);\n\n\t// add to the cache\n\targumentCache.set(key, args);\n\n\treturn args;\n};\n\n/**\n *\tGet the bindling for an argument.\n *\t@param argName - The argument name.\n *\t@param argValue - The argument value.\n *\t@param argType - The argument type.\n *\t@returns The binding.\n */\nexport const getBinding = (argName: string, argValue: unknown, argType: string): BindParameter => {\n\tconst isEmpty = argValue === '' || argValue === null || argValue === undefined;\n\n\tif (argType === DATA_TYPES.VARCHAR2 || argType === DATA_TYPES.CHAR) {\n\t\treturn {dir: BIND_IN, type: DB_TYPE_VARCHAR, val: isEmpty ? null : argValue};\n\t}\n\n\tif (argType === DATA_TYPES.CLOB) {\n\t\treturn {dir: BIND_IN, type: DB_TYPE_CLOB, val: isEmpty ? null : argValue};\n\t}\n\n\tif (argType === DATA_TYPES.NUMBER || argType === DATA_TYPES.BINARY_INTEGER) {\n\t\tif (isEmpty) {\n\t\t\treturn {dir: BIND_IN, type: DB_TYPE_NUMBER, val: null};\n\t\t}\n\t\tconst value = stringToNumber(argValue);\n\t\tif (value === null) {\n\t\t\tthrow new Error(`Error in named parameter \"${argName}\": invalid value \"${inspect(argValue)}\" for type \"${argType}\"`);\n\t\t}\n\n\t\treturn {dir: BIND_IN, type: DB_TYPE_NUMBER, val: value};\n\t}\n\n\tif (argType === DATA_TYPES.DATE) {\n\t\tif (isEmpty) {\n\t\t\treturn {dir: BIND_IN, type: DB_TYPE_DATE, val: null};\n\t\t}\n\t\tif (typeof argValue !== 'string') {\n\t\t\tthrow new TypeError(`Error in named parameter \"${argName}\": invalid value \"${inspect(argValue)}\" for type \"${argType}\"`);\n\t\t}\n\t\tconst value = new Date(argValue);\n\t\tif (Number.isNaN(value.getTime())) {\n\t\t\tthrow new TypeError(`Error in named parameter \"${argName}\": invalid value \"${inspect(argValue)}\" for type \"${argType}\"`);\n\t\t}\n\n\t\treturn {dir: BIND_IN, type: DB_TYPE_DATE, val: value};\n\t}\n\n\tif (argType === DATA_TYPES.PL_SQL_TABLE || Array.isArray(argValue)) {\n\t\tconst value = typeof argValue === 'string' ? [argValue] : argValue;\n\n\t\treturn {dir: BIND_IN, type: DB_TYPE_VARCHAR, val: value};\n\t}\n\n\tthrow new Error(`Error in named parameter \"${argName}\": invalid binding type \"${argType}\"`);\n};\n\n/**\n *\tGet binding table for tracing.\n *\t@param argObj - The arguments to pass to the procedure\n *\t@param argTypes - The argument types.\n *\t@returns The text.\n */\nconst inspectBindings = (argObj: argObjType, argTypes: argsType): string => {\n\tconst rows = Object.entries(argObj).map(([key, value]) => {\n\t\treturn [key, value.toString(), typeof value, argTypes[key.toLowerCase()] ?? 'unknown'];\n\t});\n\n\tconst {text} = toTable(['id', 'value', 'value type', 'argument type'], rows);\n\n\treturn text;\n};\n\n/**\n *\tGet the sql statement and bindings for the procedure to execute for a fixed number of arguments\n *\t@param req - The req object represents the HTTP request. (only used for debugging)\n *\t@param procName - The procedure to execute\n *\t@param argObj - The arguments to pass to the procedure\n *\t@param databaseConnection - The database connection\n *\t@param argumentCache - The argument cache.\n *\t@returns The SQL statement and bindings for the procedure to execute\n */\nexport const getProcedureNamed = async (\n\treq: Request,\n\tprocName: string,\n\targObj: argObjType,\n\tdatabaseConnection: Connection,\n\targumentCache: ArgumentCache,\n): Promise<{sql: string; bind: BindParameters}> => {\n\tdebug(`getProcedureNamed: ${procName} arguments=`, argObj);\n\n\t// get the types of the arguments\n\tconst argTypes = await findArguments(procName, databaseConnection, argumentCache);\n\n\tconst sqlParameter: string[] = [];\n\n\tconst bindings: BindParameters = {};\n\n\t// bindings for the statement\n\tfor (const key in argObj) {\n\t\tconst parameterName = `p_${key}`;\n\t\tconst argValue = argObj[key];\n\t\tconst argType = argTypes[key.toLowerCase()];\n\t\tlet bind: BindParameter = {dir: BIND_IN, type: DB_TYPE_VARCHAR, val: argValue};\n\n\t\tif (argType) {\n\t\t\tbind = getBinding(key, argValue, argType);\n\t\t} else {\n\t\t\tconst text = inspectBindings(argObj, argTypes);\n\t\t\twarningMessage({\n\t\t\t\ttype: 'warning',\n\t\t\t\tmessage: `Error in named parameter \"${key}\": invalid binding type \"${argType}\"\\n\\n${text}`,\n\t\t\t\treq,\n\t\t\t});\n\t\t}\n\n\t\tsqlParameter.push(`${key}=>:${parameterName}`);\n\t\tbindings[parameterName] = bind;\n\t}\n\n\t// select statement\n\tconst sql = `${procName}(${sqlParameter.join(', ')})`;\n\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tdebug(sql);\n\t\tdebug(inspectBindings(argObj, argTypes));\n\t}\n\t/* v8 ignore stop */\n\n\treturn {sql, bind: bindings};\n};","import debugModule from 'debug';\nconst debug = debugModule('webplsql:parsePage');\n\nimport type {pageType, cookieType} from '../../types.ts';\n\n/**\n *\tParse the header and split it up into the individual components\n *\n * @param text - The text returned from the PL/SQL procedure.\n * @returns The parsed page.\n */\nexport const parsePage = (text: string): pageType => {\n\tconst page: pageType = {\n\t\tbody: '',\n\t\thead: {\n\t\t\tcookies: [],\n\t\t\totherHeaders: {},\n\t\t},\n\t\tfile: {\n\t\t\tfileType: null,\n\t\t\tfileSize: null,\n\t\t\tfileBlob: null,\n\t\t},\n\t};\n\n\t//\n\t//\t1)\tSplit up the text in header and body\n\t//\n\n\t// Find the end of the header identified by \\n\\n\n\tlet head = '';\n\tconst headerEndPosition = text.indexOf('\\n\\n');\n\tif (headerEndPosition === -1) {\n\t\thead = text;\n\t} else {\n\t\thead = text.slice(0, Math.max(0, headerEndPosition + 2));\n\t\tpage.body = text.slice(Math.max(0, headerEndPosition + 2));\n\t}\n\n\t//\n\t//\t2)\tparse the headers\n\t//\n\n\tdebug('parsing the headers received from PL/SQL');\n\thead.split('\\n').forEach((line) => {\n\t\tconst header = getHeader(line);\n\n\t\tif (header) {\n\t\t\tswitch (header.name.toLowerCase()) {\n\t\t\t\tcase 'set-cookie':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst cookie = parseCookie(header.value);\n\t\t\t\t\t\tdebug(`oracle header \"set-cookie\" with value \"${header.value}\" was received has been parsed to ${JSON.stringify(cookie)}`);\n\t\t\t\t\t\tif (cookie === null) {\n\t\t\t\t\t\t\tthrow new Error(`Unable to parse header \"set-cookie\" with value \"${header.value}\" received from PL/SQL`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpage.head.cookies.push(cookie);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'content-type':\n\t\t\t\t\tpage.head.contentType = header.value;\n\t\t\t\t\tdebug(`oracle header \"content-type\" with value \"${page.head.contentType}\" was parsed`);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'x-db-content-length':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst contentLength = Number.parseInt(header.value, 10);\n\t\t\t\t\t\tif (Number.isNaN(contentLength)) {\n\t\t\t\t\t\t\tthrow new TypeError(`Unable to parse header \"x-db-content-length\" with value \"${header.value}\" received from PL/SQL`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpage.head.contentLength = contentLength;\n\t\t\t\t\t\t\tdebug(`oracle header \"x-db-content-length\" with value \"${page.head.contentLength}\" was parsed`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'status':\n\t\t\t\t\t{\n\t\t\t\t\t\tconst statusCode = Number.parseInt(header.value, 10);\n\t\t\t\t\t\tif (Number.isNaN(statusCode)) {\n\t\t\t\t\t\t\tthrow new TypeError(`Unable to parse header \"status\" with value \"${header.value}\" received from PL/SQL`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpage.head.statusCode = statusCode;\n\t\t\t\t\t\t\tdebug(`oracle header \"status\" with value \"${page.head.statusCode}\" was parsed`);\n\t\t\t\t\t\t\tconst index = header.value.indexOf(' ');\n\t\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\t\tpage.head.statusDescription = header.value.slice(Math.max(0, index + 1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'location':\n\t\t\t\t\tpage.head.redirectLocation = header.value;\n\t\t\t\t\tdebug(`oracle header \"location\" with value \"${page.head.statusCode}\" was parsed`);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'x-oracle-ignore':\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tpage.head.otherHeaders[header.name] = header.value;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\treturn page;\n};\n\n/**\n *\tGet a header line\n *\t@param line - The line\n *\t@returns The header.\n */\nconst getHeader = (line: string): {name: string; value: string} | null => {\n\tconst index = line.indexOf(':');\n\n\tif (index !== -1) {\n\t\treturn {\n\t\t\tname: line.slice(0, Math.max(0, index)).trim(),\n\t\t\tvalue: line.slice(Math.max(0, index + 1)).trim(),\n\t\t};\n\t}\n\n\treturn null;\n};\n\n/**\n *\tParses a cookie string\n *\t@param text - The cookie string.\n *\t@returns The parsed cookie.\n */\nconst parseCookie = (text: string): cookieType | null => {\n\t// validate\n\tif (typeof text !== 'string' || text.trim().length === 0) {\n\t\treturn null;\n\t}\n\n\t// split the cookie into it's parts\n\tlet cookieElements = text.split(';');\n\n\t// trim cookie elements\n\tcookieElements = cookieElements.map((element) => element.trim());\n\n\t// get name and value\n\tconst firstElement = cookieElements[0];\n\tif (!firstElement) {\n\t\treturn null;\n\t}\n\tconst index = firstElement.indexOf('=');\n\tif (index <= 0) {\n\t\t// if the index is -1, there is no equal sign and if it's 0 the name is empty\n\t\treturn null;\n\t}\n\n\tconst cookie: cookieType = {\n\t\tname: firstElement.slice(0, Math.max(0, index)).trim(),\n\t\tvalue: firstElement.slice(Math.max(0, index + 1)).trim(),\n\t\toptions: {},\n\t};\n\n\t// remove the first element\n\tcookieElements.shift();\n\n\t// get the other options\n\tcookieElements.forEach((element) => {\n\t\tif (element.toLowerCase().startsWith('path=')) {\n\t\t\tcookie.options.path = element.slice(5);\n\t\t} else if (element.toLowerCase().startsWith('domain=')) {\n\t\t\tcookie.options.domain = element.slice(7);\n\t\t} else if (element.toLowerCase().startsWith('secure')) {\n\t\t\tcookie.options.secure = true;\n\t\t} else if (element.toLowerCase().startsWith('expires=')) {\n\t\t\tconst date = tryDecodeDate(element.slice(8));\n\t\t\tif (date) {\n\t\t\t\tcookie.options.expires = date;\n\t\t\t}\n\t\t} else if (element.toLowerCase().startsWith('httponly')) {\n\t\t\tcookie.options.httpOnly = true;\n\t\t}\n\t});\n\n\treturn cookie;\n};\n\n/**\n * Try to decode a date\n * @param value - The value to decode.\n * @returns The decoded date or null.\n */\nconst tryDecodeDate = (value: string): Date | null => {\n\tconst result = new Date(value);\n\tif (Number.isNaN(result.getTime())) {\n\t\treturn null;\n\t}\n\treturn result;\n};","/*\n *\tPage the raw page content and return the content to the client\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:sendResponse');\n\nimport stream from 'node:stream';\nimport {getBlock} from '../../util/trace.ts';\nimport type {Request, Response} from 'express';\nimport type {pageType} from '../../types.ts';\n\n/**\n * Pipe a readable to the response and await completion.\n * Listeners are attached before piping to avoid races.\n *\n * @param readable - The source readable stream.\n * @param res - The HTTP response stream.\n */\nconst pipeReadableToResponse = async (readable: stream.Readable, res: Response): Promise<void> => {\n\tawait new Promise<void>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst canAddResponseListener = typeof res.on === 'function';\n\t\tconst canRemoveResponseListener = typeof res.removeListener === 'function';\n\n\t\tconst cleanup = () => {\n\t\t\treadable.removeListener('end', onReadableEnd);\n\t\t\treadable.removeListener('close', onReadableClose);\n\t\t\treadable.removeListener('error', onReadableError);\n\t\t\tif (canRemoveResponseListener) {\n\t\t\t\tres.removeListener('finish', onResponseFinish);\n\t\t\t\tres.removeListener('close', onResponseClose);\n\t\t\t}\n\t\t};\n\n\t\tconst resolveOnce = () => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tresolve();\n\t\t};\n\n\t\tconst rejectOnce = (error: Error) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error);\n\t\t};\n\n\t\tconst onReadableEnd = () => {\n\t\t\tresolveOnce();\n\t\t};\n\n\t\tconst onReadableClose = () => {\n\t\t\tresolveOnce();\n\t\t};\n\n\t\tconst onReadableError = (error: Error) => {\n\t\t\trejectOnce(error);\n\t\t};\n\n\t\tconst onResponseFinish = () => {\n\t\t\tresolveOnce();\n\t\t};\n\n\t\tconst onResponseClose = () => {\n\t\t\tresolveOnce();\n\t\t};\n\n\t\treadable.on('end', onReadableEnd);\n\t\treadable.on('close', onReadableClose);\n\t\treadable.on('error', onReadableError);\n\t\tif (canAddResponseListener) {\n\t\t\tres.on('finish', onResponseFinish);\n\t\t\tres.on('close', onResponseClose);\n\t\t}\n\n\t\ttry {\n\t\t\treadable.pipe(res);\n\t\t} catch (error: unknown) {\n\t\t\trejectOnce(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t});\n};\n\n/**\n *\tSend \"default\" response to the browser\n *\t@param _req - The req object represents the HTTP request.\n *\t@param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n *\t@param page - The page to send.\n */\nexport const sendResponse = async (_req: Request, res: Response, page: pageType): Promise<void> => {\n\tconst debugText: string[] = [];\n\n\t// Send the \"cookies\"\n\tpage.head.cookies.forEach((cookie) => {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.cookie: name=\"${cookie.name}\" value=\"${cookie.value}\" options=${JSON.stringify(cookie.options)}`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.cookie(cookie.name, cookie.value, cookie.options);\n\t});\n\n\t// If there is a \"redirectLocation\" header, we immediately redirect and return\n\tif (typeof page.head.redirectLocation === 'string' && page.head.redirectLocation.length > 0) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.redirect(302, \"${page.head.redirectLocation}\")`);\n\t\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.redirect(302, page.head.redirectLocation);\n\t\treturn;\n\t}\n\n\t// Send all the \"otherHeaders\"\n\tfor (const key in page.head.otherHeaders) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.set(\"${key}\", \"${page.head.otherHeaders[key]}\")`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.set(key, page.head.otherHeaders[key]);\n\t}\n\n\t// If this is a file download, we eventually set the \"Content-Type\" and the file content and then return.\n\tif (page.file.fileType === 'B' || page.file.fileType === 'F') {\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (typeof page.head.contentType === 'string' && page.head.contentType.length > 0) {\n\t\t\theaders['Content-Type'] = page.head.contentType;\n\t\t}\n\n\t\tif (typeof page.file.fileSize === 'number' && page.file.fileSize > 0) {\n\t\t\theaders['Content-Length'] = page.file.fileSize.toString();\n\t\t}\n\n\t\tif (Object.keys(headers).length > 0) {\n\t\t\t/* v8 ignore start */\n\t\t\tif (debug.enabled) {\n\t\t\t\tdebugText.push(`res.writeHead(200, ${JSON.stringify(headers)})`);\n\t\t\t}\n\t\t\t/* v8 ignore stop */\n\n\t\t\tres.writeHead(200, headers);\n\t\t}\n\n\t\t// Check if fileBlob is a stream\n\t\tif (page.file.fileBlob instanceof stream.Readable) {\n\t\t\t/* v8 ignore start */\n\t\t\tif (debug.enabled) {\n\t\t\t\tdebugText.push(`res.pipe(\"${page.file.fileType ?? ''}\") - streaming`);\n\t\t\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t\t\t}\n\t\t\t/* v8 ignore stop */\n\n\t\t\tawait pipeReadableToResponse(page.file.fileBlob, res);\n\t\t} else {\n\t\t\t/* v8 ignore start */\n\t\t\tif (debug.enabled) {\n\t\t\t\tdebugText.push(`res.end(\"${page.file.fileType ?? ''}\") - buffer`);\n\t\t\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t\t\t}\n\t\t\t/* v8 ignore stop */\n\n\t\t\tres.end(page.file.fileBlob, 'binary');\n\t\t}\n\t\treturn;\n\t}\n\n\t// Is the a \"contentType\" header\n\tif (typeof page.head.contentType === 'string' && page.head.contentType.length > 0) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.set(\"Content-Type\", \"${page.head.contentType}\")`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.set('Content-Type', page.head.contentType);\n\t}\n\n\t// If we have a \"Status\" header, we send the header and then return.\n\tif (typeof page.head.statusCode === 'number') {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebugText.push(`res.status(page.head.statusCode).send(\"${page.head.statusDescription ?? ''}\")`);\n\t\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tres.status(page.head.statusCode).send(page.head.statusDescription);\n\t\treturn;\n\t}\n\n\t// Send the body\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tif (page.body instanceof stream.Readable) {\n\t\t\tdebugText.push(`${'-'.repeat(60)}\\n[Stream Body]`);\n\t\t} else {\n\t\t\tdebugText.push(`${'-'.repeat(60)}\\n${page.body}`);\n\t\t}\n\t\tdebug(getBlock('RESPONSE', debugText.join('\\n')));\n\t}\n\t/* v8 ignore stop */\n\n\tif (page.body instanceof stream.Readable) {\n\t\tawait pipeReadableToResponse(page.body, res);\n\t} else {\n\t\tres.send(page.body);\n\t}\n};","/*\n *\tRequestError\n */\n\nimport type {environmentType} from '../../types.ts';\nimport type {BindParameters} from 'oracledb';\n\nexport class ProcedureError extends Error {\n\ttimestamp: Date;\n\tenvironment: environmentType;\n\tsql: string;\n\tbind: BindParameters;\n\n\t/**\n\t * @param message - The error message.\n\t * @param environment - The environment.\n\t * @param sql - The SQL to execute.\n\t * @param bind - The bind parameters.\n\t */\n\tconstructor(message: string, environment: environmentType, sql: string, bind: BindParameters) {\n\t\tsuper(message);\n\n\t\t// Maintains proper stack trace for where our error was thrown (only available on V8)\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, ProcedureError);\n\t\t}\n\n\t\t// Custom debugging information\n\t\tthis.timestamp = new Date();\n\t\tthis.environment = environment;\n\t\tthis.sql = sql;\n\t\tthis.bind = bind;\n\t}\n}","import {DEFAULT_CACHE_MAX_SIZE, CACHE_PRUNE_PERCENT} from '../../common/constants.ts';\n\ntype cacheEntryType<T> = {\n\thitCount: number;\n\tvalue: T;\n};\n\n/**\n * Generic Cache class with LFU (Least Frequently Used) eviction policy.\n */\nexport class Cache<T> {\n\tcache: Map<string, cacheEntryType<T>>;\n\tmaxSize: number;\n\thits: number;\n\tmisses: number;\n\n\t/**\n\t * @param maxSize - Maximum number of entries in the cache.\n\t */\n\tconstructor(maxSize: number = DEFAULT_CACHE_MAX_SIZE) {\n\t\tthis.cache = new Map();\n\t\tthis.maxSize = maxSize;\n\t\tthis.hits = 0;\n\t\tthis.misses = 0;\n\t}\n\n\t/**\n\t * Get an entry from the cache.\n\t * @param key - The key.\n\t * @returns The value or undefined if not found.\n\t */\n\tget(key: string): T | undefined {\n\t\tconst entry = this.cache.get(key);\n\t\tif (entry) {\n\t\t\tentry.hitCount++;\n\t\t\tthis.hits++;\n\t\t\treturn entry.value;\n\t\t}\n\t\tthis.misses++;\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Set an entry in the cache.\n\t * @param key - The key.\n\t * @param value - The value.\n\t */\n\tset(key: string, value: T): void {\n\t\t// If updating an existing key, preserve its hitCount?\n\t\t// Typically LFU implies resetting or keeping.\n\t\t// For simplicity and avoiding complex aging, if we set it again, we reset hitCount or keep it?\n\t\t// The requirement is \"cache invalidation\" (delete) or \"cache loading\" (set).\n\t\t// If we overwrite, it's usually a new value. Let's reset hitCount to 0 for a fresh start or 1.\n\n\t\t// Ensure we have space\n\t\tif (this.cache.size >= this.maxSize && !this.cache.has(key)) {\n\t\t\tthis.prune();\n\t\t}\n\n\t\tthis.cache.set(key, {hitCount: 0, value});\n\t}\n\n\t/**\n\t * Delete an entry from the cache.\n\t * @param key - The key.\n\t */\n\tdelete(key: string): void {\n\t\tthis.cache.delete(key);\n\t}\n\n\t/**\n\t * Clear the cache.\n\t */\n\tclear(): void {\n\t\tthis.cache.clear();\n\t\tthis.hits = 0;\n\t\tthis.misses = 0;\n\t}\n\n\t/**\n\t * Prune the cache by removing the least frequently used entries.\n\t * Removes 10% of the cache size.\n\t */\n\tprune(): void {\n\t\t// Convert cache entries to an array\n\t\tconst entries = Array.from(this.cache.entries());\n\n\t\t// Sort entries by hitCount in ascending order\n\t\tentries.sort((a, b) => a[1].hitCount - b[1].hitCount);\n\n\t\t// Remove the bottom 10%\n\t\tconst removeCount = Math.max(1, Math.floor(this.maxSize * CACHE_PRUNE_PERCENT));\n\t\tconst keysToRemove = entries.slice(0, removeCount).map(([key]) => key);\n\n\t\tfor (const key of keysToRemove) {\n\t\t\tthis.cache.delete(key);\n\t\t}\n\t}\n\n\t/**\n\t * Get the size of the cache.\n\t * @returns The size.\n\t */\n\tget size(): number {\n\t\treturn this.cache.size;\n\t}\n\n\t/**\n\t * Get all keys in the cache.\n\t * @returns The keys.\n\t */\n\tkeys(): string[] {\n\t\treturn Array.from(this.cache.keys());\n\t}\n\n\t/**\n\t * Get cache statistics.\n\t * @returns The statistics.\n\t */\n\tgetStats(): {size: number; maxSize: number; hits: number; misses: number} {\n\t\treturn {\n\t\t\tsize: this.cache.size,\n\t\t\tmaxSize: this.maxSize,\n\t\t\thits: this.hits,\n\t\t\tmisses: this.misses,\n\t\t};\n\t}\n}","import debugModule from 'debug';\nconst debug = debugModule('webplsql:procedureSanitize');\n\nimport {BIND_IN, BIND_OUT, STRING, NUMBER} from '../../util/oracledb-provider.ts';\nimport z from 'zod';\nimport {RequestError} from './requestError.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {OWA_RESOLVED_NAME_MAX_LEN} from '../../../common/constants.ts';\nimport type {Connection, Result, BindParameters} from 'oracledb';\nimport type {configPlSqlHandlerType, ProcedureNameCache} from '../../types.ts';\nimport {Cache} from '../../util/cache.ts';\n\nconst DEFAULT_EXCLUSION_LIST = ['sys.', 'dbms_', 'utl_', 'owa_', 'htp.', 'htf.', 'wpg_docload.', 'ctxsys.', 'mdsys.'];\n\nconst validationFunctionCache = new Cache<{valid: boolean}>();\n\n/**\n * Resolve the procedure name using dbms_utility.name_resolve.\n *\n * @param procName - The procedure name to resolve.\n * @param databaseConnection - The database connection.\n * @param procedureNameCache - The procedure name cache.\n * @returns The resolved canonical procedure name (SCHEMA.NAME).\n */\nconst resolveProcedureName = async (procName: string, databaseConnection: Connection, procedureNameCache: ProcedureNameCache): Promise<string> => {\n\t// Check cache\n\tconst cachedName = procedureNameCache.get(procName);\n\tif (cachedName) {\n\t\tdebug(`resolveProcedureName: Cache hit for \"${procName}\" -> \"${cachedName}\"`);\n\t\treturn cachedName;\n\t}\n\n\tdebug(`resolveProcedureName: Cache miss for \"${procName}\". Resolving in DB...`);\n\n\tconst sql = `\n\t\tDECLARE\n\t\t\tl_schema VARCHAR2(128);\n\t\t\tl_part1 VARCHAR2(128);\n\t\t\tl_part2 VARCHAR2(128);\n\t\t\tl_dblink VARCHAR2(128);\n\t\t\tl_part1_type NUMBER;\n\t\t\tl_object_number NUMBER;\n\t\tBEGIN\n\t\t\tdbms_utility.name_resolve(\n\t\t\t\tname => :name,\n\t\t\t\tcontext => 1,\n\t\t\t\tschema => l_schema,\n\t\t\t\tpart1 => l_part1,\n\t\t\t\tpart2 => l_part2,\n\t\t\t\tdblink => l_dblink,\n\t\t\t\tpart1_type => l_part1_type,\n\t\t\t\tobject_number => l_object_number\n\t\t\t);\n\t\t\t\n\t\t\t-- Reconstruct the canonical name\n\t\t\t-- If it's a package procedure: schema.package.procedure\n\t\t\t-- If it's a standalone procedure: schema.procedure\n\t\t\t\n\t\t\tIF l_part1 IS NOT NULL THEN\n\t\t\t\t:resolved := l_schema || '.' || l_part1 || '.' || l_part2;\n\t\t\tELSE\n\t\t\t\t:resolved := l_schema || '.' || l_part2;\n\t\t\tEND IF;\n\t\tEND;\n\t`;\n\n\tconst bind: BindParameters = {\n\t\tname: {dir: BIND_IN, type: STRING, val: procName},\n\t\tresolved: {dir: BIND_OUT, type: STRING, maxSize: OWA_RESOLVED_NAME_MAX_LEN},\n\t};\n\n\ttry {\n\t\tconst result = await databaseConnection.execute(sql, bind);\n\t\tconst {resolved} = z.strictObject({resolved: z.string()}).parse(result.outBinds);\n\n\t\tif (!resolved) {\n\t\t\tthrow new RequestError(`Could not resolve procedure name \"${procName}\"`);\n\t\t}\n\n\t\tdebug(`resolveProcedureName: Resolved \"${procName}\" -> \"${resolved}\"`);\n\n\t\t// Update cache\n\t\tprocedureNameCache.set(procName, resolved);\n\n\t\treturn resolved;\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug(`resolveProcedureName: Error resolving \"${procName}\"`, err);\n\t\t/* v8 ignore stop */\n\n\t\t// Rethrow as RequestError to indicate 404/403\n\t\tthrow new RequestError(`Procedure \"${procName}\" not found or not accessible.\\n${errorToString(err)}`);\n\t}\n};\n\n/**\n * Sanitize the procedure name.\n *\n * @param procName - The procedure name.\n * @param databaseConnection - The database connection\n * @param options - the options for the middleware.\n * @param procedureNameCache - The procedure name cache.\n * @returns Promise resolving to final procedure name.\n */\nexport const sanitizeProcName = async (\n\tprocName: string,\n\tdatabaseConnection: Connection,\n\toptions: configPlSqlHandlerType,\n\tprocedureNameCache: ProcedureNameCache,\n): Promise<string> => {\n\tdebug('sanitizeProcName', procName);\n\n\t// make lowercase and trim\n\tlet finalProcName = procName.toLowerCase().trim();\n\n\t// remove special characters (basic sanity check before DB call)\n\tfinalProcName = removeSpecialCharacters(finalProcName);\n\n\t// check for default exclusions\n\tfor (const i of DEFAULT_EXCLUSION_LIST) {\n\t\tif (finalProcName.startsWith(i)) {\n\t\t\tconst error = `Procedure name \"${procName}\" is in default exclusion list \"${DEFAULT_EXCLUSION_LIST.join(',')}\"`;\n\t\t\t/* v8 ignore start */\n\t\t\tdebug(error);\n\t\t\t/* v8 ignore stop */\n\n\t\t\tthrow new RequestError(error);\n\t\t}\n\t}\n\n\t// check for custom exclusions\n\tif (options.exclusionList && options.exclusionList.length > 0) {\n\t\tfor (const i of options.exclusionList) {\n\t\t\tif (finalProcName.startsWith(i)) {\n\t\t\t\tconst error = `Procedure name \"${procName}\" is in custom exclusion list \"${options.exclusionList.join(',')}\"`;\n\t\t\t\t/* v8 ignore start */\n\t\t\t\tdebug(error);\n\t\t\t\t/* v8 ignore stop */\n\n\t\t\t\tthrow new RequestError(error);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check request validation function\n\tif (options.requestValidationFunction && options.requestValidationFunction.length > 0) {\n\t\t// Note: We might want to scope this cache too, but for now let's focus on the procedure name cache.\n\t\t// The original code used a global cache for this.\n\t\t// For strict correctness, we should probably verify the *resolved* name,\n\t\t// but legacy behavior checks the input name.\n\t\tconst valid = await requestValidationFunction(finalProcName, options.requestValidationFunction, databaseConnection);\n\t\tif (!valid) {\n\t\t\tconst error = `Procedure name \"${procName}\" is not valid according to the request validation function \"${options.requestValidationFunction}\"`;\n\t\t\t/* v8 ignore start */\n\t\t\tdebug(error);\n\t\t\t/* v8 ignore stop */\n\n\t\t\tthrow new RequestError(error);\n\t\t}\n\t}\n\n\t// NEW: Resolve the procedure name against the database\n\t// This prevents SQL injection and ensures the procedure exists\n\tconst resolvedName = await resolveProcedureName(finalProcName, databaseConnection, procedureNameCache);\n\n\treturn resolvedName;\n};\n\n/**\n * @param str - string\n * @returns string\n */\nconst removeSpecialCharacters = (str: string | null | undefined): string => {\n\tif (str === null || str === undefined) {\n\t\treturn '';\n\t}\n\n\tconst chars: string[] = [];\n\n\tfor (const c of str) {\n\t\tif ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c === '.' || c === '_' || c === '#' || c === '$') {\n\t\t\tchars.push(c);\n\t\t}\n\t}\n\n\treturn chars.join('');\n};\n\n/**\n * @param procName - The procedure name.\n * @param requestValidationFunction - The request validation function.\n * @param databaseConnection - The database connection\n * @returns Promise resolving to final procedure name.\n */\nconst loadRequestValid = async (procName: string, requestValidationFunction: string, databaseConnection: Connection): Promise<boolean> => {\n\tconst bind: BindParameters = {\n\t\tproc: {dir: BIND_IN, type: STRING, val: procName},\n\t\tvalid: {dir: BIND_OUT, type: NUMBER},\n\t};\n\n\tconst SQL = [\n\t\t'DECLARE',\n\t\t' l_valid NUMBER := 0;',\n\t\t'BEGIN',\n\t\t` IF (${requestValidationFunction}(:proc)) THEN`,\n\t\t' l_valid := 1;',\n\t\t' END IF;',\n\t\t' :valid := l_valid;',\n\t\t'END;',\n\t].join('\\n');\n\n\tlet result: Result<unknown> = {};\n\ttry {\n\t\tresult = await databaseConnection.execute(SQL, bind);\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug('result', result);\n\t\t/* v8 ignore stop */\n\n\t\tconst message = `Error when validating procedure name \"${procName}\"\\n${SQL}\\n${errorToString(err)}`;\n\t\tthrow new RequestError(message);\n\t}\n\n\ttry {\n\t\tconst data = z.strictObject({valid: z.number()}).parse(result.outBinds);\n\t\treturn data.valid === 1;\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tdebug('result', result.outBinds);\n\t\t/* v8 ignore stop */\n\n\t\tconst message = `Internal error when parsing ${String(result.outBinds)}\\n${errorToString(err)}`;\n\t\tthrow new Error(message);\n\t}\n};\n\n/**\n * Request validation function.\n *\n * @param procName - The procedure name.\n * @param validationFunction - The request validation function.\n * @param databaseConnection - The database connection\n * @returns Promise resolving to final procedure name.\n */\nconst requestValidationFunction = async (procName: string, validationFunction: string, databaseConnection: Connection): Promise<boolean> => {\n\tdebug('requestValidationFunction', procName, validationFunction);\n\n\t// calculate the key\n\tconst key = procName.toLowerCase();\n\n\t// lookup in the cache\n\tconst cacheEntry = validationFunctionCache.get(key);\n\n\t// if we found the procedure in the cache, we return it (hitCount already incremented by get)\n\tif (cacheEntry !== undefined) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebug(`requestValidationFunction: procedure \"${procName}\" found in cache`);\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\treturn cacheEntry.valid;\n\t}\n\n\t// load from database\n\t/* v8 ignore start */\n\tif (debug.enabled) {\n\t\tdebug(`requestValidationFunction: procedure \"${procName}\" not found in cache and must be loaded`);\n\t}\n\t/* v8 ignore stop */\n\n\tconst valid = await loadRequestValid(procName, validationFunction, databaseConnection);\n\n\t// add to the cache\n\tvalidationFunctionCache.set(key, {valid});\n\n\treturn valid;\n};","import {Readable} from 'node:stream';\nimport {BIND_OUT, BIND_INOUT, STRING, NUMBER} from '../../util/oracledb-provider.ts';\nimport z from 'zod';\nimport debugModule from 'debug';\nimport {ProcedureError} from './procedureError.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {OWA_STREAM_CHUNK_SIZE, OWA_STREAM_BUFFER_SIZE} from '../../../common/constants.ts';\nimport type {Connection, BindParameters} from 'oracledb';\n\nconst debug = debugModule('webplsql:owaPageStream');\n\nexport class OWAPageStream extends Readable {\n\tdatabaseConnection: Connection;\n\tchunkSize: number;\n\tisDone: boolean;\n\n\t/**\n\t * @param databaseConnection - The database connection.\n\t */\n\tconstructor(databaseConnection: Connection) {\n\t\tsuper({highWaterMark: OWA_STREAM_BUFFER_SIZE}); // 16KB buffer\n\t\tthis.databaseConnection = databaseConnection;\n\t\tthis.chunkSize = OWA_STREAM_CHUNK_SIZE;\n\t\tthis.isDone = false;\n\t}\n\n\t/**\n\t * Fetch a chunk of the page from the database.\n\t * @returns The array of lines fetched.\n\t */\n\tasync fetchChunk(): Promise<string[]> {\n\t\tif (this.isDone) return [];\n\n\t\tconst bindParameter: BindParameters = {\n\t\t\tlines: {dir: BIND_OUT, type: STRING, maxArraySize: this.chunkSize},\n\t\t\tirows: {dir: BIND_INOUT, type: NUMBER, val: this.chunkSize},\n\t\t};\n\n\t\tconst sqlStatement = 'BEGIN owa.get_page(thepage=>:lines, irows=>:irows); END;';\n\n\t\ttry {\n\t\t\tconst result = await this.databaseConnection.execute(sqlStatement, bindParameter);\n\t\t\tconst {lines, irows} = z.strictObject({irows: z.number(), lines: z.array(z.string())}).parse(result.outBinds);\n\n\t\t\tdebug(`fetched ${lines.length} lines (irows=${irows})`);\n\n\t\t\t// If we got fewer lines than requested, OR if we got 0 lines, we are done\n\t\t\tif (lines.length < this.chunkSize) {\n\t\t\t\tthis.isDone = true;\n\t\t\t}\n\n\t\t\treturn lines;\n\t\t} catch (err) {\n\t\t\tif (err instanceof ProcedureError) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tthrow new ProcedureError(`OWAPageStream: error when getting page\\n${errorToString(err)}`, {}, sqlStatement, bindParameter);\n\t\t}\n\t}\n\n\t/**\n\t * @override\n\t * @param _size - The size hint (unused).\n\t */\n\toverride _read(_size: number): void {\n\t\tthis.fetchChunk()\n\t\t\t.then((lines) => {\n\t\t\t\tif (lines.length > 0) {\n\t\t\t\t\tthis.push(lines.join(''));\n\t\t\t\t}\n\n\t\t\t\t// After fetching, check if we're done\n\t\t\t\tif (this.isDone) {\n\t\t\t\t\tthis.push(null);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tthis.destroy(err instanceof Error ? err : new Error(String(err)));\n\t\t\t});\n\t}\n\n\t/**\n\t * Add initial body content to the stream.\n\t * @param content - The initial content to prepend.\n\t */\n\taddBody(content: string): void {\n\t\tif (content && content.length > 0) {\n\t\t\tthis.push(content);\n\t\t}\n\t}\n}","import fs from 'node:fs';\nimport path from 'node:path';\nimport type {procedureTraceEntry} from '../types.ts';\n\nclass TraceManager {\n\tenabled = false;\n\tfilename = 'trace.json.log';\n\tmaxEntries = 1000;\n\n\t/**\n\t * Toggle tracing\n\t * @param enabled - New state\n\t */\n\tsetEnabled(enabled: boolean): void {\n\t\tthis.enabled = enabled;\n\t}\n\n\t/**\n\t * Is tracing enabled?\n\t * @returns The state\n\t */\n\tisEnabled(): boolean {\n\t\treturn this.enabled;\n\t}\n\n\t/**\n\t * Add a trace entry\n\t * @param entry - The trace entry\n\t */\n\taddTrace(entry: procedureTraceEntry): void {\n\t\tif (!this.enabled) return;\n\n\t\ttry {\n\t\t\tconst line = JSON.stringify(entry) + '\\n';\n\t\t\tfs.appendFileSync(this.filename, line);\n\t\t} catch (err) {\n\t\t\tconsole.error('TraceManager: error writing trace', err);\n\t\t}\n\t}\n\n\t/**\n\t * Clear all traces\n\t */\n\tclear(): void {\n\t\ttry {\n\t\t\tif (fs.existsSync(this.filename)) {\n\t\t\t\tfs.truncateSync(this.filename, 0);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.error('TraceManager: error clearing traces', err);\n\t\t}\n\t}\n\n\t/**\n\t * Get the full path to the trace file\n\t * @returns The path\n\t */\n\tgetFilePath(): string {\n\t\treturn path.resolve(this.filename);\n\t}\n}\n\nexport const traceManager = new TraceManager();","/*\n *\tInvoke the Oracle procedure and return the raw content of the page\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:procedure');\n\nimport {BIND_IN, BIND_OUT, BIND_INOUT, STRING, NUMBER, BLOB} from '../../util/oracledb-provider.ts';\nimport stream from 'node:stream';\nimport z from 'zod';\n\nimport {uploadFile} from './upload.ts';\nimport {getProcedureVariable} from './procedureVariable.ts';\nimport {getProcedureNamed} from './procedureNamed.ts';\nimport {parsePage} from './parsePage.ts';\nimport {sendResponse} from './sendResponse.ts';\nimport {ProcedureError} from './procedureError.ts';\nimport {RequestError} from './requestError.ts';\nimport {inspect, getBlock} from '../../util/trace.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {sanitizeProcName} from './procedureSanitize.ts';\nimport {OWAPageStream} from './owaPageStream.ts';\nimport {traceManager} from '../../util/traceManager.ts';\nimport type {procedureTraceEntry} from '../../../frontend/types.ts';\nimport type {Request, Response} from 'express';\nimport type {Connection, Result, Lob, BindParameters} from 'oracledb';\nimport type {argObjType, fileUploadType, environmentType, configPlSqlHandlerType, ProcedureNameCache, ArgumentCache} from '../../types.ts';\n\n/**\n *\tGet the procedure and arguments to execute\n *\t@param req - The req object represents the HTTP request. (only used for debugging)\n *\t@param procName - The procedure to execute\n *\t@param argObj - The arguments to pass to the procedure\n *\t@param options - The options for the middleware\n *\t@param databaseConnection - The database connection\n *\t@param procedureNameCache - The procedure name cache.\n *\t@param argumentCache - The argument cache.\n *\t@returns The SQL statement and bindings for the procedure to execute\n */\nconst getProcedure = async (\n\treq: Request,\n\tprocName: string,\n\targObj: argObjType,\n\toptions: configPlSqlHandlerType,\n\tdatabaseConnection: Connection,\n\tprocedureNameCache: ProcedureNameCache,\n\targumentCache: ArgumentCache,\n): Promise<{sql: string; bind: BindParameters; resolvedName?: string}> => {\n\t// path alias\n\tif (options.pathAlias?.toLowerCase() === procName.toLowerCase()) {\n\t\t/* v8 ignore start */\n\t\tdebug(`getProcedure: path alias \"${options.pathAlias}\" redirects to \"${options.pathAliasProcedure}\"`);\n\t\t/* v8 ignore stop */\n\t\treturn {\n\t\t\tsql: `${options.pathAliasProcedure}(p_path=>:p_path)`,\n\t\t\tbind: {\n\t\t\t\tp_path: {dir: BIND_IN, type: STRING, val: procName},\n\t\t\t},\n\t\t};\n\t}\n\n\t// check if we use variable arguments\n\tconst useVariableArguments = procName.startsWith('!');\n\n\t// sanitize procedure name\n\tconst rawName = useVariableArguments ? procName.slice(1) : procName;\n\tconst sanitizedProcName = await sanitizeProcName(rawName, databaseConnection, options, procedureNameCache);\n\n\t// run procedure\n\treturn useVariableArguments\n\t\t? {\n\t\t\t\t...getProcedureVariable(req, sanitizedProcName, argObj),\n\t\t\t\tresolvedName: sanitizedProcName,\n\t\t\t}\n\t\t: {\n\t\t\t\t...(await getProcedureNamed(req, sanitizedProcName, argObj, databaseConnection, argumentCache)),\n\t\t\t\tresolvedName: sanitizedProcName,\n\t\t\t};\n};\n\n/**\n * Prepare procedure\n *\n * NOTE:\n * \t1) dbms_session.modify_package_state(dbms_session.reinitialize) is used to ensure a stateless environment by resetting package state (dbms_session.reset_package)\n *\n * @param cgiObj - The cgi of the procedure to invoke.\n * @param databaseConnection - Database connection.\n * @returns Promise resolving to void.\n */\nconst procedurePrepare = async (cgiObj: environmentType, databaseConnection: Connection): Promise<void> => {\n\tlet sqlStatement = 'BEGIN dbms_session.modify_package_state(dbms_session.reinitialize); END;';\n\ttry {\n\t\tawait databaseConnection.execute(sqlStatement);\n\t} catch (err) {\n\t\tthrow new ProcedureError(`procedurePrepare: error when preparing procedure\\n${errorToString(err)}`, cgiObj, sqlStatement, {});\n\t}\n\n\t// htbuf_len: reduce this limit based on your worst-case character size.\n\t// For most character sets, this will be 2 bytes per character, so the limit would be 127.\n\t// For UTF8 Unicode, it's 3 bytes per character, meaning the limit should be 85.\n\t// For the newer AL32UTF8 Unicode, it's 4 bytes per character, and the limit should be 63.\n\tsqlStatement = 'BEGIN owa.init_cgi_env(:cgicount, :cginames, :cgivalues); owa.user_id := :remote_user; htp.init; htp.htbuf_len := 63; END;';\n\tconst bindParameter: BindParameters = {\n\t\tcgicount: {dir: BIND_IN, type: NUMBER, val: Object.keys(cgiObj).length},\n\t\tcginames: {dir: BIND_IN, type: STRING, val: Object.keys(cgiObj)},\n\t\tcgivalues: {dir: BIND_IN, type: STRING, val: Object.values(cgiObj)},\n\t\tremote_user: {dir: BIND_IN, type: STRING, val: (cgiObj.REMOTE_USER ?? '').slice(0, 30)},\n\t};\n\ttry {\n\t\tawait databaseConnection.execute(sqlStatement, bindParameter);\n\t} catch (err) {\n\t\tthrow new ProcedureError(`procedurePrepare: error when preparing procedure\\n${errorToString(err)}`, cgiObj, sqlStatement, bindParameter);\n\t}\n};\n\n/**\n * Execute procedure\n *\n * @param para - The statement and binding to use when executing the procedure.\n * @param para.sql - The SQL statement.\n * @param para.bind - The bind parameters.\n * @param databaseConnection - Database connection.\n * @returns Promise resolving to void.\n */\nconst procedureExecute = async (para: {sql: string; bind: BindParameters}, databaseConnection: Connection): Promise<void> => {\n\tconst sqlStatement = `BEGIN ${para.sql}; END;`;\n\n\ttry {\n\t\tawait databaseConnection.execute(sqlStatement, para.bind);\n\t} catch (err) {\n\t\tthrow new ProcedureError(`procedureExecute: error when executing procedure:\\n${sqlStatement}\\n${errorToString(err)}`, {}, para.sql, para.bind);\n\t}\n};\n\n/**\n * Download files from procedure\n *\n * @param fileBlob - The blob eventually containing the file.\n * @param databaseConnection - Database connection.\n * @returns Promise resolving to the result.\n */\nconst procedureDownloadFiles = async (\n\tfileBlob: Lob,\n\tdatabaseConnection: Connection,\n): Promise<{fileType: string; fileSize: number; fileBlob: stream.Readable | null}> => {\n\tconst bindParameter: BindParameters = {\n\t\tfileType: {dir: BIND_OUT, type: STRING},\n\t\tfileSize: {dir: BIND_OUT, type: NUMBER},\n\t\tfileBlob: {dir: BIND_INOUT, type: BLOB, val: fileBlob},\n\t};\n\n\tconst sqlStatement = `\nDECLARE\n\tl_file_type\t\tVARCHAR2(32767)\t:= '';\n\tl_file_size\t\tINTEGER\t\t\t:= 0;\nBEGIN\n\tIF (wpg_docload.is_file_download()) THEN\n\t\twpg_docload.get_download_file(l_file_type);\n\t\tIF (l_file_type = 'B') THEN\n\t\t\twpg_docload.get_download_blob(:fileBlob);\n\t\t\tl_file_size := dbms_lob.getlength(:fileBlob);\n\t\tEND IF;\n\tEND IF;\n\t:fileType := l_file_type;\n\t:fileSize := l_file_size;\nEND;\n`;\n\n\tlet result: Result<unknown> | null = null;\n\ttry {\n\t\tresult = await databaseConnection.execute(sqlStatement, bindParameter);\n\t} catch (err) {\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebug(getBlock('procedureDownloadFiles: results', inspect(result)));\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\tthrow new ProcedureError(`procedureDownloadFiles: error when downloading files\\n${errorToString(err)}`, {}, sqlStatement, bindParameter);\n\t}\n\n\treturn z\n\t\t.object({\n\t\t\tfileType: z\n\t\t\t\t.string()\n\t\t\t\t.nullable()\n\t\t\t\t.transform((val) => val ?? ''),\n\t\t\tfileSize: z\n\t\t\t\t.number()\n\t\t\t\t.nullable()\n\t\t\t\t.transform((val) => val ?? 0),\n\t\t\tfileBlob: z.instanceof(stream.Readable).nullable(),\n\t\t})\n\t\t.parse(result.outBinds);\n};\n\n/**\n * Invoke the Oracle procedure and return the page content\n *\n * @param req - The req object represents the HTTP request.\n * @param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n * @param argObj - - The arguments of the procedure to invoke.\n * @param cgiObj - The cgi of the procedure to invoke.\n * @param filesToUpload - Array of files to be uploaded\n * @param options - the options for the middleware.\n * @param databaseConnection - Database connection.\n * @param procedureNameCache - The procedure name cache.\n * @param argumentCache - The argument cache.\n * @returns Promise resolving to the page content generated by the executed procedure\n */\nexport const invokeProcedure = async (\n\treq: Request,\n\tres: Response,\n\targObj: argObjType,\n\tcgiObj: environmentType,\n\tfilesToUpload: fileUploadType[],\n\toptions: configPlSqlHandlerType,\n\tdatabaseConnection: Connection,\n\tprocedureNameCache: ProcedureNameCache,\n\targumentCache: ArgumentCache,\n): Promise<void> => {\n\tdebug('invokeProcedure: begin');\n\n\tconst startTime = Date.now();\n\tlet traceData: procedureTraceEntry | null = null;\n\n\tif (traceManager.isEnabled()) {\n\t\ttraceData = {\n\t\t\tid: Math.random().toString(36).slice(2, 15),\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsource: cgiObj.REMOTE_ADDR ?? '',\n\t\t\turl: req.originalUrl,\n\t\t\tmethod: req.method,\n\t\t\tstatus: 'pending',\n\t\t\tduration: 0,\n\t\t\tcgi: cgiObj,\n\t\t\theaders: req.headers as Record<string, string>,\n\t\t\tcookies: req.cookies,\n\t\t\tuploads: filesToUpload.map((f) => ({\n\t\t\t\toriginalname: f.originalname,\n\t\t\t\tmimetype: f.mimetype,\n\t\t\t\tsize: f.size,\n\t\t\t})),\n\t\t};\n\t}\n\n\ttry {\n\t\t// 1) upload files\n\t\tdebug(`invokeProcedure: upload \"${filesToUpload.length}\" files`);\n\t\tif (filesToUpload.length > 0) {\n\t\t\tif (typeof options.documentTable === 'string' && options.documentTable.length > 0) {\n\t\t\t\tconst {documentTable} = options;\n\n\t\t\t\tawait Promise.all(filesToUpload.map((file) => uploadFile(file, documentTable, databaseConnection)));\n\t\t\t} else {\n\t\t\t\t// FIXME: this should be standartized\n\t\t\t\tconsole.warn(`Unable to upload \"${filesToUpload.length}\" files because the option \"\"doctable\" has not been defined`);\n\t\t\t}\n\t\t}\n\n\t\t// 2) get procedure to execute and the arguments\n\n\t\tdebug('invokeProcedure: get procedure to execute and the arguments');\n\t\t// Extract the raw procedure name from params\n\t\tconst rawProcName = Array.isArray(req.params.name) ? req.params.name[0] : req.params.name;\n\t\tif (!rawProcName) {\n\t\t\tthrow new RequestError('No procedure name provided');\n\t\t}\n\t\tconst para = await getProcedure(req, rawProcName, argObj, options, databaseConnection, procedureNameCache, argumentCache);\n\n\t\tif (traceData) {\n\t\t\ttraceData.procedure = para.resolvedName;\n\t\t\ttraceData.parameters = para.bind as Record<string, unknown> | unknown[];\n\t\t}\n\n\t\t// 3) prepare the session\n\n\t\tdebug('invokeProcedure: prepare the session');\n\t\tawait procedurePrepare(cgiObj, databaseConnection);\n\n\t\t// 4) execute the procedure\n\n\t\tdebug('invokeProcedure: execute the session');\n\t\ttry {\n\t\t\tawait procedureExecute(para, databaseConnection);\n\t\t} catch (err) {\n\t\t\t// Invalidation Logic\n\t\t\tif (err instanceof ProcedureError) {\n\t\t\t\tconst errorString = err.toString();\n\t\t\t\t// Check for ORA-04068, ORA-04061, ORA-04065, ORA-06550\n\t\t\t\tif (errorString.includes('ORA-04068') || errorString.includes('ORA-04061') || errorString.includes('ORA-04065') || errorString.includes('ORA-06550')) {\n\t\t\t\t\tdebug(`invokeProcedure: detected invalidation error (${errorString}). Clearing caches.`);\n\n\t\t\t\t\t// Clear name resolution cache for the input name\n\t\t\t\t\tif (rawProcName) {\n\t\t\t\t\t\tprocedureNameCache.delete(rawProcName);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Clear argument cache for the resolved name\n\t\t\t\t\tif (para.resolvedName) {\n\t\t\t\t\t\targumentCache.delete(para.resolvedName.toUpperCase());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\t// 5) get the page returned from the procedure\n\t\tdebug('invokeProcedure: get the page returned from the procedure');\n\n\t\tconst streamInstance = new OWAPageStream(databaseConnection);\n\t\tconst lines = await streamInstance.fetchChunk();\n\n\t\t/* v8 ignore start */\n\t\tif (debug.enabled) {\n\t\t\tdebug(getBlock('data', lines.join('')));\n\t\t}\n\t\t/* v8 ignore stop */\n\n\t\t// 6) download files\n\n\t\tdebug('invokeProcedure: download files');\n\t\tconst fileBlob = await databaseConnection.createLob(BLOB);\n\n\t\ttry {\n\t\t\tconst fileDownload = await procedureDownloadFiles(fileBlob, databaseConnection);\n\t\t\t/* v8 ignore start */\n\t\t\tif (debug.enabled) {\n\t\t\t\tdebug(getBlock('fileDownload', inspect({fileType: fileDownload.fileType, fileSize: fileDownload.fileSize})));\n\t\t\t}\n\t\t\t/* v8 ignore stop */\n\n\t\t\t// 7) parse the page\n\n\t\t\tdebug('invokeProcedure: parse the page');\n\t\t\t// We parse the headers from the first chunk\n\t\t\tconst pageComponents = parsePage(lines.join(''));\n\n\t\t\t// add \"Server\" header\n\t\t\tpageComponents.head.server = cgiObj.SERVER_SOFTWARE ?? '';\n\n\t\t\t// add file download information\n\t\t\tif (fileDownload.fileType !== '' && fileDownload.fileSize > 0 && fileDownload.fileBlob !== null) {\n\t\t\t\tpageComponents.file.fileType = fileDownload.fileType;\n\t\t\t\tpageComponents.file.fileSize = fileDownload.fileSize;\n\t\t\t\tpageComponents.file.fileBlob = fileDownload.fileBlob;\n\n\t\t\t\tif (traceData) {\n\t\t\t\t\ttraceData.downloads = {\n\t\t\t\t\t\tfileType: fileDownload.fileType,\n\t\t\t\t\t\tfileSize: fileDownload.fileSize,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// For normal pages, we use the stream.\n\t\t\t\t// Prepend the initial body (parsed by parsePage) to the stream\n\t\t\t\tif (typeof pageComponents.body === 'string' && pageComponents.body.length > 0) {\n\t\t\t\t\tstreamInstance.addBody(pageComponents.body);\n\t\t\t\t}\n\t\t\t\t// Use the stream as the body\n\t\t\t\tpageComponents.body = streamInstance;\n\n\t\t\t\tif (traceData) {\n\t\t\t\t\t// Buffer HTML if tracing enabled\n\t\t\t\t\tlet htmlBuffer = typeof pageComponents.body === 'string' ? pageComponents.body : lines.join('');\n\t\t\t\t\tconst MAX_HTML_SIZE = 1024 * 1024; // 1MB\n\n\t\t\t\t\tconst originalPush = streamInstance.push.bind(streamInstance);\n\t\t\t\t\tstreamInstance.push = (chunk) => {\n\t\t\t\t\t\tif (chunk !== null && htmlBuffer.length < MAX_HTML_SIZE) {\n\t\t\t\t\t\t\tconst str = String(chunk);\n\t\t\t\t\t\t\thtmlBuffer += str;\n\t\t\t\t\t\t\tif (htmlBuffer.length > MAX_HTML_SIZE) {\n\t\t\t\t\t\t\t\thtmlBuffer = htmlBuffer.slice(0, Math.max(0, MAX_HTML_SIZE)) + '... [truncated]';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn originalPush(chunk);\n\t\t\t\t\t};\n\n\t\t\t\t\t// Since we can't easily wait for the stream to finish here without blocking,\n\t\t\t\t\t// we'll have to finalize traceData when the stream ends.\n\t\t\t\t\tconst currentTrace = traceData;\n\t\t\t\t\tstreamInstance.on('end', () => {\n\t\t\t\t\t\tcurrentTrace.html = htmlBuffer;\n\t\t\t\t\t\tcurrentTrace.status = 'success';\n\t\t\t\t\t\tcurrentTrace.duration = Date.now() - startTime;\n\t\t\t\t\t\ttraceManager.addTrace(currentTrace);\n\t\t\t\t\t});\n\t\t\t\t\tstreamInstance.on('error', (err) => {\n\t\t\t\t\t\tcurrentTrace.status = 'fail';\n\t\t\t\t\t\tcurrentTrace.error = err instanceof Error ? err.message : String(err);\n\t\t\t\t\t\tcurrentTrace.duration = Date.now() - startTime;\n\t\t\t\t\t\ttraceManager.addTrace(currentTrace);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 8) send the page to browser\n\n\t\t\tdebug('invokeProcedure: send the page to browser');\n\t\t\tawait sendResponse(req, res, pageComponents);\n\n\t\t\tif (traceData?.downloads) {\n\t\t\t\ttraceData.status = 'success';\n\t\t\t\ttraceData.duration = Date.now() - startTime;\n\t\t\t\ttraceManager.addTrace(traceData);\n\t\t\t}\n\t\t} finally {\n\t\t\t// 9) cleanup\n\n\t\t\tdebug('invokeProcedure: cleanup');\n\t\t\tfileBlob.destroy();\n\t\t}\n\t} catch (err) {\n\t\tif (traceData) {\n\t\t\ttraceData.status = err instanceof ProcedureError ? 'error' : 'fail';\n\t\t\ttraceData.error = err instanceof Error ? err.message : String(err);\n\t\t\ttraceData.duration = Date.now() - startTime;\n\t\t\ttraceManager.addTrace(traceData);\n\t\t}\n\t\tthrow err;\n\t}\n\n\tdebug('invokeProcedure: end');\n};","/*\n *\tPrepare the CGI information\n */\n\nimport os from 'node:os';\nimport {URL} from 'node:url';\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:cgi');\n\nimport type {Request} from 'express';\nimport type {environmentType} from '../../types.ts';\n\nconst DEFAULT_CGI: environmentType = {\n\tPLSQL_GATEWAY: 'WebDb',\n\tGATEWAY_IVERSION: '2',\n\tSERVER_SOFTWARE: 'web_plsql',\n\tGATEWAY_INTERFACE: 'CGI/1.1',\n\tSERVER_PORT: '',\n\tSERVER_NAME: os.hostname(),\n\tREQUEST_METHOD: '',\n\tPATH_INFO: '',\n\tSCRIPT_NAME: '',\n\tREMOTE_ADDR: '',\n\tSERVER_PROTOCOL: '',\n\tREQUEST_PROTOCOL: '',\n\tREMOTE_USER: '',\n\tHTTP_COOKIE: '',\n\tHTTP_USER_AGENT: '',\n\tHTTP_HOST: '',\n\tHTTP_ACCEPT: '',\n\tHTTP_ACCEPT_ENCODING: '',\n\tHTTP_ACCEPT_LANGUAGE: '',\n\tHTTP_REFERER: '',\n\tHTTP_X_FORWARDED_FOR: '',\n\tWEB_AUTHENT_PREFIX: '',\n\tDAD_NAME: '',\n\tDOC_ACCESS_PATH: 'doc',\n\tDOCUMENT_TABLE: '',\n\tPATH_ALIAS: '',\n\t// oxlint-disable-next-line unicorn/text-encoding-identifier-case\n\tREQUEST_CHARSET: 'UTF8',\n\t// oxlint-disable-next-line unicorn/text-encoding-identifier-case\n\tREQUEST_IANA_CHARSET: 'UTF-8',\n\tSCRIPT_PREFIX: '',\n};\n\n/**\n * Create the HTTP_COOKIE string\n *\n * @param req - The req object represents the HTTP request.\n * @returns The string representation of the cookies.\n */\nconst getCookieString = (req: Request): string => {\n\tlet cookieString = '';\n\n\tfor (const propName in req.cookies) {\n\t\tcookieString += `${propName}=${req.cookies[propName]};`;\n\t}\n\n\tdebug('getCookieString', req.cookies, cookieString);\n\n\treturn cookieString;\n};\n\n/**\n * Get the script name and DAD name from a URL\n *\n * @param req - The req object represents the HTTP request.\n * @returns The DAD structure.\n */\nconst getPath = (req: Request): {script: string; prefix: string; dad: string} => {\n\t// create a valid url\n\tconst validUrl = `${req.protocol}://${os.hostname()}${req.originalUrl}`;\n\n\t// get the pathname from the url (new URL('https://example.org/abc/xyz?123').pathname => /abc/xyz)\n\tconst pathname = new URL(validUrl).pathname;\n\n\tconst tmp = trimPath(pathname.slice(0, Math.max(0, pathname.lastIndexOf('/') + 1)));\n\tconst script = `/${tmp}`;\n\tconst prefix = `/${tmp.slice(0, Math.max(0, tmp.lastIndexOf('/')))}`;\n\tconst dad = tmp.slice(Math.max(0, tmp.indexOf('/') + 1));\n\n\treturn {script, prefix, dad};\n};\n\n/**\n * Get a path that is not enclodes in slashes\n *\n * @param value - The value to trim.\n * @returns The trimmed value.\n */\nconst trimPath = (value: string): string => value.replaceAll(/^\\/+|\\/+$/gu, '');\n\n/**\n * Create a CGI object\n *\n * @param req - The req object represents the HTTP request.\n * @param doctable - The document table.\n * @param cgi - The additional cgi.\n * @param authenticatedUser - The authenticated user.\n * @returns CGI object\n */\nexport const getCGI = (req: Request, doctable: string, cgi: environmentType, authenticatedUser: string | null = null): environmentType => {\n\tconst PROTOCOL = req.protocol ? req.protocol.toUpperCase() : '';\n\tconst PATH = getPath(req);\n\n\tconst CGI: environmentType = {\n\t\tSERVER_PORT: typeof req.socket.localPort === 'number' ? req.socket.localPort.toString() : '',\n\t\tREQUEST_METHOD: req.method,\n\t\tPATH_INFO: Array.isArray(req.params.name) ? (req.params.name[0] ?? '') : (req.params.name ?? ''),\n\t\tSCRIPT_NAME: PATH.script,\n\t\tREMOTE_ADDR: (req.ip ?? '').replace('::ffff:', ''),\n\t\tSERVER_PROTOCOL: `${PROTOCOL}/${req.httpVersion}`,\n\t\tREQUEST_PROTOCOL: PROTOCOL,\n\t\tREMOTE_USER: authenticatedUser ?? '',\n\t\tAUTH_TYPE: authenticatedUser ? 'Basic' : '',\n\t\tHTTP_COOKIE: getCookieString(req),\n\t\tHTTP_USER_AGENT: req.get('user-agent') ?? '',\n\t\tHTTP_HOST: req.get('host') ?? '',\n\t\tHTTP_ACCEPT: req.get('accept') ?? '',\n\t\tHTTP_ACCEPT_ENCODING: req.get('accept-encoding') ?? '',\n\t\tHTTP_ACCEPT_LANGUAGE: req.get('accept-language') ?? '',\n\t\tHTTP_REFERER: req.get('referer') ?? '',\n\t\tHTTP_X_FORWARDED_FOR: req.get('x-forwarded-for') ?? '',\n\t\tDAD_NAME: PATH.dad,\n\t\tDOCUMENT_TABLE: doctable,\n\t\tSCRIPT_PREFIX: PATH.prefix,\n\t};\n\n\treturn Object.assign({}, DEFAULT_CGI, CGI, cgi);\n};","/**\n *\tIs the given value a string or an array of strings\n *\t@param value - The value to check.\n *\t@returns True if the value is a string or an array of strings\n */\nexport const isStringOrArrayOfString = (value: unknown): value is string | string[] =>\n\ttypeof value === 'string' || (Array.isArray(value) && value.every((element) => typeof element === 'string'));","/*\n *\tProcess the http request\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:request');\n\nimport util from 'node:util';\nimport {invokeProcedure} from './procedure.ts';\nimport {getCGI} from './cgi.ts';\nimport {getFiles} from './upload.ts';\nimport {RequestError} from './requestError.ts';\nimport {isStringOrArrayOfString} from '../../util/type.ts';\nimport type {Request, Response} from 'express';\nimport type {Pool} from 'oracledb';\nimport type {argObjType, configPlSqlHandlerType, ProcedureNameCache, ArgumentCache} from '../../types.ts';\n\n/**\n *\tNormalize the body by making sure that only \"simple\" parameters and no nested objects are submitted\n *\t@param req - The req object represents the HTTP request.\n *\t@returns The normalized body.\n */\nconst normalizeBody = (req: Request): Record<string, string | string[]> => {\n\tconst args: Record<string, string | string[]> = {};\n\n\t/* v8 ignore else - body validation */\n\tif (typeof req.body === 'object' && req.body !== null) {\n\t\tconst body = req.body as Record<string, unknown>;\n\t\tfor (const key in body) {\n\t\t\tconst value = body[key];\n\t\t\t/* v8 ignore else - type validation */\n\t\t\tif (isStringOrArrayOfString(value)) {\n\t\t\t\targs[key] = value;\n\t\t\t} else {\n\t\t\t\t/* v8 ignore next - invalid body type */\n\t\t\t\tthrow new RequestError(\n\t\t\t\t\t`The element \"${key}\" in the body is not a string or an array of strings!\\n${util.inspect(req.body, {showHidden: false, depth: null, colors: false})}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn args;\n};\n\n/**\n * Execute the request\n *\n * @param req - The req object represents the HTTP request.\n * @param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n * @param options - the options for the middleware.\n * @param connectionPool - The connection pool.\n * @param procedureNameCache - The procedure name cache.\n * @param argumentCache - The argument cache.\n * @param authenticatedUser - The authenticated user identity.\n * @returns Promise resolving to th page\n */\nexport const processRequest = async (\n\treq: Request,\n\tres: Response,\n\toptions: configPlSqlHandlerType,\n\tconnectionPool: Pool,\n\tprocedureNameCache: ProcedureNameCache,\n\targumentCache: ArgumentCache,\n\tauthenticatedUser: string | null = null,\n): Promise<void> => {\n\tdebug('processRequest: ENTER');\n\n\tif (typeof req.params.name !== 'string') {\n\t\t// FIXME: this should be standartized\n\t\tconsole.warn(`processRequest: WARNING: the req.params.name is not a string but an array of string: ${req.params.name}`);\n\t}\n\n\t// open database connection\n\tconst connection = await connectionPool.getConnection();\n\n\ttry {\n\t\t// Get the CGI\n\t\tconst cgiObj = getCGI(req, options.documentTable, options.cgi ?? {}, authenticatedUser);\n\t\tdebug('processRequest: cgiObj=', cgiObj);\n\n\t\t// Does the request contain any files\n\t\tconst filesToUpload = getFiles(req);\n\t\tdebug('processRequest: filesToUpload=', filesToUpload);\n\n\t\t// Add the query properties\n\t\tconst argObj: argObjType = {};\n\t\t// oxlint-disable-next-line typescript/no-explicit-any, unicorn/no-immediate-mutation\n\t\tObject.assign(argObj, req.query as any);\n\n\t\t// For add the files that must be uploaded, we now copy the actual filename to the appropriate parameter to the invoked procedure.\n\t\tfilesToUpload.reduce((aggregator, file) => {\n\t\t\taggregator[file.fieldname] = file.filename;\n\t\t\treturn aggregator;\n\t\t}, argObj);\n\n\t\t// Does the request contain a body\n\t\tObject.assign(argObj, normalizeBody(req));\n\t\tdebug('processRequest: argObj=', argObj);\n\n\t\t// invoke the Oracle procedure and get the page contenst\n\t\tawait invokeProcedure(req, res, argObj, cgiObj, filesToUpload, options, connection, procedureNameCache, argumentCache);\n\n\t\t// transaction mode\n\t\tif (options.transactionMode === 'rollback') {\n\t\t\tdebug('transactionMode: rollback');\n\t\t\tawait connection.rollback();\n\t\t} else if (typeof options.transactionMode === 'function') {\n\t\t\tdebug('transactionMode: callback');\n\t\t\tconst procName = Array.isArray(req.params.name) ? req.params.name[0] : req.params.name;\n\t\t\tconst result = options.transactionMode(connection, procName ?? '');\n\t\t\tdebug('transactionMode: callback restult', result);\n\t\t\tif (result && typeof result.then === 'function') {\n\t\t\t\tawait result;\n\t\t\t}\n\t\t} else {\n\t\t\tdebug('transactionMode: commit');\n\t\t\tawait connection.commit();\n\t\t}\n\t} finally {\n\t\t// close database connection\n\t\tawait connection.release();\n\t}\n\n\tdebug('processRequest: EXIT');\n};","import * as rotatingFileStream from 'rotating-file-stream';\nimport {JSON_LOG_ROTATION_SIZE, JSON_LOG_ROTATION_INTERVAL, JSON_LOG_MAX_ROTATED_FILES} from '../../common/constants.ts';\nimport {type logEntryType} from '../types.ts';\nimport {type MakeOptional} from '../../common/typeUtilities.ts';\n\nexport class JsonLogger {\n\tstream: rotatingFileStream.RotatingFileStream;\n\n\tconstructor(filename = 'error.json.log') {\n\t\tthis.stream = rotatingFileStream.createStream(filename, {\n\t\t\tsize: JSON_LOG_ROTATION_SIZE, // rotate every 10 MegaBytes written\n\t\t\tinterval: JSON_LOG_ROTATION_INTERVAL, // rotate daily\n\t\t\tmaxFiles: JSON_LOG_MAX_ROTATED_FILES, // maximum number of rotated files to keep\n\t\t\tcompress: 'gzip', // compress rotated files\n\t\t});\n\t}\n\n\t/**\n\t * Log an entry as NDJSON.\n\t * @param entry - The entry to log.\n\t */\n\tlog(entry: MakeOptional<logEntryType, 'timestamp'>): void {\n\t\ttry {\n\t\t\t// Ensure timestamp exists\n\t\t\tentry.timestamp ??= new Date().toISOString();\n\t\t\tconst line = JSON.stringify(entry);\n\t\t\tthis.stream.write(line + '\\n');\n\t\t} catch (err) {\n\t\t\tconsole.error('JsonLogger: Failed to write log', err);\n\t\t}\n\t}\n\n\t/**\n\t * Close the stream.\n\t */\n\tclose(): void {\n\t\tthis.stream.end();\n\t}\n}\n\nexport const jsonLogger = new JsonLogger();","/*\n *\tError handling\n */\n\nimport {ProcedureError} from './procedureError.ts';\nimport {RequestError} from './requestError.ts';\nimport {getFormattedMessage, logToFile, type messageType} from '../../util/trace.ts';\nimport {errorToString} from '../../util/errorToString.ts';\nimport {getHtmlPage} from '../../util/html.ts';\nimport {jsonLogger} from '../../util/jsonLogger.ts';\nimport type {Request, Response} from 'express';\nimport type {environmentType, configPlSqlHandlerType} from '../../types.ts';\nimport type {BindParameters} from 'oracledb';\n\n/**\n *\tGet error data\n *\t@param req - The req object represents the HTTP request.\n *\t@param error - The error.\n *\t@returns The output.\n */\nconst getErrorData = (req: Request, error: unknown): messageType => {\n\tlet timestamp = new Date();\n\tlet message = '';\n\tlet environment: environmentType | null | undefined = null;\n\tlet sql: string | null | undefined = null;\n\tlet bind: BindParameters | null | undefined = null;\n\n\t// what type of Error did we receive\n\tif (error instanceof ProcedureError) {\n\t\ttimestamp = error.timestamp;\n\t\tmessage = error.stack ?? '';\n\t\tenvironment = error.environment;\n\t\tsql = error.sql;\n\t\tbind = error.bind;\n\t} else if (error instanceof RequestError) {\n\t\ttimestamp = error.timestamp;\n\t\tmessage = error.stack ?? '';\n\t} else if (error instanceof Error) {\n\t\tmessage = errorToString(error);\n\t} else {\n\t\tif (typeof error === 'string') {\n\t\t\tmessage = `${error}\\n`;\n\t\t}\n\t\t/* v8 ignore start - unreachable code: creating Error without throwing */\n\t\ttry {\n\t\t\t// oxlint-disable-next-line unicorn/error-message\n\t\t\tnew Error();\n\t\t} catch (err) {\n\t\t\tmessage += errorToString(err);\n\t\t}\n\t\t/* v8 ignore stop */\n\t}\n\n\treturn {type: 'error', timestamp, message, req, environment, sql, bind};\n};\n\n/**\n * Show an error page\n *\n * @param req - The req object represents the HTTP request.\n * @param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n * @param options - The configuration options.\n * @param error - The error.\n */\nexport const errorPage = (req: Request, res: Response, options: configPlSqlHandlerType, error: unknown): void => {\n\t// get error data\n\tconst errorData = getErrorData(req, error);\n\n\t// get formatted message\n\tconst {html, text} = getFormattedMessage(errorData);\n\n\t// trace to file\n\tlogToFile(text);\n\n\t// json log\n\tconst firstLine = errorData.message.split('\\n')[0];\n\tjsonLogger.log({\n\t\ttimestamp: errorData.timestamp?.toISOString() ?? new Date().toISOString(),\n\t\ttype: 'error',\n\t\tmessage: firstLine ?? '',\n\t\treq: {\n\t\t\tmethod: req.method,\n\t\t\turl: req.originalUrl,\n\t\t\tip: req.ip ?? '',\n\t\t\tuserAgent: req.get('user-agent') ?? '',\n\t\t},\n\t\tdetails: {\n\t\t\tfullMessage: errorData.message,\n\t\t\tsql: errorData.sql ?? '',\n\t\t\tbind: errorData.bind,\n\t\t\tenvironment: errorData.environment ?? {},\n\t\t},\n\t});\n\n\t// console\n\tconsole.error(text);\n\n\t// If headers have already been sent, we cannot show the error page\n\tif (res.headersSent) {\n\t\tconsole.warn('errorPage: Response headers already sent. Cannot show error page.');\n\t\treturn;\n\t}\n\n\t// show page\n\tif (options.errorStyle === 'basic') {\n\t\tres.status(404).send('Page not found');\n\t} else {\n\t\tres.status(404).send(getHtmlPage(html));\n\t}\n};","/*\n *\tExpress middleware for Oracle PL/SQL\n */\n\nimport debugModule from 'debug';\nconst debug = debugModule('webplsql:handlerPlSql');\n\nimport {processRequest} from './request.ts';\nimport {RequestError} from './requestError.ts';\nimport {errorPage} from './errorPage.ts';\nimport {Cache} from '../../util/cache.ts';\nimport type {RequestHandler, Request, Response, NextFunction} from 'express';\nimport type {Pool} from 'oracledb';\nimport type {configPlSqlType, argsType} from '../../types.ts';\nimport type {AdminContext} from '../../server/adminContext.ts';\n\ntype WebPlSqlRequestHandler = RequestHandler & {\n\tprocedureNameCache: Cache<string>;\n\targumentCache: Cache<argsType>;\n};\n\n/**\n * express.Request handler\n * @param req - The req object represents the HTTP request.\n * @param res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.\n * @param _next - The next function.\n * @param connectionPool - The connection pool.\n * @param options - the options for the middleware.\n * @param procedureNameCache - The procedure name cache.\n * @param argumentCache - The argument cache.\n */\nconst requestHandler = async (\n\treq: Request,\n\tres: Response,\n\t_next: NextFunction,\n\tconnectionPool: Pool,\n\toptions: configPlSqlType,\n\tprocedureNameCache: Cache<string>,\n\targumentCache: Cache<argsType>,\n): Promise<void> => {\n\ttry {\n\t\tlet authenticatedUser: string | null = null;\n\n\t\t// authentication logic\n\t\tif (options.auth?.type === 'basic') {\n\t\t\tconst b64auth = (req.headers.authorization ?? '').split(' ')[1] ?? '';\n\t\t\tconst [login, password] = Buffer.from(b64auth, 'base64').toString().split(':');\n\n\t\t\tif (login) {\n\t\t\t\tauthenticatedUser = await options.auth.callback({username: login, password}, connectionPool);\n\t\t\t}\n\n\t\t\tif (authenticatedUser === null) {\n\t\t\t\tconst realm = options.auth.realm ?? 'PL/SQL Gateway';\n\t\t\t\tres.set('WWW-Authenticate', `Basic realm=\"${realm}\"`);\n\t\t\t\tres.status(401).send('Authentication required.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else if (options.auth?.type === 'custom') {\n\t\t\tauthenticatedUser = await options.auth.callback(req, connectionPool);\n\n\t\t\tif (authenticatedUser === null) {\n\t\t\t\tres.status(401).send('Authentication required.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// should we switch to the default page if there is one defined\n\t\tif (typeof req.params.name !== 'string' || req.params.name.length === 0) {\n\t\t\tif (typeof options.defaultPage === 'string' && options.defaultPage.length > 0) {\n\t\t\t\tconst currentUrl = new URL(req.originalUrl, 'http://localhost');\n\t\t\t\tconst basePath = currentUrl.pathname.endsWith('/') ? currentUrl.pathname : `${currentUrl.pathname}/`;\n\t\t\t\tconst defaultPage = options.defaultPage.replace(/^\\/+/u, '');\n\t\t\t\tconst newUrl = `${basePath}${defaultPage}${currentUrl.search}`;\n\t\t\t\tdebug(`Redirect to the url \"${newUrl}\"`);\n\t\t\t\tres.redirect(newUrl);\n\t\t\t} else {\n\t\t\t\terrorPage(req, res, options, new RequestError('No procedure name given and no default page has been specified'));\n\t\t\t}\n\t\t} else {\n\t\t\t// request handler\n\t\t\tawait processRequest(req, res, options, connectionPool, procedureNameCache, argumentCache, authenticatedUser);\n\t\t}\n\t} catch (err) {\n\t\terrorPage(req, res, options, err);\n\t}\n};\n\n/**\n * Express middleware.\n *\n * @param connectionPool - The connection pool.\n * @param config - The configuration options.\n * @param adminContext - Optional admin context for self-registration and stats tracking.\n * @returns The handler.\n */\nexport const handlerWebPlSql = (\n\tconnectionPool: Pool,\n\tconfig: configPlSqlType,\n\tadminContext?: AdminContext,\n): WebPlSqlRequestHandler & {procedureNameCache: Cache<string>; argumentCache: Cache<argsType>} => {\n\tdebug('options', config);\n\n\tconst procedureNameCache = new Cache<string>();\n\tconst argumentCache = new Cache<argsType>();\n\n\t// Self-register with AdminContext\n\tif (adminContext) {\n\t\tadminContext.registerHandler(config.route, connectionPool, procedureNameCache, argumentCache);\n\t}\n\n\t/**\n\t * @param req - The request.\n\t * @param res - The response.\n\t * @param next - The next function.\n\t */\n\tconst handler = ((req: Request, res: Response, next: NextFunction) => {\n\t\tvoid requestHandler(req, res, next, connectionPool, config, procedureNameCache, argumentCache);\n\t}) as WebPlSqlRequestHandler;\n\n\thandler.procedureNameCache = procedureNameCache;\n\thandler.argumentCache = argumentCache;\n\n\treturn handler;\n};","import debugModule from 'debug';\nconst debug = debugModule('webplsql:handlerLogger');\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport morgan from 'morgan';\nimport type {RequestHandler} from 'express';\n\n/**\n * Create the upload middleware.\n * @param filename - Output filename.\n * @returns Request handler.\n */\nexport const handlerLogger = (filename: string): RequestHandler => {\n\tdebug('register');\n\n\treturn morgan('combined', {stream: fs.createWriteStream(path.join(process.cwd(), filename), {flags: 'a'})});\n};","import multer from 'multer';\nimport type {RequestHandler} from 'express';\n\n/**\n * Create the upload middleware.\n * @param uploadFileSizeLimit - Maximum size of each uploaded file in bytes or no limit if omitted.\n * @returns Request handler.\n */\nexport const handlerUpload = (uploadFileSizeLimit?: number): RequestHandler => {\n\tconst upload = multer({\n\t\tstorage: multer.diskStorage({}),\n\t\tlimits: {\n\t\t\tfileSize: uploadFileSizeLimit,\n\t\t},\n\t});\n\n\treturn upload.any();\n};","import express, {type Request, type Response, type Router} from 'express';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport readline from 'node:readline';\nimport type {AdminContext} from '../server/adminContext.ts';\nimport {traceManager} from '../util/traceManager.ts';\nimport {getVersion} from '../version.ts';\nimport {SHUTDOWN_GRACE_DELAY_MS} from '../../common/constants.ts';\nimport {forceShutdown} from '../util/shutdown.ts';\nimport {logEntrySchema, procedureTraceEntrySchema} from '../types.ts';\nimport {z} from 'zod';\n\nconst version = () => getVersion();\n\n/**\n * Helper to read last N lines of a file\n * @param filePath - Path to file\n * @param n - Number of lines\n * @param filter - Optional filter string\n * @returns The lines\n */\nconst readLastLines = async (filePath: string, n = 100, filter = ''): Promise<string[]> => {\n\tif (!fs.existsSync(filePath)) {\n\t\treturn [];\n\t}\n\n\tconst fileStream = fs.createReadStream(filePath);\n\tconst rl = readline.createInterface({\n\t\tinput: fileStream,\n\t\tcrlfDelay: Infinity,\n\t});\n\n\tconst filterLower = filter.toLowerCase();\n\n\tconst lines: string[] = [];\n\tfor await (const line of rl) {\n\t\tif (!filter || line.toLowerCase().includes(filterLower)) {\n\t\t\tlines.push(line);\n\t\t\tif (lines.length > n) {\n\t\t\t\tlines.shift();\n\t\t\t}\n\t\t}\n\t}\n\treturn lines;\n};\n\n/**\n * Create admin API router\n * @param adminContext - The admin context\n * @returns Express router\n */\nexport const createAdminRouter = (adminContext: AdminContext): Router => {\n\tconst router = express.Router();\n\n\t// GET /api/status\n\trouter.get('/api/status', (req: Request, res: Response) => {\n\t\tconst uptime = (Date.now() - adminContext.startTime.getTime()) / 1000;\n\t\tconst includeHistory = req.query.history === 'true';\n\t\tconst includeConfig = req.query.config === 'true';\n\n\t\tconst poolStats = adminContext.pools.map((pool, index) => {\n\t\t\tconst cache = adminContext.caches[index];\n\t\t\tconst name = cache?.poolName ?? `pool-${index}`;\n\t\t\tconst p = pool as {getStatistics?: () => unknown};\n\t\t\tconst stats = typeof p.getStatistics === 'function' ? p.getStatistics() : null;\n\t\t\tconst procStats = cache?.procedureNameCache?.getStats();\n\t\t\tconst argStats = cache?.argumentCache?.getStats();\n\n\t\t\treturn {\n\t\t\t\tname,\n\t\t\t\tstats,\n\t\t\t\tconnectionsOpen: pool.connectionsOpen,\n\t\t\t\tconnectionsInUse: pool.connectionsInUse,\n\t\t\t\tcache: {\n\t\t\t\t\tprocedureName: {\n\t\t\t\t\t\tsize: cache?.procedureNameCache?.keys().length ?? 0,\n\t\t\t\t\t\thits: procStats?.hits ?? 0,\n\t\t\t\t\t\tmisses: procStats?.misses ?? 0,\n\t\t\t\t\t},\n\t\t\t\t\targument: {\n\t\t\t\t\t\tsize: cache?.argumentCache?.keys().length ?? 0,\n\t\t\t\t\t\thits: argStats?.hits ?? 0,\n\t\t\t\t\t\tmisses: argStats?.misses ?? 0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\n\t\tconst memUsage = process.memoryUsage();\n\t\tconst systemMemoryUsed = os.totalmem() - os.freemem();\n\t\tconst cpuUsage = process.cpuUsage();\n\t\tconst summary = adminContext.statsManager.getSummary();\n\n\t\tconst history = adminContext.statsManager.getHistory();\n\t\t// If history is not requested, return only the last bucket for charts\n\t\tconst historyData = includeHistory ? history : history.slice(-1);\n\n\t\tres.json({\n\t\t\tversion: version(),\n\t\t\tstatus: adminContext.paused ? 'paused' : 'running',\n\t\t\tuptime,\n\t\t\tstartTime: adminContext.startTime,\n\t\t\tintervalMs: adminContext.statsManager.config.intervalMs,\n\t\t\tmetrics: {\n\t\t\t\trequestCount: summary.totalRequests,\n\t\t\t\terrorCount: summary.totalErrors,\n\t\t\t\tavgResponseTime: summary.avgResponseTime,\n\t\t\t\tminResponseTime: summary.minResponseTime,\n\t\t\t\tmaxResponseTime: summary.maxResponseTime,\n\t\t\t\tmaxRequestsPerSecond: summary.maxRequestsPerSecond,\n\t\t\t},\n\t\t\thistory: historyData,\n\t\t\tpools: poolStats,\n\t\t\tsystem: {\n\t\t\t\tnodeVersion: process.version,\n\t\t\t\tplatform: process.platform,\n\t\t\t\tarch: process.arch,\n\t\t\t\tcpuCores: os.cpus().length,\n\t\t\t\tmemory: {\n\t\t\t\t\trss: systemMemoryUsed,\n\t\t\t\t\theapTotal: memUsage.heapTotal,\n\t\t\t\t\theapUsed: memUsage.heapUsed,\n\t\t\t\t\texternal: memUsage.external,\n\t\t\t\t\ttotalMemory: os.totalmem(),\n\t\t\t\t\t...summary.maxMemory,\n\t\t\t\t},\n\t\t\t\tcpu: {\n\t\t\t\t\tuser: cpuUsage.user,\n\t\t\t\t\tsystem: cpuUsage.system,\n\t\t\t\t\tmax: summary.cpu.max,\n\t\t\t\t\tuserMax: summary.cpu.userMax,\n\t\t\t\t\tsystemMax: summary.cpu.systemMax,\n\t\t\t\t},\n\t\t\t},\n\t\t\tconfig:\n\t\t\t\tincludeConfig && adminContext.config\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...adminContext.config,\n\t\t\t\t\t\t\tadminPassword: adminContext.config.adminPassword ? '********' : undefined,\n\t\t\t\t\t\t\troutePlSql: adminContext.config.routePlSql.map((p) => {\n\t\t\t\t\t\t\t\tconst {auth, transactionMode, cgi, ...rest} = p;\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t...rest,\n\t\t\t\t\t\t\t\t\tpassword: '********',\n\t\t\t\t\t\t\t\t\thasAuth: !!auth,\n\t\t\t\t\t\t\t\t\thasTransactionMode: !!transactionMode,\n\t\t\t\t\t\t\t\t\thasCgi: !!cgi,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t});\n\t});\n\n\t// GET /api/stats/history\n\trouter.get('/api/stats/history', (req: Request, res: Response) => {\n\t\tconst limitQuery = req.query.limit;\n\t\tlet limit = 100;\n\t\tif (typeof limitQuery === 'string') {\n\t\t\tconst parsed = Number(limitQuery);\n\t\t\tif (!Number.isNaN(parsed)) {\n\t\t\t\tlimit = parsed;\n\t\t\t}\n\t\t}\n\n\t\tconst history = adminContext.statsManager.getHistory();\n\t\t// Return the last 'limit' entries, reversed (newest first)\n\t\t// Create a copy to avoid mutating the original history array\n\t\tconst slice = limit > 0 ? history.slice(-limit) : [...history];\n\t\tres.json(slice.toReversed());\n\t});\n\n\t// GET /api/logs/error\n\trouter.get('/api/logs/error', async (req: Request, res: Response) => {\n\t\ttry {\n\t\t\tconst limit = Number(req.query.limit) || 100;\n\t\t\tconst filter = typeof req.query.filter === 'string' ? req.query.filter : '';\n\t\t\tconst logFile = 'error.json.log';\n\t\t\tconst lines = await readLastLines(logFile, limit, filter);\n\t\t\tconst parsedLines = lines\n\t\t\t\t.map((line) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn JSON.parse(line) as unknown;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((l): l is unknown => l !== null);\n\t\t\tconst schema = z.array(logEntrySchema);\n\t\t\tconst logs = schema.safeParse(parsedLines);\n\t\t\tif (!logs.success) {\n\t\t\t\t// FIXME: this must be standardized\n\t\t\t\tthrow new Error(`Validation failed: ${logs.error.message}`);\n\t\t\t}\n\n\t\t\treturn res.json(logs.data.toReversed());\n\t\t} catch (err) {\n\t\t\treturn res.status(500).json({error: String(err)});\n\t\t}\n\t});\n\n\t// GET /api/logs/access\n\trouter.get('/api/logs/access', async (req: Request, res: Response) => {\n\t\ttry {\n\t\t\tconst limit = Number(req.query.limit) || 100;\n\t\t\tconst filter = typeof req.query.filter === 'string' ? req.query.filter : '';\n\t\t\tconst logFile = adminContext.config?.loggerFilename ?? 'access.log';\n\n\t\t\tif (!adminContext.config?.loggerFilename) {\n\t\t\t\tres.json({message: 'Access logging not enabled'});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst lines = await readLastLines(logFile, limit, filter);\n\t\t\tres.json(lines.toReversed());\n\t\t} catch (err) {\n\t\t\tres.status(500).json({error: String(err)});\n\t\t}\n\t});\n\n\t// POST /api/cache/clear\n\trouter.post('/api/cache/clear', (req: Request, res: Response) => {\n\t\tconst body = req.body as {poolName?: unknown} | null | undefined;\n\t\tconst poolName = typeof body?.poolName === 'string' ? body.poolName : undefined;\n\n\t\tlet cleared = 0;\n\t\tadminContext.caches.forEach((c) => {\n\t\t\tif (!poolName || c.poolName === poolName) {\n\t\t\t\tc.procedureNameCache.clear();\n\t\t\t\tcleared++;\n\t\t\t\tc.argumentCache.clear();\n\t\t\t\tcleared++;\n\t\t\t}\n\t\t});\n\n\t\tres.json({message: `Cleared ${cleared} caches`});\n\t});\n\n\t// POST /api/server/:action\n\trouter.post('/api/server/:action', (req: Request, res: Response) => {\n\t\tconst action = req.params.action;\n\n\t\tswitch (action) {\n\t\t\tcase 'stop': {\n\t\t\t\tres.json({message: 'Server shutting down...'});\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tforceShutdown();\n\t\t\t\t}, SHUTDOWN_GRACE_DELAY_MS);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'pause': {\n\t\t\t\tadminContext.setPaused(true);\n\t\t\t\tres.json({message: 'Server paused', status: 'paused'});\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'resume': {\n\t\t\t\tadminContext.setPaused(false);\n\t\t\t\tres.json({message: 'Server resumed', status: 'running'});\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tres.status(400).json({error: 'Invalid action'});\n\t\t\t}\n\t\t}\n\t});\n\n\t// GET /api/trace/status\n\trouter.get('/api/trace/status', (_req: Request, res: Response) => {\n\t\tres.json({enabled: traceManager.isEnabled()});\n\t});\n\n\t// POST /api/trace/toggle\n\trouter.post('/api/trace/toggle', (req: Request, res: Response) => {\n\t\tconst body = req.body as {enabled?: unknown} | null | undefined;\n\t\tconst enabled = typeof body?.enabled === 'boolean' ? body.enabled : false;\n\t\ttraceManager.setEnabled(enabled);\n\t\tres.json({enabled: traceManager.isEnabled()});\n\t});\n\n\t// GET /api/trace/logs\n\trouter.get('/api/trace/logs', async (req: Request, res: Response) => {\n\t\ttry {\n\t\t\tconst limit = Number(req.query.limit) || 100;\n\t\t\tconst filter = typeof req.query.filter === 'string' ? req.query.filter : '';\n\t\t\tconst logFile = traceManager.getFilePath();\n\t\t\tconst lines = await readLastLines(logFile, limit, filter);\n\t\t\tconst parsedLines = lines\n\t\t\t\t.map((line) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn JSON.parse(line) as unknown;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((l): l is unknown => l !== null);\n\t\t\tconst schema = z.array(procedureTraceEntrySchema);\n\t\t\tconst logs = schema.safeParse(parsedLines);\n\t\t\tif (!logs.success) {\n\t\t\t\t// FIXME: this must be standardized\n\t\t\t\tthrow new Error(`Validation failed: ${logs.error.message}`);\n\t\t\t}\n\n\t\t\treturn res.json(logs.data.toReversed());\n\t\t} catch (err) {\n\t\t\treturn res.status(500).json({error: String(err)});\n\t\t}\n\t});\n\n\t// POST /api/trace/clear\n\trouter.post('/api/trace/clear', (_req: Request, res: Response) => {\n\t\ttraceManager.clear();\n\t\tres.json({message: 'Traces cleared'});\n\t});\n\n\treturn router;\n};","import {Router, type Request, type Response, type NextFunction, type RequestHandler} from 'express';\nimport {existsSync} from 'node:fs';\nimport path from 'node:path';\nimport expressStaticGzip from 'express-static-gzip';\nimport type {AdminContext} from '../server/adminContext.ts';\nimport type {PoolSnapshot} from '../util/statsManager.ts';\nimport {createAdminRouter} from './handlerAdmin.ts';\n\n/**\n * Resolves the admin console static directory by walking up from the current module\n * to find the project root (identified by package.json), then returns dist/frontend path.\n * @returns Path to dist/frontend directory\n * @throws {Error} if project root cannot be found\n */\nexport const resolveAdminStaticDir = (): string => {\n\tconst __dirname = import.meta.dirname;\n\n\tlet projectRoot = __dirname;\n\twhile (!existsSync(path.join(projectRoot, 'package.json')) && projectRoot !== '/') {\n\t\tprojectRoot = path.dirname(projectRoot);\n\t}\n\n\tif (projectRoot === '/') {\n\t\tthrow new Error('Could not find project root (package.json). Please provide explicit staticDir in AdminConsoleConfig.');\n\t}\n\n\treturn path.join(projectRoot, 'dist', 'frontend');\n};\n\nexport type AdminConsoleConfig = {\n\t/** Base route for the admin console (defaults to '/admin') */\n\tadminRoute?: string | undefined;\n\t/** Path to built admin frontend directory (optional - auto-detects if omitted) */\n\tstaticDir?: string | undefined;\n\t/** Optional username for basic auth */\n\tuser?: string | undefined;\n\t/** Optional password for basic auth */\n\tpassword?: string | undefined;\n\t/** Skip static dir validation (for dev mode) */\n\tdevMode?: boolean | undefined;\n};\n\n/**\n * Creates the admin console middleware.\n * @param config - The admin console configuration.\n * @param adminContext - The admin context.\n * @returns The express request handler.\n */\nexport const handlerAdminConsole = (config: AdminConsoleConfig, adminContext: AdminContext): RequestHandler => {\n\tconst adminRoute = config.adminRoute ?? '/admin';\n\tconst resolvedStaticDir = config.staticDir ?? resolveAdminStaticDir();\n\n\t// Validation\n\tif (adminRoute && !adminRoute.startsWith('/')) {\n\t\tthrow new Error('adminRoute must start with /');\n\t}\n\n\tif (!config.devMode && !existsSync(resolvedStaticDir)) {\n\t\tthrow new Error(`Admin console not built. Run 'npm run build:frontend' first.\\nExpected: ${resolvedStaticDir}`);\n\t}\n\n\t// StatsManager hook - ensure we only wrap once\n\tconst statsManager = adminContext.statsManager;\n\t// oxlint-disable-next-line typescript/unbound-method\n\tconst currentRotate = statsManager.rotateBucket;\n\tif (!Object.prototype.hasOwnProperty.call(currentRotate, '_isWrapped')) {\n\t\t// oxlint-disable-next-line typescript/unbound-method\n\t\tconst originalRotate = statsManager.rotateBucket;\n\t\tconst wrappedRotate = (poolSnapshots: PoolSnapshot[] = []) => {\n\t\t\tconst currentSnapshots: PoolSnapshot[] = adminContext.pools.map((pool, index) => {\n\t\t\t\tconst cache = adminContext.caches[index];\n\t\t\t\tconst name = cache?.poolName ?? `pool-${index}`;\n\t\t\t\tconst procStats = cache?.procedureNameCache?.getStats();\n\t\t\t\tconst argStats = cache?.argumentCache?.getStats();\n\n\t\t\t\treturn {\n\t\t\t\t\tname,\n\t\t\t\t\tconnectionsOpen: pool.connectionsOpen,\n\t\t\t\t\tconnectionsInUse: pool.connectionsInUse,\n\t\t\t\t\tcache: {\n\t\t\t\t\t\tprocedureName: {\n\t\t\t\t\t\t\tsize: cache?.procedureNameCache?.keys().length ?? 0,\n\t\t\t\t\t\t\thits: procStats?.hits ?? 0,\n\t\t\t\t\t\t\tmisses: procStats?.misses ?? 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t\targument: {\n\t\t\t\t\t\t\tsize: cache?.argumentCache?.keys().length ?? 0,\n\t\t\t\t\t\t\thits: argStats?.hits ?? 0,\n\t\t\t\t\t\t\tmisses: argStats?.misses ?? 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\t\t\t// Merge snapshots if provided\n\t\t\tconst mergedSnapshots: PoolSnapshot[] = [...currentSnapshots];\n\t\t\tif (Array.isArray(poolSnapshots)) {\n\t\t\t\tfor (const ps of poolSnapshots) {\n\t\t\t\t\tif (!mergedSnapshots.some((s) => s.name === ps.name)) {\n\t\t\t\t\t\tmergedSnapshots.push(ps);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\toriginalRotate.call(statsManager, mergedSnapshots);\n\t\t};\n\t\tObject.defineProperty(wrappedRotate, '_isWrapped', {value: true, writable: false});\n\t\tstatsManager.rotateBucket = wrappedRotate;\n\t}\n\n\tconst router = Router();\n\n\t// Pause middleware\n\trouter.use((req: Request, res: Response, next: NextFunction) => {\n\t\tif (adminContext.paused && !req.path.startsWith(adminRoute)) {\n\t\t\tres.status(503).send('Server Paused');\n\t\t\treturn;\n\t\t}\n\t\tnext();\n\t});\n\n\t// Route filter - all following middleware only apply to adminRoute\n\trouter.use(adminRoute, (req: Request, res: Response, next: NextFunction) => {\n\t\t// Trailing slash redirect\n\t\tconst baseUrl = req.baseUrl || '';\n\t\tconst [path] = req.originalUrl.split('?');\n\n\t\tif (path === baseUrl) {\n\t\t\tconst query = req.originalUrl.split('?')[1];\n\t\t\treturn res.redirect(baseUrl + '/' + (query ? '?' + query : ''));\n\t\t}\n\t\tnext();\n\t});\n\n\t// Auth middleware\n\tif (config.user && config.password) {\n\t\trouter.use(adminRoute, (req: Request, res: Response, next: NextFunction) => {\n\t\t\tconst b64auth = (req.headers.authorization ?? '').split(' ')[1] ?? '';\n\t\t\tconst [login, password] = Buffer.from(b64auth, 'base64').toString().split(':');\n\n\t\t\tif (login !== config.user || password !== config.password) {\n\t\t\t\tres.set('WWW-Authenticate', 'Basic realm=\"Admin Console\"');\n\t\t\t\tres.status(401).send('Authentication required.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tnext();\n\t\t});\n\t}\n\n\t// Mount handlerAdmin API routes\n\trouter.use(adminRoute, createAdminRouter(adminContext));\n\n\t// Mount static files\n\tif (existsSync(resolvedStaticDir)) {\n\t\trouter.use(\n\t\t\tadminRoute,\n\t\t\texpressStaticGzip(resolvedStaticDir, {\n\t\t\t\tenableBrotli: true,\n\t\t\t\torderPreference: ['br'],\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn router;\n};","import path from 'node:path';\nimport {type Request, type Response, type NextFunction, type RequestHandler} from 'express';\n\n/**\n * Creates middleware that serves index.html for SPA routes.\n *\n * Handles React Router (createBrowserRouter), Vue Router, Angular Router, etc.\n *\n * **CRITICAL**: This middleware MUST be mounted AFTER express-static-gzip.\n *\n * Middleware order:\n * 1. express-static-gzip → Serves actual files (CSS, JS, images)\n * 2. handlerSpaFallback → Serves index.html for navigation requests\n *\n * @param directoryPath - Path to the static directory containing index.html\n * @param _route - The route prefix (for debugging)\n * @returns Express request handler\n *\n * @example\n * ```typescript\n * app.use('/app', expressStaticGzip('./build'));\n * app.use('/app', createSpaFallback('./build', '/app'));\n * ```\n */\nexport const createSpaFallback = (directoryPath: string, _route: string): RequestHandler => {\n\tconst indexPath = path.join(directoryPath, 'index.html');\n\n\treturn (req: Request, res: Response, next: NextFunction): void => {\n\t\t// Only handle GET/HEAD requests (standard browser navigation)\n\t\tif (req.method !== 'GET' && req.method !== 'HEAD') {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Check Accept header to avoid serving HTML for API/asset requests\n\t\tconst accept = req.headers.accept ?? '';\n\n\t\t// Skip if Accept header explicitly excludes HTML\n\t\t// Handles: Accept: application/json, image/*, text/css, etc.\n\t\tif (accept && !accept.includes('text/html') && !accept.includes('*/*')) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Send index.html for navigation requests\n\t\tres.sendFile(indexPath, (err) => {\n\t\t\tif (err) {\n\t\t\t\t// index.html missing - let Express handle 404\n\t\t\t\tnext(err);\n\t\t\t}\n\t\t});\n\t};\n};","import process from 'node:process';\nimport chalk from 'chalk';\n\n// Named aliases — chalk 16-color approximations, original ansi256 noted\nconst C = {\n\tred: chalk.ansi256(196), // chalk.redBright.bold\n\tgray: chalk.gray, // ansi256(245)\n\tdimGray: chalk.blackBright, // ansi256(240)\n\twhite: chalk.whiteBright, // ansi256(255)\n} as const;\n\n/**\n * Prints a formatted CLI error block to stderr with timestamp.\n *\n * @param message - Primary error description\n * @param meta - Optional metadata\n */\nexport const printError = (message: string, meta?: Record<string, string>): void => {\n\tconst ts = new Date()\n\t\t.toISOString()\n\t\t.replace('T', ' ')\n\t\t.replace(/(\\.\\d{3})Z$/u, '.$1 UTC');\n\n\tconst sep = C.dimGray('─'.repeat(48));\n\tconst header = `${C.red('✖ ERROR')} ${C.dimGray(ts)}`;\n\tconst body = C.white(message);\n\n\tconst defaultMeta: Record<string, string> = {\n\t\tpid: String(process.pid),\n\t\tnode: process.version,\n\t\t...meta,\n\t};\n\n\tconst footer = Object.entries(defaultMeta)\n\t\t.map(([k, v]) => `${C.dimGray(k)} ${C.gray(v)}`)\n\t\t.join(' ');\n\n\tconsole.error([sep, header, body, sep, footer].join('\\n'));\n};","/*\n *\tError handling\n */\n\nimport {logToFile} from './trace.ts';\nimport {printError} from './printError.ts';\nimport {errorToString} from './errorToString.ts';\nimport {jsonLogger} from './jsonLogger.ts';\n\n/**\n * Log an error.\n *\n * @param error - The error.\n */\nexport const logError = (error: unknown): void => {\n\tlet message = '';\n\n\t// what type of Error did we receive\n\tif (error instanceof Error) {\n\t\tmessage = errorToString(error);\n\t} else {\n\t\tif (typeof error === 'string') {\n\t\t\tmessage = error;\n\t\t}\n\t\t/* v8 ignore start - unreachable code: creating Error without throwing */\n\t\ttry {\n\t\t\t// oxlint-disable-next-line unicorn/error-message\n\t\t\tnew Error();\n\t\t} catch (err) {\n\t\t\tmessage += errorToString(err);\n\t\t}\n\t\t/* v8 ignore stop */\n\t}\n\n\t// trace to file\n\tlogToFile(message);\n\n\t// json log\n\tjsonLogger.log({\n\t\ttimestamp: new Date().toISOString(),\n\t\ttype: 'error',\n\t\tmessage,\n\t});\n\n\t// print error\n\tprintError(message);\n};"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAa,qBAAqB,EAAE,aAAa;;CAEhD,OAAO,EAAE,OAAO;;CAEhB,eAAe,EAAE,OAAO;;;;;;;CAOxB,aAAa,EAAE,QAAQ,CAAC,CAAC,SAAS;AACnC,CAAC;;;ACfD,MAAa,4BAA4BA,IAAE,aAAa;CACvD,IAAIA,IAAE,OAAO;CACb,WAAWA,IAAE,OAAO;CACpB,QAAQA,IAAE,OAAO;CACjB,KAAKA,IAAE,OAAO;CACd,QAAQA,IAAE,OAAO;CACjB,QAAQA,IAAE,OAAO;CACjB,UAAUA,IAAE,OAAO;CACnB,WAAWA,IAAE,OAAO,CAAC,CAAC,SAAS;CAC/B,YAAYA,IAAE,MAAM,CAACA,IAAE,OAAOA,IAAE,OAAO,GAAGA,IAAE,QAAQ,CAAC,GAAGA,IAAE,MAAMA,IAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;CACxF,SAASA,IACP,MACAA,IAAE,aAAa;EACd,cAAcA,IAAE,OAAO;EACvB,UAAUA,IAAE,OAAO;EACnB,MAAMA,IAAE,OAAO;CAChB,CAAC,CACF,CAAC,CACA,SAAS;CACX,WAAWA,IACT,aAAa;EACb,UAAUA,IAAE,OAAO;EACnB,UAAUA,IAAE,OAAO;CACpB,CAAC,CAAC,CACD,SAAS;CACX,MAAMA,IAAE,OAAO,CAAC,CAAC,SAAS;CAC1B,SAASA,IAAE,OAAOA,IAAE,OAAO,GAAGA,IAAE,OAAO,CAAC,CAAC,CAAC,SAAS;CACnD,SAASA,IAAE,OAAOA,IAAE,OAAO,GAAGA,IAAE,OAAO,CAAC,CAAC,CAAC,SAAS;CACnD,KAAKA,IAAE,OAAOA,IAAE,OAAO,GAAGA,IAAE,OAAO,CAAC,CAAC,CAAC,SAAS;CAC/C,OAAOA,IAAE,OAAO,CAAC,CAAC,SAAS;AAC5B,CAAC;;;;;;AC3BD,MAAM,qBAAqBC,IAAE,MAAM;CAACA,IAAE,QAAQ,OAAO;CAAGA,IAAE,QAAQ,MAAM;CAAGA,IAAE,QAAQ,SAAS;AAAC,CAAC;AAChG,MAAa,iBAAiBA,IAAE,aAAa;CAC5C,WAAWA,IAAE,OAAO;CACpB,MAAM;CACN,SAASA,IAAE,OAAO;CAClB,KAAKA,IACH,aAAa;EACb,QAAQA,IAAE,OAAO,CAAC,CAAC,SAAS;EAC5B,KAAKA,IAAE,OAAO,CAAC,CAAC,SAAS;EACzB,IAAIA,IAAE,OAAO,CAAC,CAAC,SAAS;EACxB,WAAWA,IAAE,OAAO,CAAC,CAAC,SAAS;CAChC,CAAC,CAAC,CACD,SAAS;CACX,SAASA,IACP,aAAa;EACb,aAAaA,IAAE,OAAO,CAAC,CAAC,SAAS;EACjC,KAAKA,IAAE,OAAO,CAAC,CAAC,SAAS;EACzB,MAAMA,IAAE,QAAQ,CAAC,CAAC,SAAS;EAC3B,aAAaA,IAAE,OAAOA,IAAE,OAAO,GAAGA,IAAE,OAAO,CAAC,CAAC,CAAC,SAAS;CACxD,CAAC,CAAC,CACD,SAAS;AACZ,CAAC;;;;;;;;ACXD,MAAM,mBAAmB,EAAE,KAAK,CAAC,SAAS,OAAO,CAAC;;;;;;;AAalD,MAAM,wBAAwB,EAAE,MAAM;CACrC,EAAE,QAAiC,QAAQ,OAAO,QAAQ,YAAY,EACrE,SAAS,+BACV,CAAC;CACD,EAAE,QAAQ,QAAQ;CAClB,EAAE,QAAQ,UAAU;CACpB,EAAE,UAAU;CACZ,EAAE,KAAK;AACR,CAAC;;;;AAoBD,MAAM,eAAe,EAAE,MAAM,CAC5B,EAAE,aAAa;;CAEd,MAAM,EAAE,QAAQ,OAAO;;CAEvB,UAAU,EAAE,QAA2B,QAAQ,OAAO,QAAQ,YAAY,EACzE,SAAS,wBACV,CAAC;;CAED,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;AAC5B,CAAC,GACD,EAAE,aAAa;;CAEd,MAAM,EAAE,QAAQ,QAAQ;;CAExB,UAAU,EAAE,QAA4B,QAAQ,OAAO,QAAQ,YAAY,EAC1E,SAAS,wBACV,CAAC;AACF,CAAC,CACF,CAAC;;;;AAKD,MAAa,2BAA2B,EAAE,aAAa;;CAEtD,aAAa,EAAE,OAAO;;CAEtB,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS;;CAE/B,oBAAoB,EAAE,OAAO,CAAC,CAAC,SAAS;;CAExC,eAAe,EAAE,OAAO;;CAExB,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS;;CAE5C,2BAA2B,EAAE,OAAO,CAAC,CAAC,SAAS;;CAE/C,iBAAiB,sBAAsB,SAAS;;CAEhD,YAAY;;CAEZ,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS;;CAE/C,MAAM,aAAa,SAAS;AAC7B,CAAC;;;;AAMD,MAAM,0BAA0B,EAAE,aAAa;;CAE9C,OAAO,EAAE,OAAO;;CAEhB,MAAM,EAAE,OAAO;;CAEf,UAAU,EAAE,OAAO;;CAEnB,eAAe,EAAE,OAAO;AACzB,CAAC;AAOD,MAAM,oBAAoB,EAAE,aAAa;CACxC,GAAG,yBAAyB;CAC5B,GAAG,wBAAwB;AAC5B,CAAC;;;;AAKD,MAAa,eAAe,EAAE,aAAa;;CAE1C,MAAM,EAAE,OAAO;;CAEf,aAAa,EAAE,MAAM,kBAAkB;;CAEvC,YAAY,EAAE,MAAM,iBAAiB;;CAErC,qBAAqB,EAAE,OAAO,CAAC,CAAC,SAAS;;CAEzC,gBAAgB,EAAE,OAAO;;CAEzB,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS;;CAEhC,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS;;CAE/B,eAAe,EAAE,OAAO,CAAC,CAAC,SAAS;;CAEnC,SAAS,EAAE,QAAQ,CAAC,CAAC,SAAS;;CAE9B,iBAAiB,EACf,QAA+D,QAAQ,OAAO,QAAQ,YAAY,EAClG,SAAS,mCACV,CAAC,CAAC,CACD,SAAS;CACX,QAAQ,EACN,aAAa;EACb,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;EACnC,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,GAAG;EACpC,eAAe,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE;CACzC,CAAC,CAAC,CACD,SAAS,CAAC,CACV,QAAQ;EACR,SAAS;EACT,SAAS;EACT,eAAe;CAChB,CAAC;AACH,CAAC;;;;;;;ACpKD,IAAI,kBAA0C;;;;;AAM9C,MAAa,sBAAsB,OAA+B;CACjE,kBAAkB;AACnB;;;;AAKA,IAAM,UAAN,MAAc;CACb;CACA,YAAY,MAAuB;EAClC,KAAK,OAAO;CACb;CAEA,UAAgB,CAAC;AAClB;;;;AAKA,IAAM,iBAAN,MAAqB;CACpB,MAAM,QAAqB,KAAa,YAA6B,UAA+C;EACnH,IAAI,iBACH,OAAQ,MAAM,gBAAgB,KAAK,UAAU;EAE9C,OAAO,EAAC,MAAM,CAAC,EAAC;CACjB;CAGA,MAAM,UAAU,MAAqC;EACpD,OAAO,IAAI,QAAQ,IAAI;CACxB;CAEA,MAAM,SAAwB,CAE9B;CACA,MAAM,WAA0B,CAEhC;CACA,MAAM,UAAyB,CAE/B;AACD;;;;AAKA,IAAM,WAAN,MAAe;CACd,kBAAkB;CAClB,mBAAmB;CAGnB,MAAM,gBAAqC;EAC1C,KAAK;EACL,KAAK,kBAAkB,KAAK,IAAI,KAAK,iBAAiB,KAAK,gBAAgB;EAC3E,OAAO,IAAI,eAAe;CAC3B;CAGA,MAAM,MAAM,YAAoC;EAC/C,KAAK,kBAAkB;EACvB,KAAK,mBAAmB;CACzB;AACD;;;;;;AAQA,eAAsBC,aAAW,SAAiC;CACjE,OAAO,IAAI,SAAS;AACrB;;;;;;;;;;;;;;;;;;;;;AChFA,MAAM,WAAW,QAAQ,IAAI,gBAAgB;;;;;;AAQ7C,eAAsB,WAAW,QAAyD;CACzF,IAAI,UAEH,QAAO,MAAA,QAAA,QAAA,CAAA,CAAA,WAAA,qBAAA,EAAA,CAAK,WAAW,MAAM;CAE9B,OAAO,MAAM,SAAS,WAAW,MAAM;AACxC;AAGA,MAAa,UAAU,SAAS;AAChC,MAAa,WAAW,SAAS;AACjC,MAAa,aAAa,SAAS;AACnC,MAAa,SAAS,SAAS;AAC/B,MAAa,SAAS,SAAS;AAC/B,MAAa,OAAO,SAAS;AAC7B,MAAa,SAAS,SAAS;AAC/B,MAAa,SAAS,SAAS;AAC/B,MAAa,OAAO,SAAS;AAC7B,MAAa,OAAO,SAAS;AAC7B,MAAa,kBAAkB,SAAS;AACxC,MAAa,eAAe,SAAS;AACrC,MAAa,iBAAiB,SAAS;AACvC,MAAa,eAAe,SAAS;;;AC5BrC,WAAW,gBAAgB;;;;;AAQ3B,MAAa,mBAAA;;;ACLb,MAAM,SAAS,QAAQ,OAAO,UAAU;AAOxC,MAAM,aAAa;AACnB,MAAM,WAAW;AACjB,MAAM,WAAW;AACjB,MAAM,eAAe;AACrB,MAAM,YAAY;AAClB,MAAM,cAAc;AACpB,MAAM,YAAY;AAClB,MAAM,YAAY;AAIlB,MAAM,IAAI;AACV,MAAM,UAAU;AAChB,MAAM,UAAU,IAAI,UAAU;AAE9B,MAAM,MAAM;CACX,GAAG;CACH,GAAG;CACH,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACL;AAGA,MAAM,gBAAgB,MAAsB,YAAY,GAAG,EAAC,mBAAmB,KAAI,CAAC;AAGpF,MAAM,SAAS,GAAW,MAAsB;CAC/C,MAAM,QAAQ,IAAI,aAAa,CAAC;CAChC,OAAO,QAAQ,IAAI,IAAI,IAAI,OAAO,KAAK,IAAI;AAC5C;AAGA,MAAM,cAAc,GAAW,MAAuB,IAAI,IAAI,UAAU,GAAG,GAAG,CAAC,IAAI;AAGnF,MAAM,gBAAyB,SAAS,MAAM,IAAI,IAAI,KAAK,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,IAAI,OAAO,CAAC;AAGvG,MAAM,mBAA4B,SAAS,MAAM,IAAI,IAAI,KAAK,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,QAAQ;AAGtG,MAAM,oBAA6B,SAAS,MAAM,IAAI,IAAI,KAAK,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,QAAQ;;;;;;;;AASvG,MAAM,OAAO,KAAa,OAA2C,SAA0B;CAC9F,MAAM,OAAO,SAAU,OAAO,GAAG,KAAK,GAAG,QAAQ,KAAK,QAAS,GAAG;CAClE,MAAM,QAAQ,MAAM,MAAM,OAAO;CACjC,MAAM,WAAW,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU;CACpE,MAAM,YAAY,WAAW,OAAO,KAAK,IAAI;CAC7C,MAAM,UAAU,WAAW,MAAM,QAAQ,MAAM;CAC/C,MAAM,YAAY,MAAM,WAAW,WAAW,OAAO,GAAG,OAAO;CAE/D,OAAO,SAAS,MAAM,IAAI,IAAI,CAAC,IAAI,MAAM,MAAM,IAAI,KAAK,IAAI,MAAM,QAAQ,SAAS,IAAI,MAAM,MAAM,IAAI,IAAI,CAAC,IAAI,QAAQ,MAAM;AAC/H;;;;;AAMA,MAAa,eAAe,QAA0B;CACrD,MAAM,aAAa,IAAI,cAAc;CACrC,MAAM,UAAU,oBAAoB,IAAI;CACxC,MAAM,QAAkB,CAAC;CAGzB,MAAM,KAAK,WAAW,CAAC;CAGvB,MAAM,QAAQ,sBAAsB,WAAW;CAC/C,MAAM,MAAM,IAAI,IAAI,aAAa,KAAK;CACtC,MAAM,KAAK,SAAS,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,KAAK,MAAM,MAAM,CAAC,CAAC,IAAI,MAAM,KAAK,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK;CAC3J,MAAM,KAAK,QAAQ,CAAC;CAGpB,MAAM,KAAK,IAAI,QAAQ,IAAI,MAAM,UAAU,CAAC;CAC5C,MAAM,KAAK,IAAI,eAAe,GAAG,aAAa,IAAI,YAAY,qBAAqB,MAAM,QAAQ,CAAC;CAClG,MAAM,KAAK,IAAI,cAAc,IAAI,gBAAgB,QAAQ,CAAC;CAC1D,MAAM,KAAK,IAAI,gBAAgB,OAAO,IAAI,wBAAwB,WAAW,GAAG,IAAI,oBAAoB,UAAU,MAAM,YAAY,CAAC;CACrI,MAAM,KAAK,QAAQ,CAAC;CAGpB,MAAM,KAAK,IAAI,oBAAoB,IAAI,OAAO,SAAS,SAAS,CAAC;CACjE,MAAM,KAAK,IAAI,oBAAoB,IAAI,OAAO,SAAS,SAAS,CAAC;CACjE,MAAM,KAAK,IAAI,0BAA0B,IAAI,OAAO,eAAe,SAAS,CAAC;CAG7E,IAAI,IAAI,YAAY,SAAS,GAAG;EAC/B,MAAM,KAAK,QAAQ,CAAC;EACpB,IAAI,YAAY,SAAS,GAAG,MAAM;GACjC,MAAM,KAAK,IAAI,iBAAiB,IAAI,EAAE,UAAU,EAAE,OAAO,WAAW,CAAC;GACrE,MAAM,KAAK,IAAI,iBAAiB,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC;EAChE,CAAC;CACF;CAGA,IAAI,IAAI,WAAW,SAAS,GAAG;EAC9B,MAAM,KAAK,QAAQ,CAAC;EACpB,IAAI,WAAW,SAAS,GAAG,MAAM;GAChC,MAAM,SAAS,OAAO,EAAE,oBAAoB,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,WAAW;GAC1G,MAAM,IAAI,iBAAiB,IAAI;GAE/B,MAAM,KAAK,IAAI,GAAG,EAAE,UAAU,EAAE,OAAO,SAAS,CAAC;GACjD,MAAM,KAAK,IAAI,GAAG,EAAE,gBAAgB,EAAE,IAAI,CAAC;GAC3C,MAAM,KAAK,IAAI,GAAG,EAAE,kBAAkB,EAAE,aAAa,CAAC;GACtD,MAAM,KAAK,IAAI,GAAG,EAAE,mBAAmB,EAAE,aAAa,CAAC;GACvD,MAAM,KAAK,IAAI,GAAG,EAAE,iBAAiB,EAAE,WAAW,CAAC;GACnD,MAAM,KAAK,IAAI,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC;GACrD,MAAM,KAAK,IAAI,GAAG,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,CAAC;GACnE,MAAM,KAAK,IAAI,GAAG,EAAE,mBAAmB,EAAE,eAAe,KAAK,IAAI,KAAK,EAAE,CAAC;GACzE,MAAM,KAAK,IAAI,GAAG,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,CAAC;GACxE,MAAM,KAAK,IAAI,GAAG,EAAE,iBAAiB,MAAM,CAAC;GAC5C,MAAM,KAAK,IAAI,GAAG,EAAE,SAAS,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO,EAAE,CAAC;GACtE,MAAM,KAAK,IAAI,GAAG,EAAE,gBAAgB,EAAE,UAAU,CAAC;EAClD,CAAC;CACF;CAGA,MAAM,KAAK,QAAQ,CAAC;CACpB,MAAM,KAAK,IAAI,iBAAiB,GAAG,UAAU,cAAc,SAAS,CAAC;CACrE,IAAI,WAAW,SAAS,MAAM;EAC7B,MAAM,KAAK,IAAI,EAAE,OAAO,GAAG,UAAU,EAAE,SAAS,SAAS,CAAC;CAC3D,CAAC;CACD,MAAM,KAAK,YAAY,CAAC;CAExB,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC;AAC7B;;;ACpJA,MAAMC,WAAQ,YAAY,iBAAiB;;;;;AAoC3C,MAAa,aAAa,OAAO,UAAiC;CACjE,MAAM,QAAQ,IAAI,MAAM,KAAK,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC;AACrD;;;;;;;AAsBA,MAAa,gBAAgB,KAAc,QAAgD;CAC1F,IAAI,KAAK;EACR,MAAM,MAAM,iBAAiB,IAAI,WAAW;EAC5C,MAAM,OAAO,iBAAiB,IAAI,YAAY;EAE9C,OAAO,MAAM,aAAa;GAAC;GAAK;EAAI,GAAG,GAAG;CAC3C,OACC,OAAO,KAAK,aAAa,GAAG;AAE9B;;;;;;;AAQA,MAAa,cAAc,OAAO,QAAyB,QAAwC;CAClG,SAAM,sBAAsB,QAAQ,GAAG;CAEvC,MAAM,iBAAiB,aAAa,MAAM,MAAM;CAEhD,YAAY,cAAc;CAG1B,MAAM,MAAM,QAAQ;CAGpB,IAAI,eAAe,SAClB,IAAI,IACH,KAAK;EACJ,QAAQ;EACR,aAAa;CACd,CAAC,CACF;CAED,IAAI,IAAI,cAAc,eAAe,mBAAmB,CAAC;CACzD,IAAI,IAAI,QAAQ,KAAK,EAAC,OAAO,OAAM,CAAC,CAAC;CACrC,IAAI,IAAI,QAAQ,WAAW;EAAC,OAAO;EAAQ,UAAU;CAAI,CAAC,CAAC;CAC3D,IAAI,IAAI,aAAa,CAAC;CACtB,IAAI,IAAI,YAAY,CAAC;CAGrB,MAAM,eAAe,IAAI,aAAa,cAAc;CAGpD,IAAI,IACH,oBACC;EACC,YAAY,eAAe;EAC3B,MAAM,eAAe;EACrB,UAAU,eAAe;EACzB,SAAS,eAAe;CACzB,GACA,YACD,CACD;CAGA,KAAK,MAAM,KAAK,eAAe,YAAY;EAW1C,MAAM,UAAU,gBAAgB,MATbC,WAAoB;GACtC,MAAM,EAAE;GACR,UAAU,EAAE;GACZ,eAAe,EAAE;GACjB,SAAS,eAAe,OAAO;GAC/B,SAAS,eAAe,OAAO;GAC/B,eAAe,eAAe,OAAO;EACtC,CAAC,GAEqC,GAAsB,YAAY;EAExE,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,SAAS,EAAE,KAAK,IAAI,KAAc,KAAe,SAAuB;GAC3F,MAAM,QAAQ,QAAQ,OAAO;GAC7B,IAAI,GAAG,gBAAgB;IACtB,MAAM,OAAO,QAAQ,OAAO,KAAK;IACjC,MAAM,WAAW,KAAK,KAAK,MAAO,KAAK,KAAK;IAC5C,aAAa,aAAa,cAAc,UAAU,IAAI,cAAc,GAAG;GACxE,CAAC;GACD,QAAQ,KAAK,KAAK,IAAI;EACvB,CAAC;CACF;CAGA,IAAI,eAAe,eAAe,SAAS,GAC1C,IAAI,IAAI,cAAc,eAAe,cAAc,CAAC;CAIrD,IAAI,eAAe,iBAClB,MAAM,eAAe,gBAAgB,KAAK,aAAa,KAAK;CAI7D,KAAK,MAAM,KAAK,eAAe,aAAa;EAC3C,IAAI,IACH,EAAE,OACF,kBAAkB,EAAE,eAAe;GAClC,cAAc;GACd,iBAAiB,CAAC,IAAI;EACvB,CAAC,CACF;EAIA,IAAI,EAAE,aACL,IAAI,IAAI,EAAE,OAAO,kBAAkB,EAAE,eAAe,EAAE,KAAK,CAAC;CAE9D;CAMA,SAAM,2BAA2B;CACjC,MAAM,SAAS,aAAa,KAAK,GAAG;CAGpC,MAAM,8BAAc,IAAI,IAAY;CACpC,OAAO,GAAG,eAAe,WAAmB;EAC3C,YAAY,IAAI,MAAM;EACtB,OAAO,GAAG,eAAe;GACxB,YAAY,OAAO,MAAM;EAC1B,CAAC;CACF,CAAC;CAED,MAAM,4BAA4B;EACjC,KAAK,MAAM,UAAU,aAAa;GACjC,OAAO,QAAQ;GACf,YAAY,OAAO,MAAM;EAC1B;CACD;CAEA,MAAM,WAAW,YAAY;EAC5B,SAAM,yBAAyB;EAE/B,aAAa,aAAa,KAAK;EAE/B,MAAM,WAAW,aAAa,KAAK;EAEnC,OAAO,YAAY;GAClB,QAAQ,IAAI,mBAAmB;GAC/B,QAAQ,KAAK,CAAC;EACf,CAAC;EAED,oBAAoB;CACrB;CAGA,gBAAgB,QAAQ;CAGxB,SAAM,6BAA6B;CACnC,MAAM,IAAI,SAAe,SAAS,WAAW;EAC5C,OACE,OAAO,eAAe,IAAI,CAAC,CAC3B,GAAG,mBAAmB;GACtB,SAAM,+BAA+B;GACrC,QAAQ;EACT,CAAC,CAAC,CACD,GAAG,UAAU,QAA+B;GAC5C,IAAI,UAAU,KACT;QAAA,IAAI,SAAS,cAChB,IAAI,UAAU,QAAQ,eAAe,KAAK;SACpC,IAAI,IAAI,SAAS,UACvB,IAAI,UAAU,QAAQ,eAAe,KAAK;GAAA;GAG5C,OAAO,GAAG;EACX,CAAC;CACH,CAAC;CAED,SAAM,kBAAkB;CAExB,OAAO;EACN,QAAQ;EACR,iBAAiB,aAAa;EAC9B;EACA;EACA;EACA;CACD;AACD;;;;;;AAOA,MAAa,cAAc,WAAW,kBAA8B,aAAa,MAAM,YAAY,QAAQ,CAAC;;;;;;;AAQ5G,MAAa,oBAAoB,OAAO,WAAW,eAAe,QAAwC,YAAY,WAAW,QAAQ,GAAG,GAAG;;;ACjQ/I,MAAMC,WAAQ,YAAY,mBAAmB;;;;;AAM7C,MAAa,mBAAmB,YAAuC;CACtE,SAAM,iBAAiB;CAEvB,IAAI,iBAAiB;CAKrB,QAAQ,GAAG,uBAAuB,WAAW;EAC5C,IAAI,gBACH;EAED,iBAAiB;EAEjB,IAAI,kBAAkB,OACrB,QAAQ,MAAM,KAAK,OAAO,QAAQ,uBAAuB;OAEzD,QAAQ,MAAM,uDAAuD,MAAM;EAE5E,QAAa,CAAC,CAAC,OAAO,QAAiB;GACtC,QAAQ,MAAM,0BAA0B,GAAG;GAC3C,QAAQ,KAAK,CAAC;EACf,CAAC;CACF,CAAC;CAGD,QAAQ,GAAG,WAAW,SAAS,UAAU;EACxC,IAAI,gBACH;EAED,iBAAiB;EAEjB,QAAQ,IAAI,iEAAiE;EAC7E,QAAa,CAAC,CAAC,OAAO,QAAiB;GACtC,QAAQ,MAAM,0BAA0B,GAAG;GAC3C,QAAQ,KAAK,CAAC;EACf,CAAC;CACF,CAAC;CAED,QAAQ,GAAG,UAAU,SAAS,SAAS;EACtC,IAAI,gBACH;EAED,iBAAiB;EAEjB,QAAQ,IAAI,2DAA2D;EACvE,QAAa,CAAC,CAAC,OAAO,QAAiB;GACtC,QAAQ,MAAM,0BAA0B,GAAG;GAC3C,QAAQ,KAAK,CAAC;EACf,CAAC;CACF,CAAC;AACF;;;;AAKA,MAAa,sBAA4B;CACxC,SAAM,eAAe;CAErB,QAAQ,KAAK,QAAQ,KAAK,SAAS;AACpC;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtCA,MAAa,yBAAyB;;;;;;;;;;;;;;;AAgBtC,MAAa,sBAAsB;;;;;;;;;;;;;;;;;;;;;;AA2BnC,MAAa,2BAA2B;;;;;;;;;;;;;;;;;;;;;;AAuBxC,MAAa,wBAAwB;;;;;;;;;;;;;;;;;;;AAwBrC,MAAa,yBAAyB;;;;;;;;;;;;;;;;;;;;;;AAiDtC,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;AAsBjC,MAAa,sBAAsB;;;;;;;;;;;;;;;;;;;;;;AAuBnC,MAAa,yBAAyB;;;ACjNtC,MAAMC,WAAQ,YAAY,uBAAuB;;;;AAiGjD,IAAa,eAAb,MAA0B;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;;;;CAKA,YAAY,SAA+B,CAAC,GAAG;EAC9C,KAAK,SAAS;GACb,YAAY;GACZ,kBAAkB;GAClB,cAAc;GACd,aAAa;GACb,qBAAqB;GACrB,GAAG;EACJ;EAEA,KAAK,4BAAY,IAAI,KAAK;EAC1B,KAAK,UAAU,CAAC;EAEhB,KAAK,WAAW;GACf,eAAe;GACf,aAAa;GACb,aAAa;GACb,aAAa;GACb,eAAe;GACf,sBAAsB;GACtB,QAAQ;IACP,aAAa;IACb,cAAc;IACd,QAAQ;IACR,aAAa;GACd;GACA,KAAK;IACJ,KAAK;IACL,SAAS;IACT,WAAW;GACZ;EACD;EAEA,KAAK,iBAAiB;GACrB,OAAO;GACP,QAAQ;GACR,WAAW,CAAC;GACZ,aAAa;GACb,aAAa;GACb,aAAa;EACd;EAEA,KAAK,gBAAgB,KAAK,mBAAmB;EAE7C,KAAK,SAAS,KAAA;EACd,IAAI,KAAK,OAAO,cAAc;GAC7B,KAAK,SAAS,kBAAkB;IAC/B,KAAK,aAAa;GACnB,GAAG,KAAK,OAAO,UAAU;GACzB,IAAI,KAAK,UAAU,OAAO,KAAK,OAAO,UAAU,YAC/C,KAAK,OAAO,MAAM;EAEpB;CACD;;;;CAKA,eAA6B;EAC5B,KAAK,iBAAiB;GACrB,OAAO;GACP,QAAQ;GACR,WAAW,CAAC;GACZ,aAAa;GACb,aAAa;GACb,aAAa;EACd;CACD;;;;;;CAOA,cAAc,UAAkB,UAAU,OAAa;EACtD,KAAK,SAAS;EACd,IAAI,SACH,KAAK,SAAS;EAGf,KAAK,SAAS,iBAAiB;EAC/B,IAAI,KAAK,SAAS,cAAc,KAAK,WAAW,KAAK,SAAS,aAC7D,KAAK,SAAS,cAAc;EAE7B,IAAI,KAAK,SAAS,cAAc,KAAK,WAAW,KAAK,SAAS,aAC7D,KAAK,SAAS,cAAc;EAG7B,MAAM,IAAI,KAAK;EACf,EAAE;EACF,IAAI,SACH,EAAE;EAGH,EAAE,eAAe;EACjB,IAAI,EAAE,cAAc,KAAK,WAAW,EAAE,aACrC,EAAE,cAAc;EAEjB,IAAI,EAAE,cAAc,KAAK,WAAW,EAAE,aACrC,EAAE,cAAc;EAGjB,IAAI,EAAE,UAAU,SAAS,KAAK,OAAO,qBACpC,EAAE,UAAU,KAAK,QAAQ;CAE3B;;;;;CAMA,qBAAkH;EACjH,MAAM,OAAO,GAAG,KAAK;EACrB,IAAI,OAAO;EACX,IAAI,OAAO;EACX,IAAI,MAAM;EACV,IAAI,OAAO;EACX,IAAI,MAAM;EAEV,KAAK,MAAM,OAAO,MAAM;GACvB,QAAQ,IAAI,MAAM;GAClB,QAAQ,IAAI,MAAM;GAClB,OAAO,IAAI,MAAM;GACjB,QAAQ,IAAI,MAAM;GAClB,OAAO,IAAI,MAAM;EAClB;EAEA,MAAM,QAAQ,OAAO,OAAO,MAAM,OAAO;EACzC,OAAO;GAAC;GAAM;GAAM;GAAK;GAAM;GAAK;EAAK;CAC1C;;;;;CAMA,qBAAqC;EACpC,MAAM,UAAU,KAAK,mBAAmB;EACxC,MAAM,OAAO,KAAK,iBAAiB;GAAC,MAAM;GAAG,MAAM;GAAG,KAAK;GAAG,MAAM;GAAG,KAAK;GAAG,OAAO;EAAC;EAEvF,MAAM,aAAa,QAAQ,QAAQ,KAAK;EACxC,MAAM,YAAY,QAAQ,OAAO,KAAK;EAEtC,KAAK,gBAAgB;EAErB,IAAI,cAAc,GAAG,OAAO;EAE5B,MAAM,WAAY,aAAa,aAAa,aAAc;EAC1D,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC;CAC1C;;;;;CAMA,aAAa,gBAAgC,CAAC,GAAS;EACtD,MAAM,IAAI,KAAK;EACf,MAAM,WAAW,QAAQ,YAAY;EACrC,MAAM,mBAAmB,GAAG,SAAS,IAAI,GAAG,QAAQ;EACpD,MAAM,WAAW,QAAQ,SAAS;EAClC,MAAM,MAAM,KAAK,mBAAmB;EAGpC,MAAM,YAAY,EAAE,SAAS,KAAK,OAAO,aAAa;EACtD,KAAK,SAAS,uBAAuB,KAAK,IAAI,KAAK,SAAS,sBAAsB,SAAS;EAC3F,KAAK,SAAS,OAAO,cAAc,KAAK,IAAI,KAAK,SAAS,OAAO,aAAa,SAAS,QAAQ;EAC/F,KAAK,SAAS,OAAO,eAAe,KAAK,IAAI,KAAK,SAAS,OAAO,cAAc,SAAS,SAAS;EAClG,KAAK,SAAS,OAAO,SAAS,KAAK,IAAI,KAAK,SAAS,OAAO,QAAQ,gBAAgB;EACpF,KAAK,SAAS,OAAO,cAAc,KAAK,IAAI,KAAK,SAAS,OAAO,aAAa,SAAS,QAAQ;EAC/F,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,KAAK,SAAS,IAAI,KAAK,GAAG;EAC3D,KAAK,SAAS,IAAI,UAAU,KAAK,IAAI,KAAK,SAAS,IAAI,SAAS,SAAS,IAAI;EAC7E,KAAK,SAAS,IAAI,YAAY,KAAK,IAAI,KAAK,SAAS,IAAI,WAAW,SAAS,MAAM;EAEnF,IAAI,MAAM;EACV,IAAI,MAAM;EACV,IAAI,EAAE,UAAU,SAAS,GAAG;GAC3B,MAAM,SAAS,EAAE,UAAU,UAAU,GAAG,MAAM,IAAI,CAAC;GACnD,MAAM,SAAS,KAAK,MAAM,OAAO,SAAS,GAAI;GAC9C,MAAM,SAAS,KAAK,MAAM,OAAO,SAAS,GAAI;GAC9C,MAAM,UAAU,OAAO,SAAS;GAEhC,MAAM,OAAO,WAAW,OAAO,YAAY;GAC3C,MAAM,OAAO,WAAW,OAAO,YAAY;EAC5C;EAEA,MAAM,SAAiB;GACtB,WAAW,KAAK,IAAI;GACpB,UAAU,EAAE;GACZ,QAAQ,EAAE;GACV,aAAa,KAAK,IAAI,EAAE,aAAa,CAAC;GACtC,aAAa,KAAK,IAAI,EAAE,aAAa,CAAC;GACtC,aAAa,EAAE,QAAQ,IAAI,EAAE,cAAc,EAAE,QAAQ;GACrD,aAAa;GACb,aAAa;GACb,QAAQ;IACP;IACA,UAAU,SAAS;IACnB,WAAW,SAAS;IACpB,KAAK;IACL,UAAU,SAAS;GACpB;GACA,OAAO;EACR;EAEA,KAAK,QAAQ,KAAK,MAAM;EACxB,IAAI,KAAK,QAAQ,SAAS,KAAK,OAAO,kBACrC,KAAK,QAAQ,MAAM;EAGpB,KAAK,aAAa;EAClB,SAAM,sBAAsB,MAAM;CACnC;;;;CAKA,OAAa;EACZ,IAAI,KAAK,QAAQ;GAChB,cAAc,KAAK,MAAM;GACzB,KAAK,SAAS,KAAA;EACf;CACD;;;;;CAMA,aAA2B;EAC1B,OAAO;GACN,WAAW,KAAK;GAChB,eAAe,KAAK,SAAS;GAC7B,aAAa,KAAK,SAAS;GAC3B,iBAAiB,KAAK,SAAS,gBAAgB,IAAI,KAAK,SAAS,gBAAgB,KAAK,SAAS,gBAAgB;GAC/G,iBAAiB,KAAK,SAAS;GAC/B,iBAAiB,KAAK,SAAS;GAC/B,sBAAsB,KAAK,SAAS;GACpC,WAAW,KAAK,SAAS;GACzB,KAAK,KAAK,SAAS;EACpB;CACD;;;;;CAMA,aAAuB;EACtB,OAAO,KAAK;CACb;AACD;;;;;;AC1VA,IAAa,eAAb,MAA0B;CACzB;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,QAAoB;EAC/B,KAAK,4BAAY,IAAI,KAAK;EAC1B,KAAK,SAAS;EACd,KAAK,QAAQ,CAAC;EACd,KAAK,SAAS,CAAC;EACf,KAAK,eAAe,IAAI,aAAa;EACrC,KAAK,UAAU;CAChB;;;;;;;;CASA,gBAAgB,OAAe,MAAY,oBAAmC,eAAsC;EACnH,KAAK,MAAM,KAAK,IAAI;EACpB,KAAK,OAAO,KAAK;GAChB,UAAU;GACV;GACA;EACD,CAAC;CACF;CAEA,IAAI,SAAkB;EACrB,OAAO,KAAK;CACb;CAEA,UAAU,OAAsB;EAC/B,KAAK,UAAU;CAChB;AACD;;;;;;;;;AC9CA,MAAa,oBAAoB,aAA6B;CAC7D,IAAI;EACH,OAAO,aAAa,UAAU,MAAM;CACrC,QAAQ;EACP,MAAM,IAAI,MAAM,wBAAwB,SAAS,EAAE;CACpD;AACD;;;;;;;AAQA,MAAa,WAAW,OAAO,aAAsC;CACpE,IAAI;EACH,OAAO,MAAMC,SAAG,SAAS,QAAQ;CAClC,QAAQ;EACP,MAAM,IAAI,MAAM,wBAAwB,SAAS,EAAE;CACpD;AACD;;;;;;AAOA,MAAa,aAAa,OAAO,aAAoC;CACpE,IAAI;EACH,MAAMA,SAAG,OAAO,QAAQ;CACzB,QAAQ;EACP,MAAM,IAAI,MAAM,0BAA0B,SAAS,EAAE;CACtD;AACD;;;;;;;AAQA,MAAa,eAAe,aAA8B;CACzD,IAAI;EACH,MAAM,cAAc,aAAa,UAAU,MAAM;EACjD,OAAO,KAAK,MAAM,WAAW;CAC9B,QAAQ;EACP,MAAM,IAAI,MAAM,wBAAwB,SAAS,EAAE;CACpD;AACD;;;;;;AAOA,MAAa,cAAc,OAAO,kBAA6C;CAC9E,IAAI,OAAO,kBAAkB,UAC5B,OAAO;CAKR,QAAO,MAFaA,SAAG,KAAK,aAAa,EAAA,CAE5B,YAAY;AAC1B;;;;;;AAOA,MAAa,SAAS,OAAO,aAAwC;CACpE,IAAI,OAAO,aAAa,UACvB,OAAO;CAGR,IAAI;EAEH,QAAO,MADaA,SAAG,KAAK,QAAQ,EAAA,CACvB,OAAO;CACrB,QAAQ;EACP,OAAO;CACR;AACD;;;;;;;;;AC/EA,MAAa,cAAc,UAC1B,MAAM,WAAW,KAAK,OAAO,CAAC,CAAC,WAAW,KAAK,MAAM,CAAC,CAAC,WAAW,KAAK,MAAM,CAAC,CAAC,WAAW,MAAK,QAAQ,CAAC,CAAC,WAAW,KAAK,OAAO;;;;;;AAOjI,MAAa,sBAAsB,SAAyB;CAC3D,IAAI,OAAO,WAAW,IAAI;CAE1B,OAAO,KAAK,WAAW,gBAAgB,QAAQ;CAC/C,OAAO,KAAK,WAAW,KAAM,oBAAoB;CAEjD,OAAO;AACR;;;;;;AAOA,MAAa,eAAe,SAAyB;;;;;;;;;;;;;;;;;;EAkBnD,KAAK;;;;;;;;;;;AC/BP,MAAM,mBAAmB,QAAuC;CAC/D,IAAI,OAAO,QAAQ,YAAY,QAAQ,MACtC,OAAO;CAER,OAAO,SAAS,OAAO,UAAU,OAAO,SAAS,OAAO,aAAa,OAAO,kBAAkB;AAC/F;AAiBA,MAAM,eAAe,IAAI,OAAO,GAAG;AACnC,MAAM,eAAe,IAAI,OAAO,EAAE;;;;;;;;AASlC,MAAa,WAAW,OAAgB,QAAuB,SAAiB;CAC/E,IAAI;EACH,OAAO,KAAK,QAAQ,OAAO;GAAC,YAAY;GAAO;GAAO,QAAQ;EAAK,CAAC;CACrE,QAAQ,CAER;CAEA,IAAI;EACH,OAAO,KAAK,UAAU,KAAK;CAC5B,QAAQ,CAER;CAEA,OAAO;AACR;;;;;;AAQA,MAAM,WAAW,MAAc,UAAkB,KAAK,OAAO,OAAO,GAAG;;;;;;;;AASvE,MAAa,WAAW,MAAgB,SAAiC;CACxE,IAAI,KAAK,WAAW,GACnB,MAAM,IAAI,MAAM,sBAAsB;CAIvC,MAAM,SAAS,KAAK,KAAK,GAAG,MAAM;EACjC,MAAM,UAAU,KAAK,IAAI,GAAG,GAAG,KAAK,KAAK,SAAS,IAAI,MAAM,GAAA,CAAI,MAAM,CAAC;EACvE,OAAO,KAAK,IAAI,EAAE,QAAQ,OAAO;CAClC,CAAC;;;;;CAMD,MAAM,YAAY,MAAsB,OAAO,MAAM;CAUrD,OAAO;EAAC,MANK;GAHM,KAAK,KAAK,GAAG,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAG7C;GAFD,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,KAE3B;GAAG,GADxB,KAAK,KAAK,QAAQ,KAAK,KAAK,GAAG,MAAM,QAAQ,IAAI,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CACjD;EAAC,CAAC,CAAC,KAAK,IAMhD;EAAG,MAAA,qBAJG,KAAK,KAAK,MAAM,OAAO,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,EAE1B,EAAE,sBAD1B,KAAK,KAAK,QAAQ,OAAO,KAAK,KAAK,GAAG,MAAM,OAAO,WAAW,IAAI,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC,KAAK,EACnD,EAAE;CAExD;AACnB;;;;;;AAOA,MAAa,aAAa,SAAuB;CAChD,MAAM,KAAK,mBAAmB,aAAa,aAAa;EACvD,MAAA;EACA,UAAA;EACA,UAAA;EACA,UAAU;CACX,CAAC;CAED,GAAG,MAAM,IAAI;CACb,GAAG,IAAI;AACR;;;;;;;AAQA,MAAM,kBAAkB,QAAyB;CAChD,MAAM,cAAuC,CAAC;CAE9C,OAAO,KAAK,GAAG,CAAC,CACd,QAAQ,SAAS;EAAC;EAAe;EAAU;EAAS;EAAO;EAAU;EAAQ;EAAS;EAAU;CAAS,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAC1H,SAAS,SAAS;EAClB,YAAY,QAAQ,IAAI;CACzB,CAAC;CAEF,OAAO,QAAQ,WAAW;AAC3B;;;;;;AAOA,MAAM,eAAe,QAAoC;CACxD,QAAQ,KAAR;EACC,KAAK,SAAS,SACb,OAAO;EACR,KAAK,SAAS,UACb,OAAO;EACR,KAAK,SAAS,YACb,OAAO;EACR,SACC,OAAO;CACT;AACD;;;;;;AAOA,MAAM,oBAAoB,SAA0B;CACnD,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU,MAC1D,OAAQ,KAAwB;CAGjC,IAAI,OAAO,SAAS,UACnB,OAAO;CAGR,IAAI,OAAO,SAAS,UACnB,OAAO,KAAK,SAAS;CAGtB,OAAO;AACR;;;;;;AAOA,MAAM,wBAAwB,QAAoB,SAA+B;CAChF,MAAM,OAAO,OAAO,QAAQ,IAAI;CAEhC,IAAI,KAAK,WAAW,GACnB;CAGD,MAAM,OAAO,KAAK,KAAK,CAAC,IAAI,SAAS;EACpC,IAAI,MAAM;EACV,IAAI,eAAe;EACnB,IAAI,UAAU;EACd,IAAI,WAAW;EACf,IAAI,QAAQ;EACZ,IAAI,YAAY;EAEhB,IAAI,gBAAgB,GAAG,GAAG;GACzB,MAAM,YAAY,IAAI,GAAG;GACzB,eAAe,IAAI,eAAe,IAAI,aAAa,SAAS,IAAI;GAChE,UAAU,IAAI,UAAU,IAAI,QAAQ,SAAS,IAAI;GACjD,WAAW,iBAAiB,IAAI,IAAI;GACpC,QAAQ,QAAQ,IAAI,GAAG;GACvB,YAAY,OAAO,IAAI;EACxB,OAAO;GACN,QAAQ,QAAQ,GAAG;GACnB,YAAY,OAAO;EACpB;EAEA,OAAO;GAAC;GAAI;GAAK;GAAc;GAAS;GAAU;GAAO;EAAS;CACnE,CAAC;CAED,MAAM,EAAC,MAAM,SAAQ,QAAQ;EAAC;EAAM;EAAO;EAAgB;EAAW;EAAa;EAAS;CAAY,GAAG,IAAI;CAE/G,OAAO,QAAQ;CACf,OAAO,QAAQ;AAChB;;;;;;AAOA,MAAM,sBAAsB,QAAoB,gBAAuC;CACtF,MAAM,OAAO,OAAO,QAAQ,WAAW;CAEvC,IAAI,KAAK,WAAW,GACnB;CAGD,MAAM,EAAC,MAAM,SAAQ,QAAQ,CAAC,OAAO,OAAO,GAAG,IAAI;CAEnD,OAAO,QAAQ;CACf,OAAO,QAAQ;AAChB;;;;;;;AAQA,MAAa,YAAY,OAAe,SAAyB,KAAK,eAAe,MAAM,YAAY,IAAI,aAAa,IAAI;;;;;;AAO5H,MAAM,eAAe,SAAyB,MAAM,mBAAmB,IAAI,EAAE;;;;;;AAO7E,MAAM,eAAe,SAAyB,GAAG,KAAK;;;;;;AAOtD,MAAM,WAAW,QAAoB,SAAuB;CAC3D,OAAO,QAAQ,YAAY,IAAI;CAC/B,OAAO,QAAQ,YAAY,IAAI;AAChC;;;;;;AAOA,MAAM,aAAa,QAAoB,SAAuB;CAC7D,OAAO,QAAQ,OAAO,KAAK;CAC3B,OAAO,QAAQ,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE;AACtD;;;;;;;AAQA,MAAM,gBAAgB,QAAoB,KAAa,SAA+B;CACrF,OAAO,QAAQ,GAAG,IAAI;CACtB,OAAO,QAAQ,GAAG,IAAI;CAEtB,IAAI;EACH,qBAAqB,QAAQ,IAAI;CAClC,SAAS,KAAK;EACb,QAAQ,QAAQ,qCAAqC,cAAc,GAAG,GAAG;CAC1E;CAEA,OAAO,QAAQ;CACf,OAAO,QAAQ;AAChB;;;;;;AAOA,MAAa,uBAAuB,SAAkC;CACrE,MAAM,YAAY,KAAK,6BAAa,IAAI,KAAK;CAG7C,MAAM,MAAM,OAAO,KAAK,KAAK,gBAAgB,YAAY,KAAK,IAAI,YAAY,SAAS,IAAI,OAAO,KAAK,IAAI,gBAAgB;CAE3H,MAAM,SAAS,IADD,KAAK,QAAQ,QAAA,CAAS,YACf,EAAE,MAAM,UAAU,YAAY,IAAI;CACvD,MAAM,SAAqB;EAC1B,MAAM,OAAO,OAAO;EACpB,MAAM,OAAO,aAAa,OAAO,OAAO,IAAI,aAAa;CAC1D;CAGA,UAAU,QAAQ,OAAO;CACzB,QAAQ,QAAQ,KAAK,OAAO;CAG5B,IAAI,KAAK,KAAK;EACb,UAAU,QAAQ,SAAS;EAC3B,QAAQ,QAAQ,eAAe,KAAK,GAAG,CAAC;CACzC;CAGA,IAAI,KAAK,OAAO,KAAK,MAAM;EAC1B,UAAU,QAAQ,WAAW;EAC7B,aAAa,QAAQ,KAAK,KAAK,KAAK,IAAI;CACzC;CAGA,IAAI,KAAK,aAAa;EACrB,UAAU,QAAQ,aAAa;EAC/B,mBAAmB,QAAQ,KAAK,WAAW;CAC5C;CAEA,OAAO;AACR;;;;;AAMA,MAAa,kBAAkB,SAA4B;CAC1D,MAAM,EAAC,SAAQ,oBAAoB,IAAI;CAGvC,UAAU,IAAI;CAGd,QAAQ,KAAK,IAAI;AAClB;;;;;;;;;AC/VA,MAAa,iBAAiB,UAA2B;CACxD,IAAI,OAAO,UAAU,UACpB,OAAO;MACD,IAAI,iBAAiB,OAAO;EAClC,MAAM,QAAQ,CAAC,MAAM,IAAI;EACzB,IAAI,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,SAAS,GAC/D,MAAM,KAAK,MAAM,OAAO;EAEzB,IAAI,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,SAAS,GAC3D,MAAM,KAAK,MAAM,KAAK;EAEvB,OAAO,MAAM,KAAK,IAAI;CACvB,OACC,OAAO,QAAQ,KAAK;AAEtB;;;AClBA,MAAMC,WAAQ,YAAY,qBAAqB;AAU/C,MAAM,aAAa,EAAE,MACpB,EAAE,aAAa;CACd,WAAW,EAAE,OAAO;CACpB,cAAc,EAAE,OAAO;CACvB,UAAU,EAAE,OAAO;CACnB,UAAU,EAAE,OAAO;CACnB,aAAa,EAAE,OAAO;CACtB,UAAU,EAAE,OAAO;CACnB,MAAM,EAAE,OAAO;CACf,MAAM,EAAE,OAAO;AAChB,CAAC,CACF;;;;;;;AAQA,MAAa,YAAY,QAAmC;CAC3D,IAAI,EAAE,WAAW,MAAM;EACtB,SAAM,oBAAoB;EAC1B,OAAO,CAAC;CACT;CAEA,IAAI,OAAO,IAAI,UAAU,YAAY,IAAI,UAAU,QAAQ,OAAO,KAAK,IAAI,KAAe,CAAC,CAAC,WAAW,GAAG;EACzG,SAAM,oBAAoB;EAC1B,OAAO,CAAC;CACT;CAEA,MAAM,QAAQ,WAAW,MAAM,IAAI,KAAK;CAExC,KAAK,MAAM,QAAQ,OAClB,KAAK,YAAY,IAAI,KAAK;CAG3B,SAAM,YAAY,KAAK;CAEvB,OAAO;AACR;;;;;;;;;AAUA,MAAa,aAAa,OAAO,MAAsB,UAAkB,uBAAkD;CAC1H,SAAM,cAAc,MAAM,QAAQ;;CAGlC,IAAI,OAAO,aAAa,YAAY,SAAS,WAAW,GACvD,MAAM,IAAI,MAAM,0BAA0B,KAAK,SAAS,sDAAsD;CAI/G,IAAI;CACJ,IAAI;EACH,cAAc,MAAM,SAAS,KAAK,IAAI;CACvC,SAAS,KAAK;EACb,MAAM,IAAI,MAAM,wBAAwB,KAAK,KAAK,MAAM,cAAc,GAAG,GAAG;CAC7E;CAGA,MAAM,MAAM,eAAe,SAAS;CACpC,MAAM,OAAO;EACZ,MAAM,KAAK;EACX,WAAW,KAAK;EAChB,UAAU,KAAK;EACf,cAAc;GACb,KAAK;GACL,MAAM;EACP;CACD;CACA,IAAI;EACH,MAAM,mBAAmB,QAAQ,KAAK,MAAM,EAAC,YAAY,KAAI,CAAC;CAC/D,SAAS,KAAK;EACb,MAAM,IAAI,MAAM,0BAA0B,KAAK,SAAS,MAAM,cAAc,GAAG,GAAG;CACnF;CAGA,IAAI;EACH,MAAM,WAAW,KAAK,IAAI;CAC3B,SAAS,KAAK;EACb,MAAM,IAAI,MAAM,0BAA0B,KAAK,SAAS,MAAM,cAAc,GAAG,GAAG;CACnF;AACD;;;AClGA,MAAMC,WAAQ,YAAY,4BAA4B;;;;;;;;AActD,MAAa,wBAAwB,MAAe,UAAkB,WAA4D;;CAEjI,IAAIA,SAAM,SACT,SAAM,yBAAyB,SAAS,cAAc,MAAM;;CAI7D,MAAM,QAAkB,CAAC;CACzB,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,OAAO,QAAQ;EACzB,MAAM,QAAQ,OAAO;EACrB,IAAI,OAAO,UAAU,UAAU;GAC9B,MAAM,KAAK,GAAG;GACd,OAAO,KAAK,KAAK;EAClB,OAAO,IAAI,MAAM,QAAQ,KAAK,GAC7B,MAAM,SAAS,SAAS;GACvB,MAAM,KAAK,GAAG;GACd,OAAO,KAAK,IAAI;EACjB,CAAC;CAEH;CAEA,OAAO;EACN,KAAK,GAAG,SAAS;EACjB,MAAM;GACL,UAAU;IAAC,KAAK;IAAS,MAAM;IAAQ,KAAK;GAAK;GACjD,WAAW;IAAC,KAAK;IAAS,MAAM;IAAQ,KAAK;GAAM;EACpD;CACD;AACD;;;AC7CA,IAAa,eAAb,MAAa,qBAAqB,MAAM;CACvC;;;;CAKA,YAAY,SAAiB;EAC5B,MAAM,OAAO;EAGb,IAAI,MAAM,mBACT,MAAM,kBAAkB,MAAM,YAAY;EAI3C,KAAK,4BAAY,IAAI,KAAK;CAC3B;AACD;;;;;;;;;ACSA,MAAa,kBAAkB,UAAkC;CAEhE,IAAI,OAAO,UAAU,UACpB,OAAO,CAAC,OAAO,MAAM,KAAK,KAAK,OAAO,SAAS,KAAK,IAAI,QAAQ;CAKjE,IAAI,OAAO,UAAU,YAAY,CAAC,iDAAiD,KAAK,KAAK,GAC5F,OAAO;CAIR,OAAO,OAAO,KAAK;AACpB;;;ACvCA,MAAMC,UAAQ,YAAY,yBAAyB;AAanD,MAAM,mBAAmB;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC,CAAC,KAAK,IAAI;AAEX,MAAM,aAAa,OAAO,OAAO;CAChC,UAAU;CACV,MAAM;CACN,gBAAgB;CAChB,QAAQ;CACR,MAAM;CACN,MAAM;CACN,cAAc;AASf,CAAC;;;;;;;;;AAUD,MAAM,gBAAgB,OAAO,WAAmB,uBAAsD;CACrG,MAAM,OAAuB;EAC5B,MAAM;GAAC,KAAK;GAAS,MAAM;GAAQ,KAAK;EAAS;EACjD,OAAO;GAAC,KAAK;GAAU,MAAM;GAAQ,SAAS;GAAI,cAAc;EAAwB;EACxF,OAAO;GAAC,KAAK;GAAU,MAAM;GAAQ,SAAS;GAAI,cAAc;EAAwB;CACzF;CAEA,IAAI,SAA0B,CAAC;CAC/B,IAAI;EACH,SAAS,MAAM,mBAAmB,QAAQ,kBAAkB,IAAI;CACjE,SAAS,KAAK;;EAEb,QAAM,UAAU,MAAM;EAItB,MAAM,IAAI,aAAa,oCAD6B,iBAAiB,IAAI,cAAc,GAAG,GAC5D;CAC/B;CAEA,IAAI;CACJ,IAAI;EACH,OAAO,EACL,OAAO;GACP,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC;GACpC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC;EACrC,CAAC,CAAC,CACD,MAAM,OAAO,QAAQ;CACxB,SAAS,KAAK;;EAEb,QAAM,mBAAmB,OAAO,QAAQ;EAIxC,MAAM,IAAI,aAAa,kCAD2B,iBAAiB,IAAI,cAAc,GAAG,GAC1D;CAC/B;CAEA,IAAI,KAAK,MAAM,WAAW,KAAK,MAAM,QACpC,MAAM,IAAI,aAAa,6EAA6E;CAGrG,MAAM,WAAqB,CAAC;CAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;EAC3C,MAAM,OAAO,KAAK,MAAM;EACxB,MAAM,OAAO,KAAK,MAAM;EACxB,IAAI,QAAQ,MACX,SAAS,KAAK,YAAY,KAAK;CAEjC;CAEA,OAAO;AACR;;;;;;;;;AAUA,MAAM,gBAAgB,OAAO,WAAmB,oBAAgC,kBAAoD;CACnI,MAAM,MAAM,UAAU,YAAY;CAGlC,MAAM,aAAa,cAAc,IAAI,GAAG;CAGxC,IAAI,YAAY;;EAEf,IAAIA,QAAM,SACT,QAAM,6BAA6B,UAAU,iBAAiB;;EAI/D,OAAO;CACR;;CAIA,IAAIA,QAAM,SACT,QAAM,6BAA6B,UAAU,wCAAwC;;CAItF,MAAM,OAAO,MAAM,cAAc,WAAW,kBAAkB;CAG9D,cAAc,IAAI,KAAK,IAAI;CAE3B,OAAO;AACR;;;;;;;;AASA,MAAa,cAAc,SAAiB,UAAmB,YAAmC;CACjG,MAAM,UAAU,aAAa,MAAM,aAAa,QAAQ,aAAa,KAAA;CAErE,IAAI,YAAY,WAAW,YAAY,YAAY,WAAW,MAC7D,OAAO;EAAC,KAAK;EAAS,MAAM;EAAiB,KAAK,UAAU,OAAO;CAAQ;CAG5E,IAAI,YAAY,WAAW,MAC1B,OAAO;EAAC,KAAK;EAAS,MAAM;EAAc,KAAK,UAAU,OAAO;CAAQ;CAGzE,IAAI,YAAY,WAAW,UAAU,YAAY,WAAW,gBAAgB;EAC3E,IAAI,SACH,OAAO;GAAC,KAAK;GAAS,MAAM;GAAgB,KAAK;EAAI;EAEtD,MAAM,QAAQ,eAAe,QAAQ;EACrC,IAAI,UAAU,MACb,MAAM,IAAI,MAAM,6BAA6B,QAAQ,oBAAoB,QAAQ,QAAQ,EAAE,cAAc,QAAQ,EAAE;EAGpH,OAAO;GAAC,KAAK;GAAS,MAAM;GAAgB,KAAK;EAAK;CACvD;CAEA,IAAI,YAAY,WAAW,MAAM;EAChC,IAAI,SACH,OAAO;GAAC,KAAK;GAAS,MAAM;GAAc,KAAK;EAAI;EAEpD,IAAI,OAAO,aAAa,UACvB,MAAM,IAAI,UAAU,6BAA6B,QAAQ,oBAAoB,QAAQ,QAAQ,EAAE,cAAc,QAAQ,EAAE;EAExH,MAAM,QAAQ,IAAI,KAAK,QAAQ;EAC/B,IAAI,OAAO,MAAM,MAAM,QAAQ,CAAC,GAC/B,MAAM,IAAI,UAAU,6BAA6B,QAAQ,oBAAoB,QAAQ,QAAQ,EAAE,cAAc,QAAQ,EAAE;EAGxH,OAAO;GAAC,KAAK;GAAS,MAAM;GAAc,KAAK;EAAK;CACrD;CAEA,IAAI,YAAY,WAAW,gBAAgB,MAAM,QAAQ,QAAQ,GAGhE,OAAO;EAAC,KAAK;EAAS,MAAM;EAAiB,KAF/B,OAAO,aAAa,WAAW,CAAC,QAAQ,IAAI;CAEH;CAGxD,MAAM,IAAI,MAAM,6BAA6B,QAAQ,2BAA2B,QAAQ,EAAE;AAC3F;;;;;;;AAQA,MAAM,mBAAmB,QAAoB,aAA+B;CAK3E,MAAM,EAAC,SAAQ,QAAQ;EAAC;EAAM;EAAS;EAAc;CAAe,GAJvD,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW;EACzD,OAAO;GAAC;GAAK,MAAM,SAAS;GAAG,OAAO;GAAO,SAAS,IAAI,YAAY,MAAM;EAAS;CACtF,CAE0E,CAAC;CAE3E,OAAO;AACR;;;;;;;;;;AAWA,MAAa,oBAAoB,OAChC,KACA,UACA,QACA,oBACA,kBACkD;CAClD,QAAM,sBAAsB,SAAS,cAAc,MAAM;CAGzD,MAAM,WAAW,MAAM,cAAc,UAAU,oBAAoB,aAAa;CAEhF,MAAM,eAAyB,CAAC;CAEhC,MAAM,WAA2B,CAAC;CAGlC,KAAK,MAAM,OAAO,QAAQ;EACzB,MAAM,gBAAgB,KAAK;EAC3B,MAAM,WAAW,OAAO;EACxB,MAAM,UAAU,SAAS,IAAI,YAAY;EACzC,IAAI,OAAsB;GAAC,KAAK;GAAS,MAAM;GAAiB,KAAK;EAAQ;EAE7E,IAAI,SACH,OAAO,WAAW,KAAK,UAAU,OAAO;OAGxC,eAAe;GACd,MAAM;GACN,SAAS,6BAA6B,IAAI,2BAA2B,QAAQ,OAHjE,gBAAgB,QAAQ,QAGmD;GACvF;EACD,CAAC;EAGF,aAAa,KAAK,GAAG,IAAI,KAAK,eAAe;EAC7C,SAAS,iBAAiB;CAC3B;CAGA,MAAM,MAAM,GAAG,SAAS,GAAG,aAAa,KAAK,IAAI,EAAE;;CAGnD,IAAIA,QAAM,SAAS;EAClB,QAAM,GAAG;EACT,QAAM,gBAAgB,QAAQ,QAAQ,CAAC;CACxC;;CAGA,OAAO;EAAC;EAAK,MAAM;CAAQ;AAC5B;;;ACzRA,MAAMC,UAAQ,YAAY,oBAAoB;;;;;;;AAU9C,MAAa,aAAa,SAA2B;CACpD,MAAM,OAAiB;EACtB,MAAM;EACN,MAAM;GACL,SAAS,CAAC;GACV,cAAc,CAAC;EAChB;EACA,MAAM;GACL,UAAU;GACV,UAAU;GACV,UAAU;EACX;CACD;CAOA,IAAI,OAAO;CACX,MAAM,oBAAoB,KAAK,QAAQ,MAAM;CAC7C,IAAI,sBAAsB,IACzB,OAAO;MACD;EACN,OAAO,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,oBAAoB,CAAC,CAAC;EACvD,KAAK,OAAO,KAAK,MAAM,KAAK,IAAI,GAAG,oBAAoB,CAAC,CAAC;CAC1D;CAMA,QAAM,0CAA0C;CAChD,KAAK,MAAM,IAAI,CAAC,CAAC,SAAS,SAAS;EAClC,MAAM,SAAS,UAAU,IAAI;EAE7B,IAAI,QACH,QAAQ,OAAO,KAAK,YAAY,GAAhC;GACC,KAAK;IACJ;KACC,MAAM,SAAS,YAAY,OAAO,KAAK;KACvC,QAAM,0CAA0C,OAAO,MAAM,oCAAoC,KAAK,UAAU,MAAM,GAAG;KACzH,IAAI,WAAW,MACd,MAAM,IAAI,MAAM,mDAAmD,OAAO,MAAM,uBAAuB;UAEvG,KAAK,KAAK,QAAQ,KAAK,MAAM;IAE/B;IACA;GAED,KAAK;IACJ,KAAK,KAAK,cAAc,OAAO;IAC/B,QAAM,4CAA4C,KAAK,KAAK,YAAY,aAAa;IACrF;GAED,KAAK;IACJ;KACC,MAAM,gBAAgB,OAAO,SAAS,OAAO,OAAO,EAAE;KACtD,IAAI,OAAO,MAAM,aAAa,GAC7B,MAAM,IAAI,UAAU,4DAA4D,OAAO,MAAM,uBAAuB;UAC9G;MACN,KAAK,KAAK,gBAAgB;MAC1B,QAAM,mDAAmD,KAAK,KAAK,cAAc,aAAa;KAC/F;IACD;IACA;GAED,KAAK;IACJ;KACC,MAAM,aAAa,OAAO,SAAS,OAAO,OAAO,EAAE;KACnD,IAAI,OAAO,MAAM,UAAU,GAC1B,MAAM,IAAI,UAAU,+CAA+C,OAAO,MAAM,uBAAuB;UACjG;MACN,KAAK,KAAK,aAAa;MACvB,QAAM,sCAAsC,KAAK,KAAK,WAAW,aAAa;MAC9E,MAAM,QAAQ,OAAO,MAAM,QAAQ,GAAG;MACtC,IAAI,UAAU,IACb,KAAK,KAAK,oBAAoB,OAAO,MAAM,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC;KAEzE;IACD;IACA;GAED,KAAK;IACJ,KAAK,KAAK,mBAAmB,OAAO;IACpC,QAAM,wCAAwC,KAAK,KAAK,WAAW,aAAa;IAChF;GAED,KAAK,mBACJ;GAED;IACC,KAAK,KAAK,aAAa,OAAO,QAAQ,OAAO;IAC7C;EACF;CAEF,CAAC;CAED,OAAO;AACR;;;;;;AAOA,MAAM,aAAa,SAAuD;CACzE,MAAM,QAAQ,KAAK,QAAQ,GAAG;CAE9B,IAAI,UAAU,IACb,OAAO;EACN,MAAM,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK;EAC7C,OAAO,KAAK,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK;CAChD;CAGD,OAAO;AACR;;;;;;AAOA,MAAM,eAAe,SAAoC;CAExD,IAAI,OAAO,SAAS,YAAY,KAAK,KAAK,CAAC,CAAC,WAAW,GACtD,OAAO;CAIR,IAAI,iBAAiB,KAAK,MAAM,GAAG;CAGnC,iBAAiB,eAAe,KAAK,YAAY,QAAQ,KAAK,CAAC;CAG/D,MAAM,eAAe,eAAe;CACpC,IAAI,CAAC,cACJ,OAAO;CAER,MAAM,QAAQ,aAAa,QAAQ,GAAG;CACtC,IAAI,SAAS,GAEZ,OAAO;CAGR,MAAM,SAAqB;EAC1B,MAAM,aAAa,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK;EACrD,OAAO,aAAa,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK;EACvD,SAAS,CAAC;CACX;CAGA,eAAe,MAAM;CAGrB,eAAe,SAAS,YAAY;EACnC,IAAI,QAAQ,YAAY,CAAC,CAAC,WAAW,OAAO,GAC3C,OAAO,QAAQ,OAAO,QAAQ,MAAM,CAAC;OAC/B,IAAI,QAAQ,YAAY,CAAC,CAAC,WAAW,SAAS,GACpD,OAAO,QAAQ,SAAS,QAAQ,MAAM,CAAC;OACjC,IAAI,QAAQ,YAAY,CAAC,CAAC,WAAW,QAAQ,GACnD,OAAO,QAAQ,SAAS;OAClB,IAAI,QAAQ,YAAY,CAAC,CAAC,WAAW,UAAU,GAAG;GACxD,MAAM,OAAO,cAAc,QAAQ,MAAM,CAAC,CAAC;GAC3C,IAAI,MACH,OAAO,QAAQ,UAAU;EAE3B,OAAO,IAAI,QAAQ,YAAY,CAAC,CAAC,WAAW,UAAU,GACrD,OAAO,QAAQ,WAAW;CAE5B,CAAC;CAED,OAAO;AACR;;;;;;AAOA,MAAM,iBAAiB,UAA+B;CACrD,MAAM,SAAS,IAAI,KAAK,KAAK;CAC7B,IAAI,OAAO,MAAM,OAAO,QAAQ,CAAC,GAChC,OAAO;CAER,OAAO;AACR;;;AClMA,MAAMC,UAAQ,YAAY,uBAAuB;;;;;;;;AAcjD,MAAM,yBAAyB,OAAO,UAA2B,QAAiC;CACjG,MAAM,IAAI,SAAe,SAAS,WAAW;EAC5C,IAAI,UAAU;EACd,MAAM,yBAAyB,OAAO,IAAI,OAAO;EACjD,MAAM,4BAA4B,OAAO,IAAI,mBAAmB;EAEhE,MAAM,gBAAgB;GACrB,SAAS,eAAe,OAAO,aAAa;GAC5C,SAAS,eAAe,SAAS,eAAe;GAChD,SAAS,eAAe,SAAS,eAAe;GAChD,IAAI,2BAA2B;IAC9B,IAAI,eAAe,UAAU,gBAAgB;IAC7C,IAAI,eAAe,SAAS,eAAe;GAC5C;EACD;EAEA,MAAM,oBAAoB;GACzB,IAAI,SACH;GAED,UAAU;GACV,QAAQ;GACR,QAAQ;EACT;EAEA,MAAM,cAAc,UAAiB;GACpC,IAAI,SACH;GAED,UAAU;GACV,QAAQ;GACR,OAAO,KAAK;EACb;EAEA,MAAM,sBAAsB;GAC3B,YAAY;EACb;EAEA,MAAM,wBAAwB;GAC7B,YAAY;EACb;EAEA,MAAM,mBAAmB,UAAiB;GACzC,WAAW,KAAK;EACjB;EAEA,MAAM,yBAAyB;GAC9B,YAAY;EACb;EAEA,MAAM,wBAAwB;GAC7B,YAAY;EACb;EAEA,SAAS,GAAG,OAAO,aAAa;EAChC,SAAS,GAAG,SAAS,eAAe;EACpC,SAAS,GAAG,SAAS,eAAe;EACpC,IAAI,wBAAwB;GAC3B,IAAI,GAAG,UAAU,gBAAgB;GACjC,IAAI,GAAG,SAAS,eAAe;EAChC;EAEA,IAAI;GACH,SAAS,KAAK,GAAG;EAClB,SAAS,OAAgB;GACxB,WAAW,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;EACrE;CACD,CAAC;AACF;;;;;;;AAQA,MAAa,eAAe,OAAO,MAAe,KAAe,SAAkC;CAClG,MAAM,YAAsB,CAAC;CAG7B,KAAK,KAAK,QAAQ,SAAS,WAAW;;EAErC,IAAIA,QAAM,SACT,UAAU,KAAK,qBAAqB,OAAO,KAAK,WAAW,OAAO,MAAM,YAAY,KAAK,UAAU,OAAO,OAAO,GAAG;;EAIrH,IAAI,OAAO,OAAO,MAAM,OAAO,OAAO,OAAO,OAAO;CACrD,CAAC;CAGD,IAAI,OAAO,KAAK,KAAK,qBAAqB,YAAY,KAAK,KAAK,iBAAiB,SAAS,GAAG;;EAE5F,IAAIA,QAAM,SAAS;GAClB,UAAU,KAAK,sBAAsB,KAAK,KAAK,iBAAiB,GAAG;GACnE,QAAM,SAAS,YAAY,UAAU,KAAK,IAAI,CAAC,CAAC;EACjD;;EAGA,IAAI,SAAS,KAAK,KAAK,KAAK,gBAAgB;EAC5C;CACD;CAGA,KAAK,MAAM,OAAO,KAAK,KAAK,cAAc;;EAEzC,IAAIA,QAAM,SACT,UAAU,KAAK,YAAY,IAAI,MAAM,KAAK,KAAK,aAAa,KAAK,GAAG;;EAIrE,IAAI,IAAI,KAAK,KAAK,KAAK,aAAa,IAAI;CACzC;CAGA,IAAI,KAAK,KAAK,aAAa,OAAO,KAAK,KAAK,aAAa,KAAK;EAC7D,MAAM,UAAkC,CAAC;EAEzC,IAAI,OAAO,KAAK,KAAK,gBAAgB,YAAY,KAAK,KAAK,YAAY,SAAS,GAC/E,QAAQ,kBAAkB,KAAK,KAAK;EAGrC,IAAI,OAAO,KAAK,KAAK,aAAa,YAAY,KAAK,KAAK,WAAW,GAClE,QAAQ,oBAAoB,KAAK,KAAK,SAAS,SAAS;EAGzD,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,GAAG;;GAEpC,IAAIA,QAAM,SACT,UAAU,KAAK,sBAAsB,KAAK,UAAU,OAAO,EAAE,EAAE;;GAIhE,IAAI,UAAU,KAAK,OAAO;EAC3B;EAGA,IAAI,KAAK,KAAK,oBAAoB,OAAO,UAAU;;GAElD,IAAIA,QAAM,SAAS;IAClB,UAAU,KAAK,aAAa,KAAK,KAAK,YAAY,GAAG,eAAe;IACpE,QAAM,SAAS,YAAY,UAAU,KAAK,IAAI,CAAC,CAAC;GACjD;;GAGA,MAAM,uBAAuB,KAAK,KAAK,UAAU,GAAG;EACrD,OAAO;;GAEN,IAAIA,QAAM,SAAS;IAClB,UAAU,KAAK,YAAY,KAAK,KAAK,YAAY,GAAG,YAAY;IAChE,QAAM,SAAS,YAAY,UAAU,KAAK,IAAI,CAAC,CAAC;GACjD;;GAGA,IAAI,IAAI,KAAK,KAAK,UAAU,QAAQ;EACrC;EACA;CACD;CAGA,IAAI,OAAO,KAAK,KAAK,gBAAgB,YAAY,KAAK,KAAK,YAAY,SAAS,GAAG;;EAElF,IAAIA,QAAM,SACT,UAAU,KAAK,4BAA4B,KAAK,KAAK,YAAY,GAAG;;EAIrE,IAAI,IAAI,gBAAgB,KAAK,KAAK,WAAW;CAC9C;CAGA,IAAI,OAAO,KAAK,KAAK,eAAe,UAAU;;EAE7C,IAAIA,QAAM,SAAS;GAClB,UAAU,KAAK,0CAA0C,KAAK,KAAK,qBAAqB,GAAG,GAAG;GAC9F,QAAM,SAAS,YAAY,UAAU,KAAK,IAAI,CAAC,CAAC;EACjD;;EAGA,IAAI,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,KAAK,KAAK,KAAK,iBAAiB;EACjE;CACD;;CAIA,IAAIA,QAAM,SAAS;EAClB,IAAI,KAAK,gBAAgB,OAAO,UAC/B,UAAU,KAAK,GAAG,IAAI,OAAO,EAAE,EAAE,gBAAgB;OAEjD,UAAU,KAAK,GAAG,IAAI,OAAO,EAAE,EAAE,IAAI,KAAK,MAAM;EAEjD,QAAM,SAAS,YAAY,UAAU,KAAK,IAAI,CAAC,CAAC;CACjD;;CAGA,IAAI,KAAK,gBAAgB,OAAO,UAC/B,MAAM,uBAAuB,KAAK,MAAM,GAAG;MAE3C,IAAI,KAAK,KAAK,IAAI;AAEpB;;;ACpNA,IAAa,iBAAb,MAAa,uBAAuB,MAAM;CACzC;CACA;CACA;CACA;;;;;;;CAQA,YAAY,SAAiB,aAA8B,KAAa,MAAsB;EAC7F,MAAM,OAAO;EAGb,IAAI,MAAM,mBACT,MAAM,kBAAkB,MAAM,cAAc;EAI7C,KAAK,4BAAY,IAAI,KAAK;EAC1B,KAAK,cAAc;EACnB,KAAK,MAAM;EACX,KAAK,OAAO;CACb;AACD;;;;;;ACvBA,IAAa,QAAb,MAAsB;CACrB;CACA;CACA;CACA;;;;CAKA,YAAY,UAAkB,wBAAwB;EACrD,KAAK,wBAAQ,IAAI,IAAI;EACrB,KAAK,UAAU;EACf,KAAK,OAAO;EACZ,KAAK,SAAS;CACf;;;;;;CAOA,IAAI,KAA4B;EAC/B,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EAChC,IAAI,OAAO;GACV,MAAM;GACN,KAAK;GACL,OAAO,MAAM;EACd;EACA,KAAK;CAEN;;;;;;CAOA,IAAI,KAAa,OAAgB;EAQhC,IAAI,KAAK,MAAM,QAAQ,KAAK,WAAW,CAAC,KAAK,MAAM,IAAI,GAAG,GACzD,KAAK,MAAM;EAGZ,KAAK,MAAM,IAAI,KAAK;GAAC,UAAU;GAAG;EAAK,CAAC;CACzC;;;;;CAMA,OAAO,KAAmB;EACzB,KAAK,MAAM,OAAO,GAAG;CACtB;;;;CAKA,QAAc;EACb,KAAK,MAAM,MAAM;EACjB,KAAK,OAAO;EACZ,KAAK,SAAS;CACf;;;;;CAMA,QAAc;EAEb,MAAM,UAAU,MAAM,KAAK,KAAK,MAAM,QAAQ,CAAC;EAG/C,QAAQ,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,QAAQ;EAGpD,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,UAAU,mBAAmB,CAAC;EAC9E,MAAM,eAAe,QAAQ,MAAM,GAAG,WAAW,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG;EAErE,KAAK,MAAM,OAAO,cACjB,KAAK,MAAM,OAAO,GAAG;CAEvB;;;;;CAMA,IAAI,OAAe;EAClB,OAAO,KAAK,MAAM;CACnB;;;;;CAMA,OAAiB;EAChB,OAAO,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC;CACpC;;;;;CAMA,WAA0E;EACzE,OAAO;GACN,MAAM,KAAK,MAAM;GACjB,SAAS,KAAK;GACd,MAAM,KAAK;GACX,QAAQ,KAAK;EACd;CACD;AACD;;;AC9HA,MAAMC,UAAQ,YAAY,4BAA4B;AAWtD,MAAM,yBAAyB;CAAC;CAAQ;CAAS;CAAQ;CAAQ;CAAQ;CAAQ;CAAgB;CAAW;AAAQ;AAEpH,MAAM,0BAA0B,IAAI,MAAwB;;;;;;;;;AAU5D,MAAM,uBAAuB,OAAO,UAAkB,oBAAgC,uBAA4D;CAEjJ,MAAM,aAAa,mBAAmB,IAAI,QAAQ;CAClD,IAAI,YAAY;EACf,QAAM,wCAAwC,SAAS,QAAQ,WAAW,EAAE;EAC5E,OAAO;CACR;CAEA,QAAM,yCAAyC,SAAS,sBAAsB;CAE9E,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCZ,MAAM,OAAuB;EAC5B,MAAM;GAAC,KAAK;GAAS,MAAM;GAAQ,KAAK;EAAQ;EAChD,UAAU;GAAC,KAAK;GAAU,MAAM;GAAQ,SAAA;EAAkC;CAC3E;CAEA,IAAI;EACH,MAAM,SAAS,MAAM,mBAAmB,QAAQ,KAAK,IAAI;EACzD,MAAM,EAAC,aAAY,EAAE,aAAa,EAAC,UAAU,EAAE,OAAO,EAAC,CAAC,CAAC,CAAC,MAAM,OAAO,QAAQ;EAE/E,IAAI,CAAC,UACJ,MAAM,IAAI,aAAa,qCAAqC,SAAS,EAAE;EAGxE,QAAM,mCAAmC,SAAS,QAAQ,SAAS,EAAE;EAGrE,mBAAmB,IAAI,UAAU,QAAQ;EAEzC,OAAO;CACR,SAAS,KAAK;;EAEb,QAAM,0CAA0C,SAAS,IAAI,GAAG;;EAIhE,MAAM,IAAI,aAAa,cAAc,SAAS,kCAAkC,cAAc,GAAG,GAAG;CACrG;AACD;;;;;;;;;;AAWA,MAAa,mBAAmB,OAC/B,UACA,oBACA,SACA,uBACqB;CACrB,QAAM,oBAAoB,QAAQ;CAGlC,IAAI,gBAAgB,SAAS,YAAY,CAAC,CAAC,KAAK;CAGhD,gBAAgB,wBAAwB,aAAa;CAGrD,KAAK,MAAM,KAAK,wBACf,IAAI,cAAc,WAAW,CAAC,GAAG;EAChC,MAAM,QAAQ,mBAAmB,SAAS,kCAAkC,uBAAuB,KAAK,GAAG,EAAE;;EAE7G,QAAM,KAAK;;EAGX,MAAM,IAAI,aAAa,KAAK;CAC7B;CAID,IAAI,QAAQ,iBAAiB,QAAQ,cAAc,SAAS,GACtD;OAAA,MAAM,KAAK,QAAQ,eACvB,IAAI,cAAc,WAAW,CAAC,GAAG;GAChC,MAAM,QAAQ,mBAAmB,SAAS,iCAAiC,QAAQ,cAAc,KAAK,GAAG,EAAE;;GAE3G,QAAM,KAAK;;GAGX,MAAM,IAAI,aAAa,KAAK;EAC7B;;CAKF,IAAI,QAAQ,6BAA6B,QAAQ,0BAA0B,SAAS,GAM/E;MAAA,CAAC,MADe,0BAA0B,eAAe,QAAQ,2BAA2B,kBAAkB,GACtG;GACX,MAAM,QAAQ,mBAAmB,SAAS,+DAA+D,QAAQ,0BAA0B;;GAE3I,QAAM,KAAK;;GAGX,MAAM,IAAI,aAAa,KAAK;EAC7B;;CAOD,OAAO,MAFoB,qBAAqB,eAAe,oBAAoB,kBAAkB;AAGtG;;;;;AAMA,MAAM,2BAA2B,QAA2C;CAC3E,IAAI,QAAQ,QAAQ,QAAQ,KAAA,GAC3B,OAAO;CAGR,MAAM,QAAkB,CAAC;CAEzB,KAAK,MAAM,KAAK,KACf,IAAK,KAAK,OAAO,KAAK,OAAS,KAAK,OAAO,KAAK,OAAS,KAAK,OAAO,KAAK,OAAQ,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,KAC9H,MAAM,KAAK,CAAC;CAId,OAAO,MAAM,KAAK,EAAE;AACrB;;;;;;;AAQA,MAAM,mBAAmB,OAAO,UAAkB,2BAAmC,uBAAqD;CACzI,MAAM,OAAuB;EAC5B,MAAM;GAAC,KAAK;GAAS,MAAM;GAAQ,KAAK;EAAQ;EAChD,OAAO;GAAC,KAAK;GAAU,MAAM;EAAM;CACpC;CAEA,MAAM,MAAM;EACX;EACA;EACA;EACA,UAAU,0BAA0B;EACpC;EACA;EACA;EACA;CACD,CAAC,CAAC,KAAK,IAAI;CAEX,IAAI,SAA0B,CAAC;CAC/B,IAAI;EACH,SAAS,MAAM,mBAAmB,QAAQ,KAAK,IAAI;CACpD,SAAS,KAAK;;EAEb,QAAM,UAAU,MAAM;EAItB,MAAM,IAAI,aAAa,yCADkC,SAAS,KAAK,IAAI,IAAI,cAAc,GAAG,GAClE;CAC/B;CAEA,IAAI;EAEH,OADa,EAAE,aAAa,EAAC,OAAO,EAAE,OAAO,EAAC,CAAC,CAAC,CAAC,MAAM,OAAO,QACpD,CAAC,CAAC,UAAU;CACvB,SAAS,KAAK;;EAEb,QAAM,UAAU,OAAO,QAAQ;;EAG/B,MAAM,UAAU,+BAA+B,OAAO,OAAO,QAAQ,EAAE,IAAI,cAAc,GAAG;EAC5F,MAAM,IAAI,MAAM,OAAO;CACxB;AACD;;;;;;;;;AAUA,MAAM,4BAA4B,OAAO,UAAkB,oBAA4B,uBAAqD;CAC3I,QAAM,6BAA6B,UAAU,kBAAkB;CAG/D,MAAM,MAAM,SAAS,YAAY;CAGjC,MAAM,aAAa,wBAAwB,IAAI,GAAG;CAGlD,IAAI,eAAe,KAAA,GAAW;;EAE7B,IAAIA,QAAM,SACT,QAAM,yCAAyC,SAAS,iBAAiB;;EAI1E,OAAO,WAAW;CACnB;;CAIA,IAAIA,QAAM,SACT,QAAM,yCAAyC,SAAS,wCAAwC;;CAIjG,MAAM,QAAQ,MAAM,iBAAiB,UAAU,oBAAoB,kBAAkB;CAGrF,wBAAwB,IAAI,KAAK,EAAC,MAAK,CAAC;CAExC,OAAO;AACR;;;AC5QA,MAAMC,UAAQ,YAAY,wBAAwB;AAElD,IAAa,gBAAb,cAAmC,SAAS;CAC3C;CACA;CACA;;;;CAKA,YAAY,oBAAgC;EAC3C,MAAM,EAAC,eAAe,uBAAsB,CAAC;EAC7C,KAAK,qBAAqB;EAC1B,KAAK,YAAY;EACjB,KAAK,SAAS;CACf;;;;;CAMA,MAAM,aAAgC;EACrC,IAAI,KAAK,QAAQ,OAAO,CAAC;EAEzB,MAAM,gBAAgC;GACrC,OAAO;IAAC,KAAK;IAAU,MAAM;IAAQ,cAAc,KAAK;GAAS;GACjE,OAAO;IAAC,KAAK;IAAY,MAAM;IAAQ,KAAK,KAAK;GAAS;EAC3D;EAEA,MAAM,eAAe;EAErB,IAAI;GACH,MAAM,SAAS,MAAM,KAAK,mBAAmB,QAAQ,cAAc,aAAa;GAChF,MAAM,EAAC,OAAO,UAAS,EAAE,aAAa;IAAC,OAAO,EAAE,OAAO;IAAG,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;GAAC,CAAC,CAAC,CAAC,MAAM,OAAO,QAAQ;GAE5G,QAAM,WAAW,MAAM,OAAO,gBAAgB,MAAM,EAAE;GAGtD,IAAI,MAAM,SAAS,KAAK,WACvB,KAAK,SAAS;GAGf,OAAO;EACR,SAAS,KAAK;GACb,IAAI,eAAe,gBAClB,MAAM;GAEP,MAAM,IAAI,eAAe,2CAA2C,cAAc,GAAG,KAAK,CAAC,GAAG,cAAc,aAAa;EAC1H;CACD;;;;;CAMA,MAAe,OAAqB;EACnC,KAAK,WAAW,CAAC,CACf,MAAM,UAAU;GAChB,IAAI,MAAM,SAAS,GAClB,KAAK,KAAK,MAAM,KAAK,EAAE,CAAC;GAIzB,IAAI,KAAK,QACR,KAAK,KAAK,IAAI;EAEhB,CAAC,CAAC,CACD,OAAO,QAAiB;GACxB,KAAK,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;EACjE,CAAC;CACH;;;;;CAMA,QAAQ,SAAuB;EAC9B,IAAI,WAAW,QAAQ,SAAS,GAC/B,KAAK,KAAK,OAAO;CAEnB;AACD;;;ACtFA,IAAM,eAAN,MAAmB;CAClB,UAAU;CACV,WAAW;CACX,aAAa;;;;;CAMb,WAAW,SAAwB;EAClC,KAAK,UAAU;CAChB;;;;;CAMA,YAAqB;EACpB,OAAO,KAAK;CACb;;;;;CAMA,SAAS,OAAkC;EAC1C,IAAI,CAAC,KAAK,SAAS;EAEnB,IAAI;GACH,MAAM,OAAO,KAAK,UAAU,KAAK,IAAI;GACrC,GAAG,eAAe,KAAK,UAAU,IAAI;EACtC,SAAS,KAAK;GACb,QAAQ,MAAM,qCAAqC,GAAG;EACvD;CACD;;;;CAKA,QAAc;EACb,IAAI;GACH,IAAI,GAAG,WAAW,KAAK,QAAQ,GAC9B,GAAG,aAAa,KAAK,UAAU,CAAC;EAElC,SAAS,KAAK;GACb,QAAQ,MAAM,uCAAuC,GAAG;EACzD;CACD;;;;;CAMA,cAAsB;EACrB,OAAO,KAAK,QAAQ,KAAK,QAAQ;CAClC;AACD;AAEA,MAAa,eAAe,IAAI,aAAa;;;ACzD7C,MAAMC,UAAQ,YAAY,oBAAoB;;;;;;;;;;;;AAkC9C,MAAM,eAAe,OACpB,KACA,UACA,QACA,SACA,oBACA,oBACA,kBACyE;CAEzE,IAAI,QAAQ,WAAW,YAAY,MAAM,SAAS,YAAY,GAAG;;EAEhE,QAAM,6BAA6B,QAAQ,UAAU,kBAAkB,QAAQ,mBAAmB,EAAE;;EAEpG,OAAO;GACN,KAAK,GAAG,QAAQ,mBAAmB;GACnC,MAAM,EACL,QAAQ;IAAC,KAAK;IAAS,MAAM;IAAQ,KAAK;GAAQ,EACnD;EACD;CACD;CAGA,MAAM,uBAAuB,SAAS,WAAW,GAAG;CAIpD,MAAM,oBAAoB,MAAM,iBADhB,uBAAuB,SAAS,MAAM,CAAC,IAAI,UACD,oBAAoB,SAAS,kBAAkB;CAGzG,OAAO,uBACJ;EACA,GAAG,qBAAqB,KAAK,mBAAmB,MAAM;EACtD,cAAc;CACf,IACC;EACA,GAAI,MAAM,kBAAkB,KAAK,mBAAmB,QAAQ,oBAAoB,aAAa;EAC7F,cAAc;CACf;AACH;;;;;;;;;;;AAYA,MAAM,mBAAmB,OAAO,QAAyB,uBAAkD;CAC1G,IAAI,eAAe;CACnB,IAAI;EACH,MAAM,mBAAmB,QAAQ,YAAY;CAC9C,SAAS,KAAK;EACb,MAAM,IAAI,eAAe,qDAAqD,cAAc,GAAG,KAAK,QAAQ,cAAc,CAAC,CAAC;CAC7H;CAMA,eAAe;CACf,MAAM,gBAAgC;EACrC,UAAU;GAAC,KAAK;GAAS,MAAM;GAAQ,KAAK,OAAO,KAAK,MAAM,CAAC,CAAC;EAAM;EACtE,UAAU;GAAC,KAAK;GAAS,MAAM;GAAQ,KAAK,OAAO,KAAK,MAAM;EAAC;EAC/D,WAAW;GAAC,KAAK;GAAS,MAAM;GAAQ,KAAK,OAAO,OAAO,MAAM;EAAC;EAClE,aAAa;GAAC,KAAK;GAAS,MAAM;GAAQ,MAAM,OAAO,eAAe,GAAA,CAAI,MAAM,GAAG,EAAE;EAAC;CACvF;CACA,IAAI;EACH,MAAM,mBAAmB,QAAQ,cAAc,aAAa;CAC7D,SAAS,KAAK;EACb,MAAM,IAAI,eAAe,qDAAqD,cAAc,GAAG,KAAK,QAAQ,cAAc,aAAa;CACxI;AACD;;;;;;;;;;AAWA,MAAM,mBAAmB,OAAO,MAA2C,uBAAkD;CAC5H,MAAM,eAAe,SAAS,KAAK,IAAI;CAEvC,IAAI;EACH,MAAM,mBAAmB,QAAQ,cAAc,KAAK,IAAI;CACzD,SAAS,KAAK;EACb,MAAM,IAAI,eAAe,sDAAsD,aAAa,IAAI,cAAc,GAAG,KAAK,CAAC,GAAG,KAAK,KAAK,KAAK,IAAI;CAC9I;AACD;;;;;;;;AASA,MAAM,yBAAyB,OAC9B,UACA,uBACqF;CACrF,MAAM,gBAAgC;EACrC,UAAU;GAAC,KAAK;GAAU,MAAM;EAAM;EACtC,UAAU;GAAC,KAAK;GAAU,MAAM;EAAM;EACtC,UAAU;GAAC,KAAK;GAAY,MAAM;GAAM,KAAK;EAAQ;CACtD;CAEA,MAAM,eAAe;;;;;;;;;;;;;;;;CAiBrB,IAAI,SAAiC;CACrC,IAAI;EACH,SAAS,MAAM,mBAAmB,QAAQ,cAAc,aAAa;CACtE,SAAS,KAAK;;EAEb,IAAIA,QAAM,SACT,QAAM,SAAS,mCAAmC,QAAQ,MAAM,CAAC,CAAC;;EAInE,MAAM,IAAI,eAAe,yDAAyD,cAAc,GAAG,KAAK,CAAC,GAAG,cAAc,aAAa;CACxI;CAEA,OAAO,EACL,OAAO;EACP,UAAU,EACR,OAAO,CAAC,CACR,SAAS,CAAC,CACV,WAAW,QAAQ,OAAO,EAAE;EAC9B,UAAU,EACR,OAAO,CAAC,CACR,SAAS,CAAC,CACV,WAAW,QAAQ,OAAO,CAAC;EAC7B,UAAU,EAAE,WAAW,OAAO,QAAQ,CAAC,CAAC,SAAS;CAClD,CAAC,CAAC,CACD,MAAM,OAAO,QAAQ;AACxB;;;;;;;;;;;;;;;AAgBA,MAAa,kBAAkB,OAC9B,KACA,KACA,QACA,QACA,eACA,SACA,oBACA,oBACA,kBACmB;CACnB,QAAM,wBAAwB;CAE9B,MAAM,YAAY,KAAK,IAAI;CAC3B,IAAI,YAAwC;CAE5C,IAAI,aAAa,UAAU,GAC1B,YAAY;EACX,IAAI,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE;EAC1C,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EAClC,QAAQ,OAAO,eAAe;EAC9B,KAAK,IAAI;EACT,QAAQ,IAAI;EACZ,QAAQ;EACR,UAAU;EACV,KAAK;EACL,SAAS,IAAI;EACb,SAAS,IAAI;EACb,SAAS,cAAc,KAAK,OAAO;GAClC,cAAc,EAAE;GAChB,UAAU,EAAE;GACZ,MAAM,EAAE;EACT,EAAE;CACH;CAGD,IAAI;EAEH,QAAM,4BAA4B,cAAc,OAAO,QAAQ;EAC/D,IAAI,cAAc,SAAS,GAC1B,IAAI,OAAO,QAAQ,kBAAkB,YAAY,QAAQ,cAAc,SAAS,GAAG;GAClF,MAAM,EAAC,kBAAiB;GAExB,MAAM,QAAQ,IAAI,cAAc,KAAK,SAAS,WAAW,MAAM,eAAe,kBAAkB,CAAC,CAAC;EACnG,OAEC,QAAQ,KAAK,qBAAqB,cAAc,OAAO,4DAA4D;EAMrH,QAAM,6DAA6D;EAEnE,MAAM,cAAc,MAAM,QAAQ,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,IAAI,OAAO;EACrF,IAAI,CAAC,aACJ,MAAM,IAAI,aAAa,4BAA4B;EAEpD,MAAM,OAAO,MAAM,aAAa,KAAK,aAAa,QAAQ,SAAS,oBAAoB,oBAAoB,aAAa;EAExH,IAAI,WAAW;GACd,UAAU,YAAY,KAAK;GAC3B,UAAU,aAAa,KAAK;EAC7B;EAIA,QAAM,sCAAsC;EAC5C,MAAM,iBAAiB,QAAQ,kBAAkB;EAIjD,QAAM,sCAAsC;EAC5C,IAAI;GACH,MAAM,iBAAiB,MAAM,kBAAkB;EAChD,SAAS,KAAK;GAEb,IAAI,eAAe,gBAAgB;IAClC,MAAM,cAAc,IAAI,SAAS;IAEjC,IAAI,YAAY,SAAS,WAAW,KAAK,YAAY,SAAS,WAAW,KAAK,YAAY,SAAS,WAAW,KAAK,YAAY,SAAS,WAAW,GAAG;KACrJ,QAAM,iDAAiD,YAAY,oBAAoB;KAGvF,IAAI,aACH,mBAAmB,OAAO,WAAW;KAItC,IAAI,KAAK,cACR,cAAc,OAAO,KAAK,aAAa,YAAY,CAAC;IAEtD;GACD;GACA,MAAM;EACP;EAGA,QAAM,2DAA2D;EAEjE,MAAM,iBAAiB,IAAI,cAAc,kBAAkB;EAC3D,MAAM,QAAQ,MAAM,eAAe,WAAW;;EAG9C,IAAIA,QAAM,SACT,QAAM,SAAS,QAAQ,MAAM,KAAK,EAAE,CAAC,CAAC;;EAMvC,QAAM,iCAAiC;EACvC,MAAM,WAAW,MAAM,mBAAmB,UAAU,IAAI;EAExD,IAAI;GACH,MAAM,eAAe,MAAM,uBAAuB,UAAU,kBAAkB;;GAE9E,IAAIA,QAAM,SACT,QAAM,SAAS,gBAAgB,QAAQ;IAAC,UAAU,aAAa;IAAU,UAAU,aAAa;GAAQ,CAAC,CAAC,CAAC;;GAM5G,QAAM,iCAAiC;GAEvC,MAAM,iBAAiB,UAAU,MAAM,KAAK,EAAE,CAAC;GAG/C,eAAe,KAAK,SAAS,OAAO,mBAAmB;GAGvD,IAAI,aAAa,aAAa,MAAM,aAAa,WAAW,KAAK,aAAa,aAAa,MAAM;IAChG,eAAe,KAAK,WAAW,aAAa;IAC5C,eAAe,KAAK,WAAW,aAAa;IAC5C,eAAe,KAAK,WAAW,aAAa;IAE5C,IAAI,WACH,UAAU,YAAY;KACrB,UAAU,aAAa;KACvB,UAAU,aAAa;IACxB;GAEF,OAAO;IAGN,IAAI,OAAO,eAAe,SAAS,YAAY,eAAe,KAAK,SAAS,GAC3E,eAAe,QAAQ,eAAe,IAAI;IAG3C,eAAe,OAAO;IAEtB,IAAI,WAAW;KAEd,IAAI,aAAa,OAAO,eAAe,SAAS,WAAW,eAAe,OAAO,MAAM,KAAK,EAAE;KAC9F,MAAM,gBAAgB,OAAO;KAE7B,MAAM,eAAe,eAAe,KAAK,KAAK,cAAc;KAC5D,eAAe,QAAQ,UAAU;MAChC,IAAI,UAAU,QAAQ,WAAW,SAAS,eAAe;OAExD,cADY,OAAO,KACH;OAChB,IAAI,WAAW,SAAS,eACvB,aAAa,WAAW,MAAM,GAAG,KAAK,IAAI,GAAG,aAAa,CAAC,IAAI;MAEjE;MACA,OAAO,aAAa,KAAK;KAC1B;KAIA,MAAM,eAAe;KACrB,eAAe,GAAG,aAAa;MAC9B,aAAa,OAAO;MACpB,aAAa,SAAS;MACtB,aAAa,WAAW,KAAK,IAAI,IAAI;MACrC,aAAa,SAAS,YAAY;KACnC,CAAC;KACD,eAAe,GAAG,UAAU,QAAQ;MACnC,aAAa,SAAS;MACtB,aAAa,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;MACpE,aAAa,WAAW,KAAK,IAAI,IAAI;MACrC,aAAa,SAAS,YAAY;KACnC,CAAC;IACF;GACD;GAIA,QAAM,2CAA2C;GACjD,MAAM,aAAa,KAAK,KAAK,cAAc;GAE3C,IAAI,WAAW,WAAW;IACzB,UAAU,SAAS;IACnB,UAAU,WAAW,KAAK,IAAI,IAAI;IAClC,aAAa,SAAS,SAAS;GAChC;EACD,UAAU;GAGT,QAAM,0BAA0B;GAChC,SAAS,QAAQ;EAClB;CACD,SAAS,KAAK;EACb,IAAI,WAAW;GACd,UAAU,SAAS,eAAe,iBAAiB,UAAU;GAC7D,UAAU,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GACjE,UAAU,WAAW,KAAK,IAAI,IAAI;GAClC,aAAa,SAAS,SAAS;EAChC;EACA,MAAM;CACP;CAEA,QAAM,sBAAsB;AAC7B;;;AClaA,MAAMC,UAAQ,YAAY,cAAc;AAKxC,MAAM,cAA+B;CACpC,eAAe;CACf,kBAAkB;CAClB,iBAAiB;CACjB,mBAAmB;CACnB,aAAa;CACb,aAAa,GAAG,SAAS;CACzB,gBAAgB;CAChB,WAAW;CACX,aAAa;CACb,aAAa;CACb,iBAAiB;CACjB,kBAAkB;CAClB,aAAa;CACb,aAAa;CACb,iBAAiB;CACjB,WAAW;CACX,aAAa;CACb,sBAAsB;CACtB,sBAAsB;CACtB,cAAc;CACd,sBAAsB;CACtB,oBAAoB;CACpB,UAAU;CACV,iBAAiB;CACjB,gBAAgB;CAChB,YAAY;CAEZ,iBAAiB;CAEjB,sBAAsB;CACtB,eAAe;AAChB;;;;;;;AAQA,MAAM,mBAAmB,QAAyB;CACjD,IAAI,eAAe;CAEnB,KAAK,MAAM,YAAY,IAAI,SAC1B,gBAAgB,GAAG,SAAS,GAAG,IAAI,QAAQ,UAAU;CAGtD,QAAM,mBAAmB,IAAI,SAAS,YAAY;CAElD,OAAO;AACR;;;;;;;AAQA,MAAM,WAAW,QAAgE;CAKhF,MAAM,WAAW,IAAIC,MAAI,GAHL,IAAI,SAAS,KAAK,GAAG,SAAS,IAAI,IAAI,aAGzB,CAAC,CAAC;CAEnC,MAAM,MAAM,SAAS,SAAS,MAAM,GAAG,KAAK,IAAI,GAAG,SAAS,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC;CAKlF,OAAO;EAAC,QAAA,IAJW;EAIH,QAAA,IAHG,IAAI,MAAM,GAAG,KAAK,IAAI,GAAG,IAAI,YAAY,GAAG,CAAC,CAAC;EAGzC,KAFZ,IAAI,MAAM,KAAK,IAAI,GAAG,IAAI,QAAQ,GAAG,IAAI,CAAC,CAE5B;CAAC;AAC5B;;;;;;;AAQA,MAAM,YAAY,UAA0B,MAAM,WAAW,eAAe,EAAE;;;;;;;;;;AAW9E,MAAa,UAAU,KAAc,UAAkB,KAAsB,oBAAmC,SAA0B;CACzI,MAAM,WAAW,IAAI,WAAW,IAAI,SAAS,YAAY,IAAI;CAC7D,MAAM,OAAO,QAAQ,GAAG;CAExB,MAAM,MAAuB;EAC5B,aAAa,OAAO,IAAI,OAAO,cAAc,WAAW,IAAI,OAAO,UAAU,SAAS,IAAI;EAC1F,gBAAgB,IAAI;EACpB,WAAW,MAAM,QAAQ,IAAI,OAAO,IAAI,IAAK,IAAI,OAAO,KAAK,MAAM,KAAO,IAAI,OAAO,QAAQ;EAC7F,aAAa,KAAK;EAClB,cAAc,IAAI,MAAM,GAAA,CAAI,QAAQ,WAAW,EAAE;EACjD,iBAAiB,GAAG,SAAS,GAAG,IAAI;EACpC,kBAAkB;EAClB,aAAa,qBAAqB;EAClC,WAAW,oBAAoB,UAAU;EACzC,aAAa,gBAAgB,GAAG;EAChC,iBAAiB,IAAI,IAAI,YAAY,KAAK;EAC1C,WAAW,IAAI,IAAI,MAAM,KAAK;EAC9B,aAAa,IAAI,IAAI,QAAQ,KAAK;EAClC,sBAAsB,IAAI,IAAI,iBAAiB,KAAK;EACpD,sBAAsB,IAAI,IAAI,iBAAiB,KAAK;EACpD,cAAc,IAAI,IAAI,SAAS,KAAK;EACpC,sBAAsB,IAAI,IAAI,iBAAiB,KAAK;EACpD,UAAU,KAAK;EACf,gBAAgB;EAChB,eAAe,KAAK;CACrB;CAEA,OAAO,OAAO,OAAO,CAAC,GAAG,aAAa,KAAK,GAAG;AAC/C;;;;;;;;AC7HA,MAAa,2BAA2B,UACvC,OAAO,UAAU,YAAa,MAAM,QAAQ,KAAK,KAAK,MAAM,OAAO,YAAY,OAAO,YAAY,QAAQ;;;ACD3G,MAAMC,UAAQ,YAAY,kBAAkB;;;;;;AAiB5C,MAAM,iBAAiB,QAAoD;CAC1E,MAAM,OAA0C,CAAC;;CAGjD,IAAI,OAAO,IAAI,SAAS,YAAY,IAAI,SAAS,MAAM;EACtD,MAAM,OAAO,IAAI;EACjB,KAAK,MAAM,OAAO,MAAM;GACvB,MAAM,QAAQ,KAAK;;GAEnB,IAAI,wBAAwB,KAAK,GAChC,KAAK,OAAO;;;GAGZ,MAAM,IAAI,aACT,gBAAgB,IAAI,yDAAyD,KAAK,QAAQ,IAAI,MAAM;IAAC,YAAY;IAAO,OAAO;IAAM,QAAQ;GAAK,CAAC,GACpJ;EAEF;CACD;CAEA,OAAO;AACR;;;;;;;;;;;;;AAcA,MAAa,iBAAiB,OAC7B,KACA,KACA,SACA,gBACA,oBACA,eACA,oBAAmC,SAChB;CACnB,QAAM,uBAAuB;CAE7B,IAAI,OAAO,IAAI,OAAO,SAAS,UAE9B,QAAQ,KAAK,wFAAwF,IAAI,OAAO,MAAM;CAIvH,MAAM,aAAa,MAAM,eAAe,cAAc;CAEtD,IAAI;EAEH,MAAM,SAAS,OAAO,KAAK,QAAQ,eAAe,QAAQ,OAAO,CAAC,GAAG,iBAAiB;EACtF,QAAM,2BAA2B,MAAM;EAGvC,MAAM,gBAAgB,SAAS,GAAG;EAClC,QAAM,kCAAkC,aAAa;EAGrD,MAAM,SAAqB,CAAC;EAE5B,OAAO,OAAO,QAAQ,IAAI,KAAY;EAGtC,cAAc,QAAQ,YAAY,SAAS;GAC1C,WAAW,KAAK,aAAa,KAAK;GAClC,OAAO;EACR,GAAG,MAAM;EAGT,OAAO,OAAO,QAAQ,cAAc,GAAG,CAAC;EACxC,QAAM,2BAA2B,MAAM;EAGvC,MAAM,gBAAgB,KAAK,KAAK,QAAQ,QAAQ,eAAe,SAAS,YAAY,oBAAoB,aAAa;EAGrH,IAAI,QAAQ,oBAAoB,YAAY;GAC3C,QAAM,2BAA2B;GACjC,MAAM,WAAW,SAAS;EAC3B,OAAO,IAAI,OAAO,QAAQ,oBAAoB,YAAY;GACzD,QAAM,2BAA2B;GACjC,MAAM,WAAW,MAAM,QAAQ,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,IAAI,OAAO;GAClF,MAAM,SAAS,QAAQ,gBAAgB,YAAY,YAAY,EAAE;GACjE,QAAM,qCAAqC,MAAM;GACjD,IAAI,UAAU,OAAO,OAAO,SAAS,YACpC,MAAM;EAER,OAAO;GACN,QAAM,yBAAyB;GAC/B,MAAM,WAAW,OAAO;EACzB;CACD,UAAU;EAET,MAAM,WAAW,QAAQ;CAC1B;CAEA,QAAM,sBAAsB;AAC7B;;;ACxHA,IAAa,aAAb,MAAwB;CACvB;CAEA,YAAY,WAAW,kBAAkB;EACxC,KAAK,SAAS,mBAAmB,aAAa,UAAU;GACvD,MAAA;GACA,UAAA;GACA,UAAA;GACA,UAAU;EACX,CAAC;CACF;;;;;CAMA,IAAI,OAAsD;EACzD,IAAI;GAEH,MAAM,+BAAc,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,MAAM,OAAO,KAAK,UAAU,KAAK;GACjC,KAAK,OAAO,MAAM,OAAO,IAAI;EAC9B,SAAS,KAAK;GACb,QAAQ,MAAM,mCAAmC,GAAG;EACrD;CACD;;;;CAKA,QAAc;EACb,KAAK,OAAO,IAAI;CACjB;AACD;AAEA,MAAa,aAAa,IAAI,WAAW;;;;;;;;;ACpBzC,MAAM,gBAAgB,KAAc,UAAgC;CACnE,IAAI,4BAAY,IAAI,KAAK;CACzB,IAAI,UAAU;CACd,IAAI,cAAkD;CACtD,IAAI,MAAiC;CACrC,IAAI,OAA0C;CAG9C,IAAI,iBAAiB,gBAAgB;EACpC,YAAY,MAAM;EAClB,UAAU,MAAM,SAAS;EACzB,cAAc,MAAM;EACpB,MAAM,MAAM;EACZ,OAAO,MAAM;CACd,OAAO,IAAI,iBAAiB,cAAc;EACzC,YAAY,MAAM;EAClB,UAAU,MAAM,SAAS;CAC1B,OAAO,IAAI,iBAAiB,OAC3B,UAAU,cAAc,KAAK;MAE7B,IAAI,OAAO,UAAU,UACpB,UAAU,GAAG,MAAM;CAYrB,OAAO;EAAC,MAAM;EAAS;EAAW;EAAS;EAAK;EAAa;EAAK;CAAI;AACvE;;;;;;;;;AAUA,MAAa,aAAa,KAAc,KAAe,SAAiC,UAAyB;CAEhH,MAAM,YAAY,aAAa,KAAK,KAAK;CAGzC,MAAM,EAAC,MAAM,SAAQ,oBAAoB,SAAS;CAGlD,UAAU,IAAI;CAGd,MAAM,YAAY,UAAU,QAAQ,MAAM,IAAI,CAAC,CAAC;CAChD,WAAW,IAAI;EACd,WAAW,UAAU,WAAW,YAAY,sBAAK,IAAI,KAAK,EAAA,CAAE,YAAY;EACxE,MAAM;EACN,SAAS,aAAa;EACtB,KAAK;GACJ,QAAQ,IAAI;GACZ,KAAK,IAAI;GACT,IAAI,IAAI,MAAM;GACd,WAAW,IAAI,IAAI,YAAY,KAAK;EACrC;EACA,SAAS;GACR,aAAa,UAAU;GACvB,KAAK,UAAU,OAAO;GACtB,MAAM,UAAU;GAChB,aAAa,UAAU,eAAe,CAAC;EACxC;CACD,CAAC;CAGD,QAAQ,MAAM,IAAI;CAGlB,IAAI,IAAI,aAAa;EACpB,QAAQ,KAAK,mEAAmE;EAChF;CACD;CAGA,IAAI,QAAQ,eAAe,SAC1B,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,gBAAgB;MAErC,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC;AAExC;;;ACxGA,MAAMC,UAAQ,YAAY,uBAAuB;;;;;;;;;;;AA0BjD,MAAM,iBAAiB,OACtB,KACA,KACA,OACA,gBACA,SACA,oBACA,kBACmB;CACnB,IAAI;EACH,IAAI,oBAAmC;EAGvC,IAAI,QAAQ,MAAM,SAAS,SAAS;GACnC,MAAM,WAAW,IAAI,QAAQ,iBAAiB,GAAA,CAAI,MAAM,GAAG,CAAC,CAAC,MAAM;GACnE,MAAM,CAAC,OAAO,YAAY,OAAO,KAAK,SAAS,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG;GAE7E,IAAI,OACH,oBAAoB,MAAM,QAAQ,KAAK,SAAS;IAAC,UAAU;IAAO;GAAQ,GAAG,cAAc;GAG5F,IAAI,sBAAsB,MAAM;IAC/B,MAAM,QAAQ,QAAQ,KAAK,SAAS;IACpC,IAAI,IAAI,oBAAoB,gBAAgB,MAAM,EAAE;IACpD,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,0BAA0B;IAC/C;GACD;EACD,OAAO,IAAI,QAAQ,MAAM,SAAS,UAAU;GAC3C,oBAAoB,MAAM,QAAQ,KAAK,SAAS,KAAK,cAAc;GAEnE,IAAI,sBAAsB,MAAM;IAC/B,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,0BAA0B;IAC/C;GACD;EACD;EAGA,IAAI,OAAO,IAAI,OAAO,SAAS,YAAY,IAAI,OAAO,KAAK,WAAW,GACrE,IAAI,OAAO,QAAQ,gBAAgB,YAAY,QAAQ,YAAY,SAAS,GAAG;GAC9E,MAAM,aAAa,IAAI,IAAI,IAAI,aAAa,kBAAkB;GAG9D,MAAM,SAAS,GAFE,WAAW,SAAS,SAAS,GAAG,IAAI,WAAW,WAAW,GAAG,WAAW,SAAS,KAC9E,QAAQ,YAAY,QAAQ,SAAS,EAClB,IAAI,WAAW;GACtD,QAAM,wBAAwB,OAAO,EAAE;GACvC,IAAI,SAAS,MAAM;EACpB,OACC,UAAU,KAAK,KAAK,SAAS,IAAI,aAAa,gEAAgE,CAAC;OAIhH,MAAM,eAAe,KAAK,KAAK,SAAS,gBAAgB,oBAAoB,eAAe,iBAAiB;CAE9G,SAAS,KAAK;EACb,UAAU,KAAK,KAAK,SAAS,GAAG;CACjC;AACD;;;;;;;;;AAUA,MAAa,mBACZ,gBACA,QACA,iBACkG;CAClG,QAAM,WAAW,MAAM;CAEvB,MAAM,qBAAqB,IAAI,MAAc;CAC7C,MAAM,gBAAgB,IAAI,MAAgB;CAG1C,IAAI,cACH,aAAa,gBAAgB,OAAO,OAAO,gBAAgB,oBAAoB,aAAa;;;;;;CAQ7F,MAAM,YAAY,KAAc,KAAe,SAAuB;EACrE,eAAoB,KAAK,KAAK,MAAM,gBAAgB,QAAQ,oBAAoB,aAAa;CAC9F;CAEA,QAAQ,qBAAqB;CAC7B,QAAQ,gBAAgB;CAExB,OAAO;AACR;;;AC3HA,MAAM,QAAQ,YAAY,wBAAwB;;;;;;AAYlD,MAAa,iBAAiB,aAAqC;CAClE,MAAM,UAAU;CAEhB,OAAO,OAAO,YAAY,EAAC,QAAQ,GAAG,kBAAkB,KAAK,KAAK,QAAQ,IAAI,GAAG,QAAQ,GAAG,EAAC,OAAO,IAAG,CAAC,EAAC,CAAC;AAC3G;;;;;;;;ACTA,MAAa,iBAAiB,wBAAiD;CAQ9E,OAPe,OAAO;EACrB,SAAS,OAAO,YAAY,CAAC,CAAC;EAC9B,QAAQ,EACP,UAAU,oBACX;CACD,CAEY,CAAC,CAAC,IAAI;AACnB;;;ACLA,MAAM,gBAAgB,WAAW;;;;;;;;AASjC,MAAM,gBAAgB,OAAO,UAAkB,IAAI,KAAK,SAAS,OAA0B;CAC1F,IAAI,CAAC,GAAG,WAAW,QAAQ,GAC1B,OAAO,CAAC;CAGT,MAAM,aAAa,GAAG,iBAAiB,QAAQ;CAC/C,MAAM,KAAK,SAAS,gBAAgB;EACnC,OAAO;EACP,WAAW;CACZ,CAAC;CAED,MAAM,cAAc,OAAO,YAAY;CAEvC,MAAM,QAAkB,CAAC;CACzB,WAAW,MAAM,QAAQ,IACxB,IAAI,CAAC,UAAU,KAAK,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG;EACxD,MAAM,KAAK,IAAI;EACf,IAAI,MAAM,SAAS,GAClB,MAAM,MAAM;CAEd;CAED,OAAO;AACR;;;;;;AAOA,MAAa,qBAAqB,iBAAuC;CACxE,MAAM,SAAS,QAAQ,OAAO;CAG9B,OAAO,IAAI,gBAAgB,KAAc,QAAkB;EAC1D,MAAM,UAAU,KAAK,IAAI,IAAI,aAAa,UAAU,QAAQ,KAAK;EACjE,MAAM,iBAAiB,IAAI,MAAM,YAAY;EAC7C,MAAM,gBAAgB,IAAI,MAAM,WAAW;EAE3C,MAAM,YAAY,aAAa,MAAM,KAAK,MAAM,UAAU;GACzD,MAAM,QAAQ,aAAa,OAAO;GAClC,MAAM,OAAO,OAAO,YAAY,QAAQ;GACxC,MAAM,IAAI;GACV,MAAM,QAAQ,OAAO,EAAE,kBAAkB,aAAa,EAAE,cAAc,IAAI;GAC1E,MAAM,YAAY,OAAO,oBAAoB,SAAS;GACtD,MAAM,WAAW,OAAO,eAAe,SAAS;GAEhD,OAAO;IACN;IACA;IACA,iBAAiB,KAAK;IACtB,kBAAkB,KAAK;IACvB,OAAO;KACN,eAAe;MACd,MAAM,OAAO,oBAAoB,KAAK,CAAC,CAAC,UAAU;MAClD,MAAM,WAAW,QAAQ;MACzB,QAAQ,WAAW,UAAU;KAC9B;KACA,UAAU;MACT,MAAM,OAAO,eAAe,KAAK,CAAC,CAAC,UAAU;MAC7C,MAAM,UAAU,QAAQ;MACxB,QAAQ,UAAU,UAAU;KAC7B;IACD;GACD;EACD,CAAC;EAED,MAAM,WAAW,QAAQ,YAAY;EACrC,MAAM,mBAAmB,GAAG,SAAS,IAAI,GAAG,QAAQ;EACpD,MAAM,WAAW,QAAQ,SAAS;EAClC,MAAM,UAAU,aAAa,aAAa,WAAW;EAErD,MAAM,UAAU,aAAa,aAAa,WAAW;EAErD,MAAM,cAAc,iBAAiB,UAAU,QAAQ,MAAM,EAAE;EAE/D,IAAI,KAAK;GACR,SAAS,QAAQ;GACjB,QAAQ,aAAa,SAAS,WAAW;GACzC;GACA,WAAW,aAAa;GACxB,YAAY,aAAa,aAAa,OAAO;GAC7C,SAAS;IACR,cAAc,QAAQ;IACtB,YAAY,QAAQ;IACpB,iBAAiB,QAAQ;IACzB,iBAAiB,QAAQ;IACzB,iBAAiB,QAAQ;IACzB,sBAAsB,QAAQ;GAC/B;GACA,SAAS;GACT,OAAO;GACP,QAAQ;IACP,aAAa,QAAQ;IACrB,UAAU,QAAQ;IAClB,MAAM,QAAQ;IACd,UAAU,GAAG,KAAK,CAAC,CAAC;IACpB,QAAQ;KACP,KAAK;KACL,WAAW,SAAS;KACpB,UAAU,SAAS;KACnB,UAAU,SAAS;KACnB,aAAa,GAAG,SAAS;KACzB,GAAG,QAAQ;IACZ;IACA,KAAK;KACJ,MAAM,SAAS;KACf,QAAQ,SAAS;KACjB,KAAK,QAAQ,IAAI;KACjB,SAAS,QAAQ,IAAI;KACrB,WAAW,QAAQ,IAAI;IACxB;GACD;GACA,QACC,iBAAiB,aAAa,SAC3B;IACA,GAAG,aAAa;IAChB,eAAe,aAAa,OAAO,gBAAgB,aAAa,KAAA;IAChE,YAAY,aAAa,OAAO,WAAW,KAAK,MAAM;KACrD,MAAM,EAAC,MAAM,iBAAiB,KAAK,GAAG,SAAQ;KAC9C,OAAO;MACN,GAAG;MACH,UAAU;MACV,SAAS,CAAC,CAAC;MACX,oBAAoB,CAAC,CAAC;MACtB,QAAQ,CAAC,CAAC;KACX;IACD,CAAC;GACF,IACC,KAAA;EACL,CAAC;CACF,CAAC;CAGD,OAAO,IAAI,uBAAuB,KAAc,QAAkB;EACjE,MAAM,aAAa,IAAI,MAAM;EAC7B,IAAI,QAAQ;EACZ,IAAI,OAAO,eAAe,UAAU;GACnC,MAAM,SAAS,OAAO,UAAU;GAChC,IAAI,CAAC,OAAO,MAAM,MAAM,GACvB,QAAQ;EAEV;EAEA,MAAM,UAAU,aAAa,aAAa,WAAW;EAGrD,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,CAAC,KAAK,IAAI,CAAC,GAAG,OAAO;EAC7D,IAAI,KAAK,MAAM,WAAW,CAAC;CAC5B,CAAC;CAGD,OAAO,IAAI,mBAAmB,OAAO,KAAc,QAAkB;EACpE,IAAI;GACH,MAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,KAAK;GACzC,MAAM,SAAS,OAAO,IAAI,MAAM,WAAW,WAAW,IAAI,MAAM,SAAS;GAGzE,MAAM,eAAc,MADA,cAAc,kBAAS,OAAO,MAAM,EAAA,CAEtD,KAAK,SAAS;IACd,IAAI;KACH,OAAO,KAAK,MAAM,IAAI;IACvB,QAAQ;KACP,OAAO;IACR;GACD,CAAC,CAAC,CACD,QAAQ,MAAoB,MAAM,IAAI;GAExC,MAAM,OADSC,IAAE,MAAM,cACL,CAAC,CAAC,UAAU,WAAW;GACzC,IAAI,CAAC,KAAK,SAET,MAAM,IAAI,MAAM,sBAAsB,KAAK,MAAM,SAAS;GAG3D,OAAO,IAAI,KAAK,KAAK,KAAK,WAAW,CAAC;EACvC,SAAS,KAAK;GACb,OAAO,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,EAAC,OAAO,OAAO,GAAG,EAAC,CAAC;EACjD;CACD,CAAC;CAGD,OAAO,IAAI,oBAAoB,OAAO,KAAc,QAAkB;EACrE,IAAI;GACH,MAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,KAAK;GACzC,MAAM,SAAS,OAAO,IAAI,MAAM,WAAW,WAAW,IAAI,MAAM,SAAS;GACzE,MAAM,UAAU,aAAa,QAAQ,kBAAkB;GAEvD,IAAI,CAAC,aAAa,QAAQ,gBAAgB;IACzC,IAAI,KAAK,EAAC,SAAS,6BAA4B,CAAC;IAChD;GACD;GAEA,MAAM,QAAQ,MAAM,cAAc,SAAS,OAAO,MAAM;GACxD,IAAI,KAAK,MAAM,WAAW,CAAC;EAC5B,SAAS,KAAK;GACb,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,EAAC,OAAO,OAAO,GAAG,EAAC,CAAC;EAC1C;CACD,CAAC;CAGD,OAAO,KAAK,qBAAqB,KAAc,QAAkB;EAChE,MAAM,OAAO,IAAI;EACjB,MAAM,WAAW,OAAO,MAAM,aAAa,WAAW,KAAK,WAAW,KAAA;EAEtE,IAAI,UAAU;EACd,aAAa,OAAO,SAAS,MAAM;GAClC,IAAI,CAAC,YAAY,EAAE,aAAa,UAAU;IACzC,EAAE,mBAAmB,MAAM;IAC3B;IACA,EAAE,cAAc,MAAM;IACtB;GACD;EACD,CAAC;EAED,IAAI,KAAK,EAAC,SAAS,WAAW,QAAQ,SAAQ,CAAC;CAChD,CAAC;CAGD,OAAO,KAAK,wBAAwB,KAAc,QAAkB;EAGnE,QAFe,IAAI,OAAO,QAE1B;GACC,KAAK;IACJ,IAAI,KAAK,EAAC,SAAS,0BAAyB,CAAC;IAC7C,iBAAiB;KAChB,cAAc;IACf,GAAA,GAA0B;IAE1B;GAED,KAAK;IACJ,aAAa,UAAU,IAAI;IAC3B,IAAI,KAAK;KAAC,SAAS;KAAiB,QAAQ;IAAQ,CAAC;IAErD;GAED,KAAK;IACJ,aAAa,UAAU,KAAK;IAC5B,IAAI,KAAK;KAAC,SAAS;KAAkB,QAAQ;IAAS,CAAC;IAEvD;GAED,SACC,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,EAAC,OAAO,iBAAgB,CAAC;EAEhD;CACD,CAAC;CAGD,OAAO,IAAI,sBAAsB,MAAe,QAAkB;EACjE,IAAI,KAAK,EAAC,SAAS,aAAa,UAAU,EAAC,CAAC;CAC7C,CAAC;CAGD,OAAO,KAAK,sBAAsB,KAAc,QAAkB;EACjE,MAAM,OAAO,IAAI;EACjB,MAAM,UAAU,OAAO,MAAM,YAAY,YAAY,KAAK,UAAU;EACpE,aAAa,WAAW,OAAO;EAC/B,IAAI,KAAK,EAAC,SAAS,aAAa,UAAU,EAAC,CAAC;CAC7C,CAAC;CAGD,OAAO,IAAI,mBAAmB,OAAO,KAAc,QAAkB;EACpE,IAAI;GACH,MAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,KAAK;GACzC,MAAM,SAAS,OAAO,IAAI,MAAM,WAAW,WAAW,IAAI,MAAM,SAAS;GACzE,MAAM,UAAU,aAAa,YAAY;GAEzC,MAAM,eAAc,MADA,cAAc,SAAS,OAAO,MAAM,EAAA,CAEtD,KAAK,SAAS;IACd,IAAI;KACH,OAAO,KAAK,MAAM,IAAI;IACvB,QAAQ;KACP,OAAO;IACR;GACD,CAAC,CAAC,CACD,QAAQ,MAAoB,MAAM,IAAI;GAExC,MAAM,OADSA,IAAE,MAAM,yBACL,CAAC,CAAC,UAAU,WAAW;GACzC,IAAI,CAAC,KAAK,SAET,MAAM,IAAI,MAAM,sBAAsB,KAAK,MAAM,SAAS;GAG3D,OAAO,IAAI,KAAK,KAAK,KAAK,WAAW,CAAC;EACvC,SAAS,KAAK;GACb,OAAO,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,EAAC,OAAO,OAAO,GAAG,EAAC,CAAC;EACjD;CACD,CAAC;CAGD,OAAO,KAAK,qBAAqB,MAAe,QAAkB;EACjE,aAAa,MAAM;EACnB,IAAI,KAAK,EAAC,SAAS,iBAAgB,CAAC;CACrC,CAAC;CAED,OAAO;AACR;;;;;;;;;AChTA,MAAa,8BAAsC;CAGlD,IAAI,cAFc,OAAO,KAAK;CAG9B,OAAO,CAAC,WAAW,KAAK,KAAK,aAAa,cAAc,CAAC,KAAK,gBAAgB,KAC7E,cAAc,KAAK,QAAQ,WAAW;CAGvC,IAAI,gBAAgB,KACnB,MAAM,IAAI,MAAM,sGAAsG;CAGvH,OAAO,KAAK,KAAK,aAAa,QAAQ,UAAU;AACjD;;;;;;;AAqBA,MAAa,uBAAuB,QAA4B,iBAA+C;CAC9G,MAAM,aAAa,OAAO,cAAc;CACxC,MAAM,oBAAoB,OAAO,aAAa,sBAAsB;CAGpE,IAAI,cAAc,CAAC,WAAW,WAAW,GAAG,GAC3C,MAAM,IAAI,MAAM,8BAA8B;CAG/C,IAAI,CAAC,OAAO,WAAW,CAAC,WAAW,iBAAiB,GACnD,MAAM,IAAI,MAAM,2EAA2E,mBAAmB;CAI/G,MAAM,eAAe,aAAa;CAElC,MAAM,gBAAgB,aAAa;CACnC,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,eAAe,YAAY,GAAG;EAEvE,MAAM,iBAAiB,aAAa;EACpC,MAAM,iBAAiB,gBAAgC,CAAC,MAAM;GA0B7D,MAAM,kBAAkC,CAAC,GAzBA,aAAa,MAAM,KAAK,MAAM,UAAU;IAChF,MAAM,QAAQ,aAAa,OAAO;IAClC,MAAM,OAAO,OAAO,YAAY,QAAQ;IACxC,MAAM,YAAY,OAAO,oBAAoB,SAAS;IACtD,MAAM,WAAW,OAAO,eAAe,SAAS;IAEhD,OAAO;KACN;KACA,iBAAiB,KAAK;KACtB,kBAAkB,KAAK;KACvB,OAAO;MACN,eAAe;OACd,MAAM,OAAO,oBAAoB,KAAK,CAAC,CAAC,UAAU;OAClD,MAAM,WAAW,QAAQ;OACzB,QAAQ,WAAW,UAAU;MAC9B;MACA,UAAU;OACT,MAAM,OAAO,eAAe,KAAK,CAAC,CAAC,UAAU;OAC7C,MAAM,UAAU,QAAQ;OACxB,QAAQ,UAAU,UAAU;MAC7B;KACD;IACD;GACD,CAE2D,CAAC;GAC5D,IAAI,MAAM,QAAQ,aAAa,GACzB;SAAA,MAAM,MAAM,eAChB,IAAI,CAAC,gBAAgB,MAAM,MAAM,EAAE,SAAS,GAAG,IAAI,GAClD,gBAAgB,KAAK,EAAE;GAAA;GAI1B,eAAe,KAAK,cAAc,eAAe;EAClD;EACA,OAAO,eAAe,eAAe,cAAc;GAAC,OAAO;GAAM,UAAU;EAAK,CAAC;EACjF,aAAa,eAAe;CAC7B;CAEA,MAAM,SAAS,OAAO;CAGtB,OAAO,KAAK,KAAc,KAAe,SAAuB;EAC/D,IAAI,aAAa,UAAU,CAAC,IAAI,KAAK,WAAW,UAAU,GAAG;GAC5D,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,eAAe;GACpC;EACD;EACA,KAAK;CACN,CAAC;CAGD,OAAO,IAAI,aAAa,KAAc,KAAe,SAAuB;EAE3E,MAAM,UAAU,IAAI,WAAW;EAC/B,MAAM,CAAC,QAAQ,IAAI,YAAY,MAAM,GAAG;EAExC,IAAI,SAAS,SAAS;GACrB,MAAM,QAAQ,IAAI,YAAY,MAAM,GAAG,CAAC,CAAC;GACzC,OAAO,IAAI,SAAS,UAAU,OAAO,QAAQ,MAAM,QAAQ,GAAG;EAC/D;EACA,KAAK;CACN,CAAC;CAGD,IAAI,OAAO,QAAQ,OAAO,UACzB,OAAO,IAAI,aAAa,KAAc,KAAe,SAAuB;EAC3E,MAAM,WAAW,IAAI,QAAQ,iBAAiB,GAAA,CAAI,MAAM,GAAG,CAAC,CAAC,MAAM;EACnE,MAAM,CAAC,OAAO,YAAY,OAAO,KAAK,SAAS,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG;EAE7E,IAAI,UAAU,OAAO,QAAQ,aAAa,OAAO,UAAU;GAC1D,IAAI,IAAI,oBAAoB,+BAA6B;GACzD,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,0BAA0B;GAC/C;EACD;EACA,KAAK;CACN,CAAC;CAIF,OAAO,IAAI,YAAY,kBAAkB,YAAY,CAAC;CAGtD,IAAI,WAAW,iBAAiB,GAC/B,OAAO,IACN,YACA,kBAAkB,mBAAmB;EACpC,cAAc;EACd,iBAAiB,CAAC,IAAI;CACvB,CAAC,CACF;CAGD,OAAO;AACR;;;;;;;;;;;;;;;;;;;;;;;;AC1IA,MAAa,qBAAqB,eAAuB,WAAmC;CAC3F,MAAM,YAAY,KAAK,KAAK,eAAe,YAAY;CAEvD,QAAQ,KAAc,KAAe,SAA6B;EAEjE,IAAI,IAAI,WAAW,SAAS,IAAI,WAAW,QAC1C,OAAO,KAAK;EAIb,MAAM,SAAS,IAAI,QAAQ,UAAU;EAIrC,IAAI,UAAU,CAAC,OAAO,SAAS,WAAW,KAAK,CAAC,OAAO,SAAS,KAAK,GACpE,OAAO,KAAK;EAIb,IAAI,SAAS,YAAY,QAAQ;GAChC,IAAI,KAEH,KAAK,GAAG;EAEV,CAAC;CACF;AACD;;;AC9CA,MAAM,IAAI;CACT,KAAK,MAAM,QAAQ,GAAG;CACtB,MAAM,MAAM;CACZ,SAAS,MAAM;CACf,OAAO,MAAM;AACd;;;;;;;AAQA,MAAa,cAAc,SAAiB,SAAwC;CACnF,MAAM,sBAAK,IAAI,KAAK,EAAA,CAClB,YAAY,CAAC,CACb,QAAQ,KAAK,GAAG,CAAC,CACjB,QAAQ,gBAAgB,SAAS;CAEnC,MAAM,MAAM,EAAE,QAAQ,IAAI,OAAO,EAAE,CAAC;CACpC,MAAM,SAAS,GAAG,EAAE,IAAI,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE;CACnD,MAAM,OAAO,EAAE,MAAM,OAAO;CAE5B,MAAM,cAAsC;EAC3C,KAAK,OAAOC,UAAQ,GAAG;EACvB,MAAMA,UAAQ;EACd,GAAG;CACJ;CAEA,MAAM,SAAS,OAAO,QAAQ,WAAW,CAAC,CACxC,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAC/C,KAAK,IAAI;CAEX,QAAQ,MAAM;EAAC;EAAK;EAAQ;EAAM;EAAK;CAAM,CAAC,CAAC,KAAK,IAAI,CAAC;AAC1D;;;;;;;;ACxBA,MAAa,YAAY,UAAyB;CACjD,IAAI,UAAU;CAGd,IAAI,iBAAiB,OACpB,UAAU,cAAc,KAAK;MAE7B,IAAI,OAAO,UAAU,UACpB,UAAU;CAaZ,UAAU,OAAO;CAGjB,WAAW,IAAI;EACd,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EAClC,MAAM;EACN;CACD,CAAC;CAGD,WAAW,OAAO;AACnB"}
|